You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-24 15:26:15 +00:00
Mono/C#: Add iOS support
Right now, games only work on devices when exported with FullAOT+Interpreter. There are some issues left that need to addressed for FullAOT alone. Right now, it's giving issues with the Godot.NativeCalls static constructor.
This commit is contained in:
@@ -58,7 +58,18 @@
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
#include "android_mono_config.h"
|
||||
#include "gd_mono_android.h"
|
||||
#include "support/android_support.h"
|
||||
#elif defined(IPHONE_ENABLED)
|
||||
#include "support/ios_support.h"
|
||||
#endif
|
||||
|
||||
#if defined(TOOL_ENABLED) && defined(GD_MONO_SINGLE_APPDOMAIN)
|
||||
// This will no longer be the case if we replace appdomains with AssemblyLoadContext
|
||||
#error "Editor build requires support for multiple appdomains"
|
||||
#endif
|
||||
|
||||
#if defined(GD_MONO_HOT_RELOAD) && defined(GD_MONO_SINGLE_APPDOMAIN)
|
||||
#error "Hot reloading requires multiple appdomains"
|
||||
#endif
|
||||
|
||||
// TODO:
|
||||
@@ -178,7 +189,14 @@ MonoDomain *gd_initialize_mono_runtime() {
|
||||
gd_mono_debug_init();
|
||||
#endif
|
||||
|
||||
return mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
|
||||
#if defined(IPHONE_ENABLED) || defined(ANDROID_ENABLED)
|
||||
// I don't know whether this actually matters or not
|
||||
const char *runtime_version = "mobile";
|
||||
#else
|
||||
const char *runtime_version = "v4.0.30319";
|
||||
#endif
|
||||
|
||||
return mono_jit_init_version("GodotEngine.RootDomain", runtime_version);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -320,8 +338,16 @@ void GDMono::initialize() {
|
||||
add_mono_shared_libs_dir_to_path();
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data());
|
||||
#else
|
||||
mono_config_parse(NULL);
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID_ENABLED)
|
||||
GDMonoAndroid::initialize();
|
||||
gdmono::android::support::initialize();
|
||||
#elif defined(IPHONE_ENABLED)
|
||||
gdmono::ios::support::initialize();
|
||||
#endif
|
||||
|
||||
GDMonoAssembly::initialize();
|
||||
@@ -330,12 +356,6 @@ void GDMono::initialize() {
|
||||
gd_mono_profiler_init();
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID_ENABLED
|
||||
mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data());
|
||||
#else
|
||||
mono_config_parse(NULL);
|
||||
#endif
|
||||
|
||||
mono_install_unhandled_exception_hook(&unhandled_exception_hook, NULL);
|
||||
|
||||
#ifndef TOOLS_ENABLED
|
||||
@@ -371,15 +391,19 @@ void GDMono::initialize() {
|
||||
print_verbose("Mono: Runtime initialized");
|
||||
|
||||
#if defined(ANDROID_ENABLED)
|
||||
GDMonoAndroid::register_internal_calls();
|
||||
gdmono::android::support::register_internal_calls();
|
||||
#endif
|
||||
|
||||
// mscorlib assembly MUST be present at initialization
|
||||
bool corlib_loaded = _load_corlib_assembly();
|
||||
ERR_FAIL_COND_MSG(!corlib_loaded, "Mono: Failed to load mscorlib assembly.");
|
||||
|
||||
#ifndef GD_MONO_SINGLE_APPDOMAIN
|
||||
Error domain_load_err = _load_scripts_domain();
|
||||
ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
|
||||
#else
|
||||
scripts_domain = root_domain;
|
||||
#endif
|
||||
|
||||
_register_internal_calls();
|
||||
|
||||
@@ -491,11 +515,15 @@ void GDMono::add_assembly(uint32_t p_domain_id, GDMonoAssembly *p_assembly) {
|
||||
assemblies[p_domain_id][p_assembly->get_name()] = p_assembly;
|
||||
}
|
||||
|
||||
GDMonoAssembly **GDMono::get_loaded_assembly(const String &p_name) {
|
||||
GDMonoAssembly *GDMono::get_loaded_assembly(const String &p_name) {
|
||||
|
||||
if (p_name == "mscorlib")
|
||||
return get_corlib_assembly();
|
||||
|
||||
MonoDomain *domain = mono_domain_get();
|
||||
uint32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
|
||||
return assemblies[domain_id].getptr(p_name);
|
||||
GDMonoAssembly **result = assemblies[domain_id].getptr(p_name);
|
||||
return result ? *result : NULL;
|
||||
}
|
||||
|
||||
bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
|
||||
@@ -549,14 +577,6 @@ bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMo
|
||||
if (!assembly)
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
|
||||
GDMonoAssembly **stored_assembly = assemblies[domain_id].getptr(p_name);
|
||||
|
||||
ERR_FAIL_COND_V(stored_assembly == NULL, false);
|
||||
ERR_FAIL_COND_V(*stored_assembly != assembly, false);
|
||||
#endif
|
||||
|
||||
*r_assembly = assembly;
|
||||
|
||||
print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
|
||||
@@ -894,8 +914,8 @@ void GDMono::_load_api_assemblies() {
|
||||
|
||||
bool api_assemblies_loaded = _try_load_api_assemblies_preset();
|
||||
|
||||
#if defined(TOOLS_ENABLED) && !defined(GD_MONO_SINGLE_APPDOMAIN)
|
||||
if (!api_assemblies_loaded) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
// 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.
|
||||
|
||||
@@ -916,8 +936,8 @@ void GDMono::_load_api_assemblies() {
|
||||
|
||||
// 4. Try loading the updated assemblies
|
||||
api_assemblies_loaded = _try_load_api_assemblies_preset();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!api_assemblies_loaded) {
|
||||
// welp... too bad
|
||||
@@ -991,6 +1011,7 @@ void GDMono::_install_trace_listener() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef GD_MONO_SINGLE_APPDOMAIN
|
||||
Error GDMono::_load_scripts_domain() {
|
||||
|
||||
ERR_FAIL_COND_V(scripts_domain != NULL, ERR_BUG);
|
||||
@@ -1010,7 +1031,7 @@ Error GDMono::_unload_scripts_domain() {
|
||||
|
||||
ERR_FAIL_NULL_V(scripts_domain, ERR_BUG);
|
||||
|
||||
print_verbose("Mono: Unloading scripts domain...");
|
||||
print_verbose("Mono: Finalizing scripts domain...");
|
||||
|
||||
if (mono_domain_get() != root_domain)
|
||||
mono_domain_set(root_domain, true);
|
||||
@@ -1043,6 +1064,8 @@ Error GDMono::_unload_scripts_domain() {
|
||||
MonoDomain *domain = scripts_domain;
|
||||
scripts_domain = NULL;
|
||||
|
||||
print_verbose("Mono: Unloading scripts domain...");
|
||||
|
||||
MonoException *exc = NULL;
|
||||
mono_domain_try_unload(domain, (MonoObject **)&exc);
|
||||
|
||||
@@ -1054,6 +1077,7 @@ Error GDMono::_unload_scripts_domain() {
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GD_MONO_HOT_RELOAD
|
||||
Error GDMono::reload_scripts_domain() {
|
||||
@@ -1092,6 +1116,7 @@ Error GDMono::reload_scripts_domain() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef GD_MONO_SINGLE_APPDOMAIN
|
||||
Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
|
||||
|
||||
CRASH_COND(p_domain == NULL);
|
||||
@@ -1123,6 +1148,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
|
||||
|
||||
@@ -1150,13 +1176,17 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
|
||||
|
||||
GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) {
|
||||
|
||||
GDMonoClass *klass = corlib_assembly->get_class(p_namespace, p_name);
|
||||
if (klass)
|
||||
return klass;
|
||||
|
||||
uint32_t domain_id = mono_domain_get_id(mono_domain_get());
|
||||
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
|
||||
|
||||
const String *k = NULL;
|
||||
while ((k = domain_assemblies.next(k))) {
|
||||
GDMonoAssembly *assembly = domain_assemblies.get(*k);
|
||||
GDMonoClass *klass = assembly->get_class(p_namespace, p_name);
|
||||
klass = assembly->get_class(p_namespace, p_name);
|
||||
if (klass)
|
||||
return klass;
|
||||
}
|
||||
@@ -1223,12 +1253,44 @@ GDMono::GDMono() {
|
||||
GDMono::~GDMono() {
|
||||
|
||||
if (is_runtime_initialized()) {
|
||||
#ifndef GD_MONO_SINGLE_APPDOMAIN
|
||||
if (scripts_domain) {
|
||||
Error err = _unload_scripts_domain();
|
||||
if (err != OK) {
|
||||
ERR_PRINT("Mono: Failed to unload scripts domain.");
|
||||
}
|
||||
}
|
||||
#else
|
||||
CRASH_COND(scripts_domain != root_domain);
|
||||
|
||||
print_verbose("Mono: Finalizing scripts domain...");
|
||||
|
||||
if (mono_domain_get() != root_domain)
|
||||
mono_domain_set(root_domain, true);
|
||||
|
||||
finalizing_scripts_domain = true;
|
||||
|
||||
if (!mono_domain_finalize(root_domain, 2000)) {
|
||||
ERR_PRINT("Mono: Domain finalization timeout.");
|
||||
}
|
||||
|
||||
finalizing_scripts_domain = false;
|
||||
|
||||
mono_gc_collect(mono_gc_max_generation());
|
||||
|
||||
GDMonoCache::clear_godot_api_cache();
|
||||
|
||||
_domain_assemblies_cleanup(mono_domain_get_id(root_domain));
|
||||
|
||||
core_api_assembly.assembly = NULL;
|
||||
|
||||
project_assembly = NULL;
|
||||
|
||||
root_domain = NULL;
|
||||
scripts_domain = NULL;
|
||||
|
||||
// Leave the rest to 'mono_jit_cleanup'
|
||||
#endif
|
||||
|
||||
const uint32_t *k = NULL;
|
||||
while ((k = assemblies.next(k))) {
|
||||
@@ -1245,15 +1307,15 @@ GDMono::~GDMono() {
|
||||
|
||||
mono_jit_cleanup(root_domain);
|
||||
|
||||
#if defined(ANDROID_ENABLED)
|
||||
GDMonoAndroid::cleanup();
|
||||
#endif
|
||||
|
||||
print_verbose("Mono: Finalized");
|
||||
|
||||
runtime_initialized = false;
|
||||
}
|
||||
|
||||
#if defined(ANDROID_ENABLED)
|
||||
gdmono::android::support::cleanup();
|
||||
#endif
|
||||
|
||||
if (gdmono_log)
|
||||
memdelete(gdmono_log);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user