summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/Skeleton2D.xml2
-rw-r--r--editor/editor_inspector.cpp4
-rw-r--r--editor/output_strings.cpp208
-rw-r--r--editor/output_strings.h87
-rw-r--r--editor/plugins/script_editor_plugin.cpp37
-rw-r--r--editor/plugins/script_editor_plugin.h1
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/BuildManager.cs13
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs22
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs3
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs6
-rw-r--r--modules/mono/editor/csharp_project.cpp2
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp51
-rw-r--r--modules/mono/editor/godotsharp_export.cpp14
-rw-r--r--modules/mono/editor/godotsharp_export.h3
-rw-r--r--modules/mono/godotsharp_dirs.cpp18
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp288
-rw-r--r--modules/mono/mono_gd/gd_mono.h66
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp2
19 files changed, 332 insertions, 498 deletions
diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml
index 064a7266bd..886e8244a2 100644
--- a/doc/classes/Skeleton2D.xml
+++ b/doc/classes/Skeleton2D.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Skeleton2D" inherits="Node2D" category="Core" version="3.2">
<brief_description>
+ Skeleton for 2D characters and animated objects.
</brief_description>
<description>
</description>
@@ -20,6 +21,7 @@
<return type="int">
</return>
<description>
+ Returns the amount of bones in the skeleton.
</description>
</method>
<method name="get_skeleton" qualifiers="const">
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index b29417b4c3..78e058eeaa 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1566,11 +1566,11 @@ void EditorInspector::update_tree() {
if (dot != -1) {
String ov = name.right(dot);
name = name.substr(0, dot);
- name = name.camelcase_to_underscore().capitalize();
+ name = name.capitalize();
name += ov;
} else {
- name = name.camelcase_to_underscore().capitalize();
+ name = name.capitalize();
}
}
diff --git a/editor/output_strings.cpp b/editor/output_strings.cpp
deleted file mode 100644
index baabaff9a8..0000000000
--- a/editor/output_strings.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*************************************************************************/
-/* output_strings.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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 "output_strings.h"
-
-void OutputStrings::update_scrollbars() {
-
- Size2 hmin = h_scroll->get_combined_minimum_size();
- Size2 vmin = v_scroll->get_combined_minimum_size();
-
- v_scroll->set_anchor(MARGIN_LEFT, ANCHOR_END);
- v_scroll->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- v_scroll->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
-
- v_scroll->set_begin(Point2(-vmin.width, 0));
- v_scroll->set_end(Point2(0, 0));
-
- h_scroll->set_anchor(MARGIN_RIGHT, ANCHOR_END);
- h_scroll->set_anchor(MARGIN_TOP, ANCHOR_END);
- h_scroll->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
-
- h_scroll->set_begin(Point2(0, -hmin.y));
- h_scroll->set_end(Point2(-vmin.x, 0));
-
- margin.y = hmin.y;
- margin.x = vmin.x;
-
- Ref<StyleBox> tree_st = get_stylebox("bg", "Tree");
- int page = ((size_height - (int)margin.y - tree_st->get_margin(MARGIN_TOP)) / font_height);
- v_scroll->set_page(page);
-}
-
-void OutputStrings::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_DRAW: {
-
- if (following) {
-
- updating = true;
- v_scroll->set_value(v_scroll->get_max() - v_scroll->get_page());
- updating = false;
- }
-
- RID ci = get_canvas_item();
- Size2 size = get_size();
-
- Ref<Font> font = get_font("font", "Tree");
- Ref<StyleBox> tree_st = get_stylebox("bg", "Tree");
- tree_st->draw(ci, Rect2(Point2(), size));
- Color color = get_color("font_color", "Tree");
- Ref<Texture> icon_error = get_icon("Error", "EditorIcons");
- Ref<Texture> icon_warning = get_icon("Warning", "EditorIcons");
-
- //int lines = (size_height-(int)margin.y) / font_height;
- Point2 ofs = tree_st->get_offset();
-
- LineMap::Element *E = line_map.find(v_scroll->get_value());
- float h_ofs = (int)h_scroll->get_value();
- Point2 icon_ofs = Point2(0, (font_height - (int)icon_error->get_height()) / 2);
-
- FontDrawer drawer(font, Color(1, 1, 1));
- while (E && ofs.y < (size_height - (int)margin.y)) {
-
- String str = E->get().text;
- Point2 line_ofs = ofs;
-
- switch (E->get().type) {
-
- case LINE_WARNING: {
- icon_warning->draw(ci, line_ofs + icon_ofs);
-
- } break;
- case LINE_ERROR: {
- icon_error->draw(ci, line_ofs + icon_ofs);
- } break;
- case LINE_LINK: {
-
- } break;
- default: {
- }
- }
-
- line_ofs.y += font->get_ascent();
- line_ofs.x += icon_error->get_width() + 4;
-
- for (int i = 0; i < str.length(); i++) {
- if (line_ofs.x - h_ofs < 0) {
- line_ofs.x += font->get_char_size(str[i], str[i + 1]).width;
- } else if (line_ofs.x - h_ofs > size.width - margin.width) {
- break;
- } else {
- line_ofs.x += font->draw_char(ci, Point2(line_ofs.x - h_ofs, line_ofs.y), str[i], str[i + 1], color);
- }
- }
-
- ofs.y += font_height;
- E = E->next();
- }
-
- } break;
-
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_RESIZED: {
-
- font_height = get_font("font", "Tree")->get_height();
- size_height = get_size().height;
- update_scrollbars();
- } break;
- }
-}
-
-void OutputStrings::_hscroll_changed(float p_value) {
-
- if (updating)
- return;
-
- update();
-}
-void OutputStrings::_vscroll_changed(float p_value) {
-
- if (updating)
- return;
- //user changed scroll
- following = (p_value + v_scroll->get_page()) >= v_scroll->get_max();
- update();
-}
-
-void OutputStrings::add_line(const String &p_text, const Variant &p_meta, const LineType p_type) {
-
- Vector<String> strings = p_text.split("\n");
-
- for (int i = 0; i < strings.size(); i++) {
-
- if (strings[i].length() == 0)
- continue;
-
- int last = line_map.empty() ? 0 : (line_map.back()->key() + 1);
-
- Line l;
- l.text = strings[i];
- l.meta = p_meta;
- l.type = p_type;
- line_map.insert(last, l);
-
- updating = true;
- v_scroll->set_max(last + 1);
- v_scroll->set_min(line_map.front()->key());
- updating = false;
- }
-
- while (line_map.size() > line_max_count) {
-
- line_map.erase(line_map.front());
- }
-
- update();
-}
-
-void OutputStrings::_bind_methods() {
-
- ClassDB::bind_method("_vscroll_changed", &OutputStrings::_vscroll_changed);
- ClassDB::bind_method("_hscroll_changed", &OutputStrings::_hscroll_changed);
-}
-
-OutputStrings::OutputStrings() {
-
- following = true;
- updating = false;
- line_max_count = 4096;
- h_scroll = memnew(HScrollBar);
- v_scroll = memnew(VScrollBar);
- add_child(h_scroll);
- add_child(v_scroll);
- size_height = 1;
- font_height = 1;
- update_scrollbars();
- h_scroll->connect("value_changed", this, "_hscroll_changed");
- v_scroll->connect("value_changed", this, "_vscroll_changed");
-}
diff --git a/editor/output_strings.h b/editor/output_strings.h
deleted file mode 100644
index 4fd3f7d836..0000000000
--- a/editor/output_strings.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*************************************************************************/
-/* output_strings.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2019 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 OUTPUT_STRINGS_H
-#define OUTPUT_STRINGS_H
-
-#include "core/map.h"
-#include "scene/gui/control.h"
-#include "scene/gui/scroll_bar.h"
-
-class OutputStrings : public Control {
-
- GDCLASS(OutputStrings, Control);
-
-public:
- enum LineType {
-
- LINE_NORMAL,
- LINE_WARNING,
- LINE_ERROR,
- LINE_LINK
- };
-
-private:
- struct Line {
-
- LineType type;
- Variant meta;
- String text;
- };
-
- int font_height;
- int size_height;
-
- Size2 margin;
- typedef Map<int, Line> LineMap;
- Map<int, Line> line_map;
-
- VScrollBar *v_scroll;
- HScrollBar *h_scroll;
-
- bool following;
- int line_max_count;
- bool updating;
-
- void _vscroll_changed(float p_value);
- void _hscroll_changed(float p_value);
- void update_scrollbars();
-
-protected:
- static void _bind_methods();
- void _notification(int p_what);
-
-public:
- void add_line(const String &p_text, const Variant &p_meta = Variant(), const LineType p_type = LINE_NORMAL);
-
- OutputStrings();
-};
-
-#endif // OUTPUT_STRINGS_H
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 132a491fb3..f7e997a269 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -43,6 +43,7 @@
#include "editor/plugins/shader_editor_plugin.h"
#include "editor/script_editor_debugger.h"
#include "scene/main/viewport.h"
+#include "scene/scene_string_names.h"
#include "script_text_editor.h"
#include "text_editor.h"
@@ -1420,16 +1421,6 @@ void ScriptEditor::_notification(int p_what) {
members_overview->connect("item_selected", this, "_members_overview_selected");
help_overview->connect("item_selected", this, "_help_overview_selected");
script_split->connect("dragged", this, "_script_split_dragged");
- autosave_timer->connect("timeout", this, "_autosave_scripts");
- {
- float autosave_time = EditorSettings::get_singleton()->get("text_editor/files/autosave_interval_secs");
- if (autosave_time > 0) {
- autosave_timer->set_wait_time(autosave_time);
- autosave_timer->start();
- } else {
- autosave_timer->stop();
- }
- }
EditorSettings::get_singleton()->connect("settings_changed", this, "_editor_settings_changed");
FALLTHROUGH;
@@ -2335,13 +2326,7 @@ void ScriptEditor::_editor_settings_changed() {
_update_members_overview_visibility();
_update_help_overview_visibility();
- float autosave_time = EditorSettings::get_singleton()->get("text_editor/files/autosave_interval_secs");
- if (autosave_time > 0) {
- autosave_timer->set_wait_time(autosave_time);
- autosave_timer->start();
- } else {
- autosave_timer->stop();
- }
+ _update_autosave_timer();
if (current_theme == "") {
current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
@@ -2369,6 +2354,21 @@ void ScriptEditor::_autosave_scripts() {
save_all_scripts();
}
+void ScriptEditor::_update_autosave_timer() {
+
+ if (!autosave_timer->is_inside_tree()) {
+ return;
+ }
+
+ float autosave_time = EditorSettings::get_singleton()->get("text_editor/files/autosave_interval_secs");
+ if (autosave_time > 0) {
+ autosave_timer->set_wait_time(autosave_time);
+ autosave_timer->start();
+ } else {
+ autosave_timer->stop();
+ }
+}
+
void ScriptEditor::_tree_changed() {
if (waiting_update_names)
@@ -3092,6 +3092,7 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_show_debugger", &ScriptEditor::_show_debugger);
ClassDB::bind_method("_get_debug_tooltip", &ScriptEditor::_get_debug_tooltip);
ClassDB::bind_method("_autosave_scripts", &ScriptEditor::_autosave_scripts);
+ ClassDB::bind_method("_update_autosave_timer", &ScriptEditor::_update_autosave_timer);
ClassDB::bind_method("_editor_settings_changed", &ScriptEditor::_editor_settings_changed);
ClassDB::bind_method("_update_script_names", &ScriptEditor::_update_script_names);
ClassDB::bind_method("_update_script_connections", &ScriptEditor::_update_script_connections);
@@ -3428,6 +3429,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
autosave_timer = memnew(Timer);
autosave_timer->set_one_shot(false);
+ autosave_timer->connect(SceneStringNames::get_singleton()->tree_entered, this, "_update_autosave_timer");
+ autosave_timer->connect("timeout", this, "_autosave_scripts");
add_child(autosave_timer);
grab_focus_block = false;
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 8ff7a2222d..294294fc56 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -343,6 +343,7 @@ class ScriptEditor : public PanelContainer {
void _save_layout();
void _editor_settings_changed();
void _autosave_scripts();
+ void _update_autosave_timer();
void _update_members_overview_visibility();
void _update_members_overview();
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 62c212a2bd..8d58b99e02 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -56,8 +56,9 @@ void GDScriptLanguageServer::_notification(int p_what) {
void GDScriptLanguageServer::thread_main(void *p_userdata) {
GDScriptLanguageServer *self = static_cast<GDScriptLanguageServer *>(p_userdata);
while (!self->thread_exit) {
+ // Poll 20 times per second
self->protocol.poll();
- OS::get_singleton()->delay_usec(10);
+ OS::get_singleton()->delay_usec(50000);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs
index 417032da54..ab37d89955 100644
--- a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs
@@ -160,9 +160,16 @@ namespace GodotTools
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return true; // No solution to build
- // Make sure to update the API assemblies if they happen to be missing. Just in
- // case the user decided to delete them at some point after they were loaded.
- Internal.UpdateApiAssembliesFromPrebuilt();
+ // Make sure the API assemblies are up to date before building the project.
+ // We may not have had the chance to update the release API assemblies, and the debug ones
+ // may have been deleted by the user at some point after they were loaded by the Godot editor.
+ string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "Release" ? "Release" : "Debug");
+
+ if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
+ {
+ ShowBuildErrorDialog("Failed to update the Godot API assemblies");
+ return false;
+ }
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
var buildTool = (BuildTool) editorSettings.GetSetting("mono/builds/build_tool");
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 7da7cff933..12edd651df 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -34,7 +34,7 @@ namespace GodotTools
private bool CreateProjectSolution()
{
- using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 2))
+ using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 3))
{
pr.Step("Generating C# project...".TTR());
@@ -73,9 +73,23 @@ namespace GodotTools
return false;
}
- // Make sure to update the API assemblies if they happen to be missing. Just in
- // case the user decided to delete them at some point after they were loaded.
- Internal.UpdateApiAssembliesFromPrebuilt();
+ pr.Step("Updating Godot API assemblies...".TTR());
+
+ string debugApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Debug");
+
+ if (!string.IsNullOrEmpty(debugApiAssembliesError))
+ {
+ ShowErrorDialog("Failed to update the Godot API assemblies: " + debugApiAssembliesError);
+ return false;
+ }
+
+ string releaseApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Release");
+
+ if (!string.IsNullOrEmpty(releaseApiAssembliesError))
+ {
+ ShowErrorDialog("Failed to update the Godot API assemblies: " + releaseApiAssembliesError);
+ return false;
+ }
pr.Step("Done".TTR());
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
index 9e24138143..01aa0d0ab1 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
@@ -40,8 +40,7 @@ namespace GodotTools.Ides
protected ILogger Logger
{
- get => logger ?? (logger = new ConsoleLogger());
- set => logger = value;
+ get => logger ?? (logger = new GodotLogger());
}
private void StartServer()
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index 7783576910..836c9c11e4 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -10,8 +10,8 @@ namespace GodotTools.Internals
public const string CSharpLanguageType = "CSharpScript";
public const string CSharpLanguageExtension = "cs";
- public static string UpdateApiAssembliesFromPrebuilt() =>
- internal_UpdateApiAssembliesFromPrebuilt();
+ public static string UpdateApiAssembliesFromPrebuilt(string config) =>
+ internal_UpdateApiAssembliesFromPrebuilt(config);
public static string FullTemplatesDir =>
internal_FullTemplatesDir();
@@ -55,7 +55,7 @@ namespace GodotTools.Internals
// Internal Calls
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_UpdateApiAssembliesFromPrebuilt();
+ private static extern string internal_UpdateApiAssembliesFromPrebuilt(string config);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string internal_FullTemplatesDir();
diff --git a/modules/mono/editor/csharp_project.cpp b/modules/mono/editor/csharp_project.cpp
index 0e6c58c9d7..748447005f 100644
--- a/modules/mono/editor/csharp_project.cpp
+++ b/modules/mono/editor/csharp_project.cpp
@@ -75,7 +75,7 @@ bool generate_api_solution(const String &p_solution_dir, const String &p_core_pr
p_editor_proj_dir, p_editor_compile_items,
GDMono::get_singleton()->get_tools_project_editor_assembly());
} else {
- MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.ApiSolutionGenerationDomain");
+ MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ApiSolutionGeneration");
CRASH_COND(temp_domain == NULL);
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 5a84d9e3b8..1564d73c2a 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -230,31 +230,9 @@ uint32_t godot_icall_GodotSharpExport_GetExportedAssemblyDependencies(MonoString
return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_lib_dir, dependencies);
}
-float godot_icall_Globals_EditorScale() {
- return EDSCALE;
-}
-
-MonoObject *godot_icall_Globals_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
- Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
- Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed);
- return GDMonoMarshal::variant_to_mono_object(result);
-}
-
-MonoObject *godot_icall_Globals_EditorDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
- Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
- Variant result = _EDITOR_DEF(setting, default_value, (bool)p_restart_if_changed);
- return GDMonoMarshal::variant_to_mono_object(result);
-}
-
-MonoString *godot_icall_Globals_TTR(MonoString *p_text) {
- String text = GDMonoMarshal::mono_string_to_godot(p_text);
- return GDMonoMarshal::mono_string_from_godot(TTR(text));
-}
-
-MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt() {
- String error_str = GDMono::get_singleton()->update_api_assemblies_from_prebuilt();
+MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) {
+ String config = GDMonoMarshal::mono_string_to_godot(p_config);
+ String error_str = GDMono::get_singleton()->update_api_assemblies_from_prebuilt(config);
return GDMonoMarshal::mono_string_from_godot(error_str);
}
@@ -365,6 +343,29 @@ void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts() {
}
}
+float godot_icall_Globals_EditorScale() {
+ return EDSCALE;
+}
+
+MonoObject *godot_icall_Globals_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
+ String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
+ Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+ Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed);
+ return GDMonoMarshal::variant_to_mono_object(result);
+}
+
+MonoObject *godot_icall_Globals_EditorDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
+ String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
+ Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+ Variant result = _EDITOR_DEF(setting, default_value, (bool)p_restart_if_changed);
+ return GDMonoMarshal::variant_to_mono_object(result);
+}
+
+MonoString *godot_icall_Globals_TTR(MonoString *p_text) {
+ String text = GDMonoMarshal::mono_string_to_godot(p_text);
+ return GDMonoMarshal::mono_string_from_godot(TTR(text));
+}
+
MonoString *godot_icall_Utils_OS_GetPlatformName() {
String os_name = OS::get_singleton()->get_name();
return GDMonoMarshal::mono_string_from_godot(os_name);
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index 80a7335b1d..e83152d668 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -32,9 +32,13 @@
#include <mono/metadata/image.h>
+#include "core/os/os.h"
+
#include "../mono_gd/gd_mono.h"
#include "../mono_gd/gd_mono_assembly.h"
+namespace GodotSharpExport {
+
String get_assemblyref_name(MonoImage *p_image, int index) {
const MonoTableInfo *table_info = mono_image_get_table_info(p_image, MONO_TABLE_ASSEMBLYREF);
@@ -45,7 +49,7 @@ String get_assemblyref_name(MonoImage *p_image, int index) {
return String::utf8(mono_metadata_string_heap(p_image, cols[MONO_ASSEMBLYREF_NAME]));
}
-Error GodotSharpExport::get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies) {
+Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies) {
MonoImage *image = p_assembly->get_image();
for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
@@ -96,8 +100,8 @@ Error GodotSharpExport::get_assembly_dependencies(GDMonoAssembly *p_assembly, co
return OK;
}
-Error GodotSharpExport::get_exported_assembly_dependencies(const String &p_project_dll_name, const String &p_project_dll_src_path, const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_dependencies) {
- MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.ProjectExportDomain");
+Error get_exported_assembly_dependencies(const String &p_project_dll_name, const String &p_project_dll_src_path, const String &p_build_config, const String &p_custom_bcl_dir, Dictionary &r_dependencies) {
+ MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ProjectExport");
ERR_FAIL_NULL_V(export_domain, FAILED);
_GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
@@ -110,7 +114,9 @@ Error GodotSharpExport::get_exported_assembly_dependencies(const String &p_proje
ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + p_project_dll_name + "'.");
Vector<String> search_dirs;
- GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_lib_dir);
+ GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_bcl_dir);
return get_assembly_dependencies(scripts_assembly, search_dirs, r_dependencies);
}
+
+} // namespace GodotSharpExport
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
index 8d121a6bc3..58e46e2f2d 100644
--- a/modules/mono/editor/godotsharp_export.h
+++ b/modules/mono/editor/godotsharp_export.h
@@ -39,10 +39,11 @@
namespace GodotSharpExport {
+Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies);
+
Error get_exported_assembly_dependencies(const String &p_project_dll_name,
const String &p_project_dll_src_path, const String &p_build_config,
const String &p_custom_lib_dir, Dictionary &r_dependencies);
-Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies);
} // namespace GodotSharpExport
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 4b2525c692..5fa8aed5a9 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -43,6 +43,8 @@
#include "utils/android_utils.h"
#endif
+#include "mono_gd/gd_mono.h"
+
namespace GodotSharpDirs {
String _get_expected_build_config() {
@@ -59,20 +61,6 @@ String _get_expected_build_config() {
#endif
}
-String _get_expected_api_build_config() {
-#ifdef TOOLS_ENABLED
- return "Debug";
-#else
-
-#ifdef DEBUG_ENABLED
- return "Debug";
-#else
- return "Release";
-#endif
-
-#endif
-}
-
String _get_mono_user_dir() {
#ifdef TOOLS_ENABLED
if (EditorSettings::get_singleton()) {
@@ -134,7 +122,7 @@ private:
res_data_dir = "res://.mono";
res_metadata_dir = res_data_dir.plus_file("metadata");
res_assemblies_base_dir = res_data_dir.plus_file("assemblies");
- res_assemblies_dir = res_assemblies_base_dir.plus_file(_get_expected_api_build_config());
+ res_assemblies_dir = res_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
// TODO use paths from csproj
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 544bfc4615..0a34404154 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -381,10 +381,10 @@ void GDMono::initialize_load_assemblies() {
}
bool GDMono::_are_api_assemblies_out_of_sync() {
- bool out_of_sync = core_api_assembly && (core_api_assembly_out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated);
+ bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated);
#ifdef TOOLS_ENABLED
if (!out_of_sync)
- out_of_sync = editor_api_assembly && editor_api_assembly_out_of_sync;
+ out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync;
#endif
return out_of_sync;
}
@@ -523,10 +523,10 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMo
return true;
}
-APIAssembly::Version APIAssembly::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, APIAssembly::Type p_api_type) {
- APIAssembly::Version api_assembly_version;
+ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, ApiAssemblyInfo::Type p_api_type) {
+ ApiAssemblyInfo::Version api_assembly_version;
- const char *nativecalls_name = p_api_type == APIAssembly::API_CORE ?
+ const char *nativecalls_name = p_api_type == ApiAssemblyInfo::API_CORE ?
BINDINGS_CLASS_NATIVECALLS :
BINDINGS_CLASS_NATIVECALLS_EDITOR;
@@ -549,8 +549,8 @@ APIAssembly::Version APIAssembly::Version::get_from_loaded_assembly(GDMonoAssemb
return api_assembly_version;
}
-String APIAssembly::to_string(APIAssembly::Type p_type) {
- return p_type == APIAssembly::API_CORE ? "API_CORE" : "API_EDITOR";
+String ApiAssemblyInfo::to_string(ApiAssemblyInfo::Type p_type) {
+ return p_type == ApiAssemblyInfo::API_CORE ? "API_CORE" : "API_EDITOR";
}
bool GDMono::_load_corlib_assembly() {
@@ -567,16 +567,12 @@ bool GDMono::_load_corlib_assembly() {
}
#ifdef TOOLS_ENABLED
-bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type, const String &p_config) {
-
- bool &api_assembly_out_of_sync = (p_api_type == APIAssembly::API_CORE) ?
- GDMono::get_singleton()->core_api_assembly_out_of_sync :
- GDMono::get_singleton()->editor_api_assembly_out_of_sync;
+bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config) {
String src_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
String dst_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
- String assembly_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
+ String assembly_name = p_api_type == ApiAssemblyInfo::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
// Create destination directory if needed
if (!DirAccess::exists(dst_dir)) {
@@ -590,35 +586,102 @@ bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type, const Stri
}
}
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+ String xml_file = assembly_name + ".xml";
+ if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK)
+ WARN_PRINTS("Failed to copy '" + xml_file + "'.");
+
+ String pdb_file = assembly_name + ".pdb";
+ if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK)
+ WARN_PRINTS("Failed to copy '" + pdb_file + "'.");
+
String assembly_file = assembly_name + ".dll";
- String assembly_src = src_dir.plus_file(assembly_file);
- String assembly_dst = dst_dir.plus_file(assembly_file);
+ if (da->copy(src_dir.plus_file(assembly_file), dst_dir.plus_file(assembly_file)) != OK) {
+ ERR_PRINTS("Failed to copy '" + assembly_file + "'.");
+ return false;
+ }
- if (!FileAccess::exists(assembly_dst) || api_assembly_out_of_sync) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ return true;
+}
- String xml_file = assembly_name + ".xml";
- if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK)
- WARN_PRINTS("Failed to copy '" + xml_file + "'.");
+static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool &r_out_of_sync) {
+ String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
+ String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
- String pdb_file = assembly_name + ".pdb";
- if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK)
- WARN_PRINTS("Failed to copy '" + pdb_file + "'.");
+ if (!FileAccess::exists(core_api_assembly_path) || !FileAccess::exists(editor_api_assembly_path))
+ return false;
- Error err = da->copy(assembly_src, assembly_dst);
+ String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
- if (err != OK) {
- ERR_PRINTS("Failed to copy '" + assembly_file + "'.");
- return false;
- }
+ if (!FileAccess::exists(cached_api_hash_path))
+ return false;
+
+ Ref<ConfigFile> cfg;
+ cfg.instance();
+ Error cfg_err = cfg->load(cached_api_hash_path);
+ ERR_FAIL_COND_V(cfg_err != OK, false);
- api_assembly_out_of_sync = false;
+ // Checking the modified time is good enough
+ if (FileAccess::get_modified_time(core_api_assembly_path) != (uint64_t)cfg->get_value("core", "modified_time") ||
+ FileAccess::get_modified_time(editor_api_assembly_path) != (uint64_t)cfg->get_value("editor", "modified_time")) {
+ return false;
}
+ r_out_of_sync = GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("core", "bindings_version") ||
+ GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("core", "cs_glue_version") ||
+ GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("editor", "bindings_version") ||
+ GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("editor", "cs_glue_version") ||
+ GodotSharpBindings::get_core_api_hash() != (uint64_t)cfg->get_value("core", "api_hash") ||
+ GodotSharpBindings::get_editor_api_hash() != (uint64_t)cfg->get_value("editor", "api_hash");
+
return true;
}
-String GDMono::update_api_assemblies_from_prebuilt() {
+static void create_cached_api_hash_for(const String &p_api_assemblies_dir) {
+
+ String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
+ String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
+ String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
+
+ Ref<ConfigFile> cfg;
+ cfg.instance();
+
+ cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path));
+ cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path));
+
+ cfg->set_value("core", "bindings_version", GodotSharpBindings::get_bindings_version());
+ cfg->set_value("core", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
+ cfg->set_value("editor", "bindings_version", GodotSharpBindings::get_bindings_version());
+ cfg->set_value("editor", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
+
+ // This assumes the prebuilt api assemblies we copied to the project are not out of sync
+ cfg->set_value("core", "api_hash", GodotSharpBindings::get_core_api_hash());
+ cfg->set_value("editor", "api_hash", GodotSharpBindings::get_editor_api_hash());
+
+ Error err = cfg->save(cached_api_hash_path);
+ ERR_FAIL_COND(err != OK);
+}
+
+bool GDMono::_temp_domain_load_are_assemblies_out_of_sync(const String &p_config) {
+ MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.Domain.CheckApiAssemblies");
+ ERR_FAIL_NULL_V(temp_domain, "Failed to create temporary domain to check API assemblies");
+ _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
+
+ _GDMONO_SCOPE_DOMAIN_(temp_domain);
+
+ GDMono::LoadedApiAssembly temp_core_api_assembly;
+ GDMono::LoadedApiAssembly temp_editor_api_assembly;
+
+ if (!_try_load_api_assemblies(temp_core_api_assembly, temp_editor_api_assembly,
+ p_config, /* refonly: */ true, /* loaded_callback: */ NULL)) {
+ return temp_core_api_assembly.out_of_sync || temp_editor_api_assembly.out_of_sync;
+ }
+
+ return true; // Failed to load, assume they're outdated assemblies
+}
+
+String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync, const bool *p_editor_api_out_of_sync) {
#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \
( \
@@ -629,46 +692,55 @@ String GDMono::update_api_assemblies_from_prebuilt() {
String("and the prebuilt assemblies are missing.") : \
String("and we failed to copy the prebuilt assemblies.")))
- bool api_assembly_out_of_sync = core_api_assembly_out_of_sync || editor_api_assembly_out_of_sync;
+ String dst_assemblies_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
- String core_assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String editor_assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
+ String core_assembly_path = dst_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
+ String editor_assembly_path = dst_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
- if (!api_assembly_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path))
- return String(); // No update needed
+ bool api_assemblies_out_of_sync = false;
- const int CONFIGS_LEN = 2;
- String configs[CONFIGS_LEN] = { String("Debug"), String("Release") };
+ if (p_core_api_out_of_sync && p_editor_api_out_of_sync) {
+ api_assemblies_out_of_sync = p_core_api_out_of_sync || p_editor_api_out_of_sync;
+ } else if (FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
+ // Determine if they're out of sync
+ if (!try_get_cached_api_hash_for(dst_assemblies_dir, api_assemblies_out_of_sync)) {
+ api_assemblies_out_of_sync = _temp_domain_load_are_assemblies_out_of_sync(p_config);
+ }
+ }
- for (int i = 0; i < CONFIGS_LEN; i++) {
- String config = configs[i];
+ // Note: Even if only one of the assemblies if missing or out of sync, we update both
- print_verbose("Updating '" + config + "' API assemblies");
+ if (!api_assemblies_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path))
+ return String(); // No update needed
- String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(config);
- 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");
+ print_verbose("Updating '" + p_config + "' API assemblies");
- if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) {
- return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exists: */ false);
- }
+ String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
+ 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");
- // Copy the prebuilt Api
- if (!copy_prebuilt_api_assembly(APIAssembly::API_CORE, config) ||
- !copy_prebuilt_api_assembly(APIAssembly::API_EDITOR, config)) {
- return FAIL_REASON(api_assembly_out_of_sync, /* prebuilt_exists: */ true);
- }
+ if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) {
+ return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ false);
}
+ // Copy the prebuilt Api
+ if (!copy_prebuilt_api_assembly(ApiAssemblyInfo::API_CORE, p_config) ||
+ !copy_prebuilt_api_assembly(ApiAssemblyInfo::API_EDITOR, p_config)) {
+ return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ true);
+ }
+
+ // Cache the api hash of the assemblies we just copied
+ create_cached_api_hash_for(dst_assemblies_dir);
+
return String(); // Updated successfully
#undef FAIL_REASON
}
#endif
-bool GDMono::_load_core_api_assembly() {
+bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (core_api_assembly)
+ if (r_loaded_api_assembly.assembly)
return true;
#ifdef TOOLS_ENABLED
@@ -676,101 +748,115 @@ bool GDMono::_load_core_api_assembly() {
// 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");
+ GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
+ GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
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);
+ load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
#else
- bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly);
+ bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &core_api_assembly, p_refonly);
#endif
if (success) {
- APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(core_api_assembly, APIAssembly::API_CORE);
- 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 ||
- GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
- if (!core_api_assembly_out_of_sync) {
- GDMonoUtils::update_godot_api_cache();
-
- _install_trace_listener();
- }
+ ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_CORE);
+ r_loaded_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 ||
+ GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
} else {
- core_api_assembly_out_of_sync = false;
+ r_loaded_api_assembly.out_of_sync = false;
}
return success;
}
#ifdef TOOLS_ENABLED
-bool GDMono::_load_editor_api_assembly() {
+bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (editor_api_assembly)
+ if (r_loaded_api_assembly.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
// 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");
+ GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config) :
+ GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
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);
+ load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
if (success) {
- APIAssembly::Version api_assembly_ver = APIAssembly::Version::get_from_loaded_assembly(editor_api_assembly, APIAssembly::API_EDITOR);
- editor_api_assembly_out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
- GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
- GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
+ ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_EDITOR);
+ r_loaded_api_assembly.out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
+ GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
+ GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
} else {
- editor_api_assembly_out_of_sync = false;
+ r_loaded_api_assembly.out_of_sync = false;
}
return success;
}
#endif
-bool GDMono::_try_load_api_assemblies() {
-
- if (!_load_core_api_assembly()) {
+bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
+ const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback) {
+ if (!_load_core_api_assembly(r_core_api_assembly, p_config, p_refonly)) {
if (OS::get_singleton()->is_stdout_verbose())
print_error("Mono: Failed to load Core API assembly");
return false;
}
#ifdef TOOLS_ENABLED
- if (!_load_editor_api_assembly()) {
+ if (!_load_editor_api_assembly(r_editor_api_assembly, p_config, p_refonly)) {
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)
+ if (r_editor_api_assembly.out_of_sync)
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)
+ if (r_core_api_assembly.out_of_sync)
return false;
+ if (p_callback)
+ return p_callback();
+
return true;
}
+bool GDMono::_on_core_api_assembly_loaded() {
+ GDMonoUtils::update_godot_api_cache();
+
+ if (!GDMonoUtils::mono_cache.godot_api_cache_updated)
+ return false;
+
+ get_singleton()->_install_trace_listener();
+
+ return true;
+}
+
+bool GDMono::_try_load_api_assemblies_preset() {
+ return _try_load_api_assemblies(core_api_assembly, editor_api_assembly,
+ get_expected_api_build_config(), /* refonly: */ false, _on_core_api_assembly_loaded);
+}
+
void GDMono::_load_api_assemblies() {
- bool api_assemblies_loaded = _try_load_api_assemblies();
+ bool api_assemblies_loaded = _try_load_api_assemblies_preset();
if (!api_assemblies_loaded) {
#ifdef TOOLS_ENABLED
- // 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.
+ // The API assemblies are out of sync or some other error happened. Fine, try one more time, but
+ // this time update them from the prebuilt assemblies directory before trying to load them again.
// Shouldn't happen. The project manager loads the prebuilt API assemblies
CRASH_COND_MSG(Main::is_project_manager(), "Failed to load one of the prebuilt API assemblies.");
@@ -780,7 +866,7 @@ void GDMono::_load_api_assemblies() {
CRASH_COND_MSG(domain_unload_err != OK, "Mono: Failed to unload scripts domain.");
// 2. Update the API assemblies
- String update_error = update_api_assemblies_from_prebuilt();
+ String update_error = update_api_assemblies_from_prebuilt("Debug", &core_api_assembly.out_of_sync, &editor_api_assembly.out_of_sync);
CRASH_COND_MSG(!update_error.empty(), update_error);
// 3. Load the scripts domain again
@@ -788,7 +874,7 @@ void GDMono::_load_api_assemblies() {
CRASH_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
// 4. Try loading the updated assemblies
- api_assemblies_loaded = _try_load_api_assemblies();
+ api_assemblies_loaded = _try_load_api_assemblies_preset();
#endif
}
@@ -796,14 +882,14 @@ void GDMono::_load_api_assemblies() {
// welp... too bad
if (_are_api_assemblies_out_of_sync()) {
- if (core_api_assembly_out_of_sync) {
+ if (core_api_assembly.out_of_sync) {
ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed.");
}
#ifdef TOOLS_ENABLED
- if (editor_api_assembly_out_of_sync) {
+ if (editor_api_assembly.out_of_sync) {
ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync.");
}
#endif
@@ -852,15 +938,14 @@ void GDMono::_install_trace_listener() {
#ifdef DEBUG_ENABLED
// Install the trace listener now before the project assembly is loaded
- typedef void (*DebuggingUtils_InstallTraceListener)(MonoObject **);
+ GDMonoClass *debug_utils = get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
+ GDMonoMethod *install_func = debug_utils->get_method("InstallTraceListener");
+
MonoException *exc = NULL;
- GDMonoClass *debug_utils = core_api_assembly->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
- DebuggingUtils_InstallTraceListener install_func =
- (DebuggingUtils_InstallTraceListener)debug_utils->get_method_thunk("InstallTraceListener");
- install_func((MonoObject **)&exc);
+ install_func->invoke_raw(NULL, NULL, &exc);
if (exc) {
- ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
GDMonoUtils::debug_print_unhandled_exception(exc);
+ ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
}
#endif
}
@@ -871,7 +956,7 @@ Error GDMono::_load_scripts_domain() {
print_verbose("Mono: Loading scripts domain...");
- scripts_domain = GDMonoUtils::create_domain("GodotEngine.ScriptsDomain");
+ scripts_domain = GDMonoUtils::create_domain("GodotEngine.Domain.Scripts");
ERR_FAIL_NULL_V_MSG(scripts_domain, ERR_CANT_CREATE, "Mono: Could not create scripts app domain.");
@@ -903,10 +988,8 @@ Error GDMono::_unload_scripts_domain() {
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
- core_api_assembly = NULL;
project_assembly = NULL;
#ifdef TOOLS_ENABLED
- editor_api_assembly = NULL;
tools_assembly = NULL;
tools_project_editor_assembly = NULL;
#endif
@@ -1076,16 +1159,9 @@ GDMono::GDMono() {
root_domain = NULL;
scripts_domain = NULL;
- core_api_assembly_out_of_sync = false;
-#ifdef TOOLS_ENABLED
- editor_api_assembly_out_of_sync = false;
-#endif
-
corlib_assembly = NULL;
- core_api_assembly = NULL;
project_assembly = NULL;
#ifdef TOOLS_ENABLED
- editor_api_assembly = NULL;
tools_assembly = NULL;
tools_project_editor_assembly = NULL;
#endif
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 343d68bc2d..e14a0d8409 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -41,7 +41,7 @@
#include "../utils/mono_reg_utils.h"
#endif
-namespace APIAssembly {
+namespace ApiAssemblyInfo {
enum Type {
API_CORE,
API_EDITOR
@@ -76,7 +76,7 @@ struct Version {
};
String to_string(Type p_type);
-} // namespace APIAssembly
+} // namespace ApiAssemblyInfo
class GDMono {
@@ -86,44 +86,58 @@ public:
POLICY_LOG_ERROR
};
+ struct LoadedApiAssembly {
+ GDMonoAssembly *assembly;
+ bool out_of_sync;
+
+ LoadedApiAssembly() :
+ assembly(NULL),
+ out_of_sync(false) {
+ }
+ };
+
private:
bool runtime_initialized;
bool finalizing_scripts_domain;
+ UnhandledExceptionPolicy unhandled_exception_policy;
+
MonoDomain *root_domain;
MonoDomain *scripts_domain;
- bool core_api_assembly_out_of_sync;
-#ifdef TOOLS_ENABLED
- bool editor_api_assembly_out_of_sync;
-#endif
+ HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
GDMonoAssembly *corlib_assembly;
- GDMonoAssembly *core_api_assembly;
GDMonoAssembly *project_assembly;
#ifdef TOOLS_ENABLED
- GDMonoAssembly *editor_api_assembly;
GDMonoAssembly *tools_assembly;
GDMonoAssembly *tools_project_editor_assembly;
#endif
- HashMap<uint32_t, HashMap<String, GDMonoAssembly *> > assemblies;
-
- UnhandledExceptionPolicy unhandled_exception_policy;
+ LoadedApiAssembly core_api_assembly;
+ LoadedApiAssembly editor_api_assembly;
- void _domain_assemblies_cleanup(uint32_t p_domain_id);
+ typedef bool (*CoreApiAssemblyLoadedCallback)();
bool _are_api_assemblies_out_of_sync();
+ bool _temp_domain_load_are_assemblies_out_of_sync(const String &p_config);
+
+ bool _load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
+#ifdef TOOLS_ENABLED
+ bool _load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
+#endif
+
+ static bool _on_core_api_assembly_loaded();
bool _load_corlib_assembly();
- bool _load_core_api_assembly();
#ifdef TOOLS_ENABLED
- bool _load_editor_api_assembly();
bool _load_tools_assemblies();
#endif
bool _load_project_assembly();
- bool _try_load_api_assemblies();
+ bool _try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
+ const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback);
+ bool _try_load_api_assemblies_preset();
void _load_api_assemblies();
void _install_trace_listener();
@@ -133,6 +147,8 @@ private:
Error _load_scripts_domain();
Error _unload_scripts_domain();
+ void _domain_assemblies_cleanup(uint32_t p_domain_id);
+
uint64_t api_core_hash;
#ifdef TOOLS_ENABLED
uint64_t api_editor_hash;
@@ -166,9 +182,21 @@ public:
#endif // TOOLS_ENABLED
#endif // DEBUG_METHODS_ENABLED
+ _FORCE_INLINE_ static String get_expected_api_build_config() {
+#ifdef TOOLS_ENABLED
+ return "Debug";
+#else
+#ifdef DEBUG_ENABLED
+ return "Debug";
+#else
+ return "Release";
+#endif
+#endif
+ }
+
#ifdef TOOLS_ENABLED
- bool copy_prebuilt_api_assembly(APIAssembly::Type p_api_type, const String &p_config);
- String update_api_assemblies_from_prebuilt();
+ bool copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config);
+ String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = NULL, const bool *p_editor_api_out_of_sync = NULL);
#endif
static GDMono *get_singleton() { return singleton; }
@@ -188,10 +216,10 @@ public:
_FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
_FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly.assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly; }
+ _FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly.assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_tools_assembly() const { return tools_assembly; }
_FORCE_INLINE_ GDMonoAssembly *get_tools_project_editor_assembly() const { return tools_project_editor_assembly; }
#endif
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index e385f4c601..6504fbe423 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -550,6 +550,8 @@ MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class)
}
MonoDomain *create_domain(const String &p_friendly_name) {
+ print_verbose("Mono: Creating domain '" + p_friendly_name + "'...");
+
MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL);
if (domain) {