Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Editor]: Stop Loading .Net Project Assembly when TOOLS is not Defined #98153

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPt
return false.ToGodotBool();
}
}

#if TOOLS
#pragma warning disable CS0169
private static bool ToolsDefined;
#pragma warning restore CS0169
#endif
}
}
";
Expand Down
20 changes: 18 additions & 2 deletions modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,33 +131,49 @@ private static unsafe godot_bool InitializeFromEngine(IntPtr godotDllHandle, god
[StructLayout(LayoutKind.Sequential)]
private struct PluginsCallbacks
{
public unsafe delegate* unmanaged<char*, godot_string*, godot_bool> LoadProjectAssemblyCallback;
public unsafe delegate* unmanaged<char*, godot_string*, godot_string*, godot_bool*, godot_bool> LoadProjectAssemblyCallback;
public unsafe delegate* unmanaged<char*, IntPtr, int, IntPtr> LoadToolsAssemblyCallback;
public unsafe delegate* unmanaged<godot_bool> UnloadProjectPluginCallback;
}

[UnmanagedCallersOnly]
private static unsafe godot_bool LoadProjectAssembly(char* nAssemblyPath, godot_string* outLoadedAssemblyPath)
private static unsafe godot_bool LoadProjectAssembly(char* nAssemblyPath, godot_string* outLoadedAssemblyPath, godot_string* outFailedReason, godot_bool* shouldRetry)
{
try
{
if (_projectLoadContext != null)
return godot_bool.True; // Already loaded

*shouldRetry = godot_bool.False;
string assemblyPath = new(nAssemblyPath);

(var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath, isCollectible: _editorHint);

string loadedAssemblyPath = _projectLoadContext.AssemblyLoadedPath ?? assemblyPath;
*outLoadedAssemblyPath = Marshaling.ConvertStringToNative(loadedAssemblyPath);

// This generated field is here to ensure that
// the developer do not drop the TOOLS compiler preprocessor
// from their csproj, which breaks the C# Editor Functionality.
var isToolsDefinedField =
projectAssembly
.GetType("GodotPlugins.Game.Main")?
.GetField("ToolsDefined", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

if (isToolsDefinedField == null)
{
*outFailedReason = Marshaling.ConvertStringToNative("The csproj was missing the `TOOLS` compiler symbol, which is required for C# editor functionality. Please modify the csproj file and rebuild the C# project, check https://github.com/godotengine/godot/issues/98124 for more information.");
return godot_bool.False;
}

ScriptManagerBridge.LookupScriptsInAssembly(projectAssembly);

return godot_bool.True;
}
catch (Exception e)
{
Console.Error.WriteLine(e);
*outFailedReason = Marshaling.ConvertStringToNative(e.Message);
return godot_bool.False;
}
}
Expand Down
32 changes: 25 additions & 7 deletions modules/mono/mono_gd/gd_mono.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,9 +605,15 @@ void GDMono::_try_load_project_assembly() {
// Load the project's main assembly. This doesn't necessarily need to succeed.
// The game may not be using .NET at all, or if the project does use .NET and
// we're running in the editor, it may just happen to be it wasn't built yet.
if (!_load_project_assembly()) {
String error_message;
bool should_retry;
if (!_load_project_assembly(&error_message, &should_retry)) {
if (OS::get_singleton()->is_stdout_verbose()) {
print_error(".NET: Failed to load project assembly");
if (error_message.is_empty()) {
print_error(".NET: Failed to load project assembly");
} else {
print_error(".NET: Failed to load project assembly: " + error_message);
}
}
}
}
Expand All @@ -624,19 +630,22 @@ void GDMono::_init_godot_api_hashes() {
}

#ifdef TOOLS_ENABLED
bool GDMono::_load_project_assembly() {
bool GDMono::_load_project_assembly(String *p_error_message, bool *p_should_retry) {
*p_should_retry = true;

String assembly_name = path::get_csharp_project_name();

String assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
.path_join(assembly_name + ".dll");
assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);

if (!FileAccess::exists(assembly_path)) {
*p_error_message = String("Assembly Path \"" + assembly_path + "\" does not exist");
return false;
}

String loaded_assembly_path;
bool success = plugin_callbacks.LoadProjectAssemblyCallback(assembly_path.utf16(), &loaded_assembly_path);
bool success = plugin_callbacks.LoadProjectAssemblyCallback(assembly_path.utf16(), &loaded_assembly_path, p_error_message, p_should_retry);

if (success) {
project_assembly_path = loaded_assembly_path.simplify_path();
Expand Down Expand Up @@ -679,10 +688,19 @@ Error GDMono::reload_project_assemblies() {

// Load the project's main assembly. Here, during hot-reloading, we do
// consider failing to load the project's main assembly to be an error.
if (!_load_project_assembly()) {
ERR_PRINT_ED(".NET: Failed to load project assembly.");
String error_message;
bool should_retry;
if (!_load_project_assembly(&error_message, &should_retry)) {
if (error_message.is_empty()) {
ERR_PRINT_ED(".NET: Failed to load project assembly.");
} else {
ERR_PRINT_ED(".NET: Failed to load project assembly: " + error_message);
}
if (!should_retry) {
project_load_failure_count = (int)GLOBAL_GET("dotnet/project/assembly_reload_attempts");
}
reload_failure();
return ERR_CANT_OPEN;
return FAILED;
}

if (project_load_failure_count > 0) {
Expand Down
4 changes: 2 additions & 2 deletions modules/mono/mono_gd/gd_mono.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace gdmono {

#ifdef TOOLS_ENABLED
struct PluginCallbacks {
using FuncLoadProjectAssemblyCallback = bool(GD_CLR_STDCALL *)(const char16_t *, String *);
using FuncLoadProjectAssemblyCallback = bool(GD_CLR_STDCALL *)(const char16_t *, String *, String *, bool *);
using FuncLoadToolsAssemblyCallback = Object *(GD_CLR_STDCALL *)(const char16_t *, const void **, int32_t);
using FuncUnloadProjectPluginCallback = bool(GD_CLR_STDCALL *)();
FuncLoadProjectAssemblyCallback LoadProjectAssemblyCallback = nullptr;
Expand All @@ -73,7 +73,7 @@ class GDMono {
#endif

#ifdef TOOLS_ENABLED
bool _load_project_assembly();
bool _load_project_assembly(String *p_error_message, bool *p_should_retry);
void _try_load_project_assembly();
#endif

Expand Down
Loading