CScriptSystem::CScriptSystem() : m_pRootDomain(nullptr) , m_pCryBraryAssembly(nullptr) , m_pPdb2MdbAssembly(nullptr) , m_pScriptManager(nullptr) , m_pScriptDomain(nullptr) , m_bReloading(false) , m_bDetectedChanges(false) , m_bQuitting(false) , m_pConverter(nullptr) { CryLogAlways("Initializing Mono Script System"); #ifndef PLUGIN_SDK gEnv->pMonoScriptSystem = this; #endif; g_pScriptSystem = this; m_pCVars = new SCVars(); g_pMonoCVars = m_pCVars; // We should look into storing mono binaries, configuration as well as scripts via CryPak. mono_set_dirs(PathUtils::GetMonoLibPath(), PathUtils::GetMonoConfigPath()); #ifndef _RELEASE // Enable Mono signal handling // Makes sure that Mono sends back exceptions it tries to handle, for CE crash handling. mono_set_signal_chaining(true); #endif string monoCmdOptions = ""; if(auto *pArg = gEnv->pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "monoArgs")) monoCmdOptions.append(pArg->GetValue()); // Commandline switch -DEBUG makes the process connect to the debugging server. Warning: Failure to connect to a debugging server WILL result in a crash. // This is currently a WIP feature which requires custom MonoDevelop extensions and other irritating things. const ICmdLineArg* arg = gEnv->pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "DEBUG"); if (arg != nullptr) monoCmdOptions.append("--debugger-agent=transport=dt_socket,address=127.0.0.1:65432,embedding=1"); #ifndef _RELEASE else if(g_pMonoCVars->mono_softBreakpoints) // Soft breakpoints not compatible with debugging server { CryLogAlways(" [Performance Warning] Mono soft breakpoints are enabled!"); // Prevents managed null reference exceptions causing crashes in unmanaged code // See: https://bugzilla.xamarin.com/show_bug.cgi?id=5963 monoCmdOptions.append("--soft-breakpoints"); } #endif char *options = new char[monoCmdOptions.size() + 1]; strcpy(options, monoCmdOptions.c_str()); // Note: iPhone requires AOT compilation, this can be enforced via mono options. TODO: Get Crytek to add CryMobile support to the Free SDK. mono_jit_parse_options(1, &options); #ifndef _RELEASE // Required for mdb's to load for detailed stack traces etc. mono_debug_init(MONO_DEBUG_FORMAT_MONO); #endif m_pConverter = new CConverter(); if(!CompleteInit()) return; if(IFileChangeMonitor *pFileChangeMonitor = gEnv->pFileChangeMonitor) pFileChangeMonitor->RegisterListener(this, "scripts\\"); }
CScriptSystem::CScriptSystem(IGameFramework *pGameFramework) : m_pRootDomain(nullptr) , m_pCryBraryAssembly(nullptr) , m_pPdb2MdbAssembly(nullptr) , m_pScriptManager(nullptr) , m_pScriptDomain(nullptr) , m_bReloading(false) , m_bDetectedChanges(false) , m_bQuitting(false) , m_pConverter(nullptr) , m_bFirstReload(true) , m_pGameFramework(pGameFramework) { CryLogAlways("Initializing Mono Script System"); g_pThis = this; m_pCVars = new SCVars(); g_pMonoCVars = m_pCVars; // We should look into storing mono binaries, configuration as well as scripts via CryPak. mono_set_dirs(PathUtils::GetMonoLibPath(), PathUtils::GetMonoConfigPath()); #ifndef _RELEASE // Enable Mono signal handling // Makes sure that Mono sends back exceptions it tries to handle, for CE crash handling. mono_set_signal_chaining(true); #endif string monoCmdOptions = ""; if(auto *pArg = gEnv->pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "monoArgs")) monoCmdOptions.append(pArg->GetValue()); // Commandline switch -DEBUG makes the process connect to the debugging server. Warning: Failure to connect to a debugging server WILL result in a crash. // This is currently a WIP feature which requires custom MonoDevelop extensions and other irritating things. const ICmdLineArg* arg = gEnv->pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "DEBUG"); if (arg != nullptr) monoCmdOptions.append("--debugger-agent=transport=dt_socket,address=127.0.0.1:65432,embedding=1"); #ifndef _RELEASE else if(g_pMonoCVars->mono_softBreakpoints) // Soft breakpoints not compatible with debugging server { CryLogAlways(" [Performance Warning] Mono soft breakpoints are enabled!"); // Prevents managed null reference exceptions causing crashes in unmanaged code // See: https://bugzilla.xamarin.com/show_bug.cgi?id=5963 monoCmdOptions.append("--soft-breakpoints"); } #endif char *options = new char[monoCmdOptions.size() + 1]; strcpy(options, monoCmdOptions.c_str()); // Note: iPhone requires AOT compilation, this can be enforced via mono options. TODO: Get Crytek to add CryMobile support to the Free SDK. mono_jit_parse_options(1, &options); #ifndef _RELEASE // Required for mdb's to load for detailed stack traces etc. mono_debug_init(MONO_DEBUG_FORMAT_MONO); #endif m_pConverter = new CConverter(); if(!CompleteInit()) { CryLogAlways("CryMono initialization failed!"); return; } RegisterSecondaryBindings(); pGameFramework->RegisterListener(this, "CryMono", FRAMEWORKLISTENERPRIORITY_GAME); gEnv->pSystem->GetISystemEventDispatcher()->RegisterListener(&g_systemEventListener_CryMono); if(IFileChangeMonitor *pFileChangeMonitor = gEnv->pFileChangeMonitor) pFileChangeMonitor->RegisterListener(this, "scripts\\"); CryModuleMemoryInfo memInfo; CryModuleGetMemoryInfo(&memInfo); IMonoClass *pCryStats = m_pCryBraryAssembly->GetClass("CryStats", "CryEngine.Utilities"); IMonoObject *pMemoryUsage = *pCryStats->GetPropertyValue(NULL, "MemoryUsage"); CryLogAlways(" Initializing CryMono done, MemUsage=%iKb", (memInfo.allocated + pMemoryUsage->Unbox<long>()) / 1024); pMemoryUsage->Release(); }
static void InitMono() { std::string citizenClrPath = MakeRelativeNarrowPath("citizen/clr2/lib/"); std::string citizenCfgPath = MakeRelativeNarrowPath("citizen/clr2/cfg/"); mono_set_dirs(citizenClrPath.c_str(), citizenCfgPath.c_str()); #ifdef _WIN32 std::wstring citizenClrLibPath = MakeRelativeCitPath(L"citizen/clr2/lib/mono/4.5/"); SetEnvironmentVariable(L"MONO_PATH", citizenClrLibPath.c_str()); mono_set_crash_chaining(true); #else std::string citizenClrLibPath = MakeRelativeNarrowPath("citizen/clr2/lib/mono/4.5/"); putenv(const_cast<char*>(va("MONO_PATH=%s", citizenClrLibPath))); #endif mono_assembly_setrootdir(citizenClrPath.c_str()); putenv("MONO_DEBUG=casts"); #ifndef IS_FXSERVER mono_security_enable_core_clr(); mono_security_core_clr_set_options((MonoSecurityCoreCLROptions)(MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_DELEGATE | MONO_SECURITY_CORE_CLR_OPTIONS_RELAX_REFLECTION)); mono_security_set_core_clr_platform_callback(CoreClrCallback); #endif char* args[1]; #ifdef _WIN32 args[0] = "--soft-breakpoints"; #else args[0] = "--use-fallback-tls"; #endif mono_jit_parse_options(1, args); mono_debug_init(MONO_DEBUG_FORMAT_MONO); g_rootDomain = mono_jit_init_version("Citizen", "v4.0.30319"); mono_domain_set_config(g_rootDomain, ".", "cfx.config"); mono_install_unhandled_exception_hook([] (MonoObject* exc, void*) { OutputExceptionDetails(exc); }, nullptr); mono_set_crash_chaining(true); mono_add_internal_call("CitizenFX.Core.GameInterface::PrintLog", reinterpret_cast<void*>(GI_PrintLogCall)); mono_add_internal_call("CitizenFX.Core.GameInterface::fwFree", reinterpret_cast<void*>(fwFree)); std::string platformPath = MakeRelativeNarrowPath("citizen/clr2/lib/mono/4.5/CitizenFX.Core.dll"); auto scriptManagerAssembly = mono_domain_assembly_open(g_rootDomain, platformPath.c_str()); if (!scriptManagerAssembly) { FatalError("Could not load CitizenFX.Core.dll.\n"); } auto scriptManagerImage = mono_assembly_get_image(scriptManagerAssembly); bool methodSearchSuccess = true; MonoMethodDesc* description; #define method_search(name, method) description = mono_method_desc_new(name, 1); \ method = mono_method_desc_search_in_image(description, scriptManagerImage); \ mono_method_desc_free(description); \ methodSearchSuccess = methodSearchSuccess && method != NULL MonoMethod* rtInitMethod; method_search("CitizenFX.Core.RuntimeManager:Initialize", rtInitMethod); method_search("CitizenFX.Core.RuntimeManager:GetImplementedClasses", g_getImplementsMethod); method_search("CitizenFX.Core.RuntimeManager:CreateObjectInstance", g_createObjectMethod); if (!methodSearchSuccess) { FatalError("Couldn't find one or more CitizenFX.Core methods.\n"); } MonoObject* exc = nullptr; mono_runtime_invoke(rtInitMethod, nullptr, nullptr, &exc); if (exc) { OutputExceptionDetails(exc); return; } }