diff --git a/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp b/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp index 2d0cec1e..6226949e 100644 --- a/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp +++ b/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp @@ -115,7 +115,7 @@ namespace SHADE ( runtimePath.c_str(), // AppDomain base path "SHADEHost", // AppDomain friendly name - propertyKeys.size(), // Property count + static_cast(propertyKeys.size()), // Property count propertyKeys.data(), // Property names propertyValues.data(), // Property values &hostHandle, // Host handle diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index ac8ad84c..5f816066 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -244,10 +244,10 @@ namespace SHADE true\n\ \n\ \n\ - \n\ - \n\ - \n\ - \n\ + \n\ + \n\ + \n\ + \n\ \n\ \n\ \n\ diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h index 85e3ac3f..bd9fb079 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -183,8 +183,8 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Constants */ /*-----------------------------------------------------------------------------*/ - static constexpr std::string_view DEFAULT_CSHARP_LIB_NAME = "SHADEAPI"; - static constexpr std::string_view MANAGED_SCRIPT_LIB_NAME = "SHADEManaged"; + static constexpr std::string_view DEFAULT_CSHARP_LIB_NAME = "SHADE_Managed"; + static constexpr std::string_view MANAGED_SCRIPT_LIB_NAME = "SHADE_Scripting"; static const std::string DEFAULT_CSHARP_NAMESPACE; /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/SHADE_Managed.vcxproj.filters b/SHADE_Managed/SHADE_Managed.vcxproj.filters index ae83954d..776142d3 100644 --- a/SHADE_Managed/SHADE_Managed.vcxproj.filters +++ b/SHADE_Managed/SHADE_Managed.vcxproj.filters @@ -15,6 +15,9 @@ + + Engine + Engine @@ -48,6 +51,10 @@ + + + Engine + Engine diff --git a/SHADE_Managed/src/AssemblyInfo.cxx b/SHADE_Managed/src/AssemblyInfo.cxx new file mode 100644 index 00000000..234bda73 --- /dev/null +++ b/SHADE_Managed/src/AssemblyInfo.cxx @@ -0,0 +1,39 @@ +/************************************************************************************//*! +\file AssemblyInfo.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 24, 2021 +\brief Defines the properties of this managed .NET Assembly. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2022 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#include "SHpch.h" + +/*-------------------------------------------------------------------------------------*/ +/* Using Declarations */ +/*-------------------------------------------------------------------------------------*/ +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +/*-------------------------------------------------------------------------------------*/ +/* Assembly Properties */ +/*-------------------------------------------------------------------------------------*/ +[assembly:AssemblyTitleAttribute(L"SHADE_Managed")]; +[assembly:AssemblyDescriptionAttribute(L"")]; +[assembly:AssemblyConfigurationAttribute(L"")]; +[assembly:AssemblyCompanyAttribute(L"")]; +[assembly:AssemblyProductAttribute(L"SHADE_Managed")]; +[assembly:AssemblyCopyrightAttribute(L"Copyright (C) 2022 DigiPen Institute of Technology")]; +[assembly:AssemblyTrademarkAttribute(L"")]; +[assembly:AssemblyCultureAttribute(L"")]; + +[assembly:AssemblyVersionAttribute("1.0.*")]; + +[assembly:ComVisible(false)]; diff --git a/SHADE_Managed/src/Engine/EngineInterface.cxx b/SHADE_Managed/src/Engine/EngineInterface.cxx new file mode 100644 index 00000000..27645342 --- /dev/null +++ b/SHADE_Managed/src/Engine/EngineInterface.cxx @@ -0,0 +1,138 @@ +/************************************************************************************//*! +\file EngineInterface.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the implementation of the managed EngineInterface static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +// Precompiled Headers +#include "SHpch.h" +// Primary Header +#include "EngineInterface.hxx" +// Standard Libraries +#include +// Project Headers +#include "Utility/Convert.hxx" +#include "Utility/Debug.hxx" +#include "Scripts/ScriptStore.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructor */ + /*---------------------------------------------------------------------------------*/ + static EngineInterface::EngineInterface() + { + exceptionHandler = gcnew System::UnhandledExceptionEventHandler(unhandledExceptionHandler); + managedLibPath = System::Reflection::Assembly::GetExecutingAssembly()->Location->Replace("SHADE_Managed.dll", ManagedLibraryName + ".dll"); + } + + /*---------------------------------------------------------------------------------*/ + /* Interop Static Functions */ + /*---------------------------------------------------------------------------------*/ + void EngineInterface::Init() + { + SAFE_NATIVE_CALL_BEGIN + // Set up exception handler + System::AppDomain::CurrentDomain->UnhandledException += exceptionHandler; + LoadScriptAssembly(); + Debug::Log("[EngineInterface] Successfully initialized managed runtime."); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::UnloadScriptAssembly() + { + SAFE_NATIVE_CALL_BEGIN + std::ostringstream oss; + oss << "[EngineInterface] Unloading " << Convert::ToNative(ManagedLibraryName) << ".dll"; + ScriptStore::Exit(); + + // Unload the script + scriptContext->Unload(); + scriptContext = nullptr; + System::GC::Collect(); + System::GC::WaitForPendingFinalizers(); + + // Unload the assembly File + if (managedLibFile != nullptr) + { + managedLibFile->Close(); + managedLibFile = nullptr; + } + + oss.str(""); + oss << "[EngineInterface] Successfully unloaded " << Convert::ToNative(ManagedLibraryName) << ".dll"; + Debug::Log(oss.str()); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::LoadScriptAssembly() + { + SAFE_NATIVE_CALL_BEGIN + scriptContext = gcnew DisposableAssemblyLoadContext(); + loadManagedLibrary(); + ScriptStore::Init(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::ReloadScriptAssembly() + { + SAFE_NATIVE_CALL_BEGIN + // Stop scripts + UnloadScriptAssembly(); + // Reload assembly and restart scripts runtime + LoadScriptAssembly(); + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + void EngineInterface::Exit() + { + SAFE_NATIVE_CALL_BEGIN + // Clean up ScriptStore + ScriptStore::Exit(); + scriptContext->Unload(); + + // Release exception handler + System::AppDomain::CurrentDomain->UnhandledException -= exceptionHandler; + SAFE_NATIVE_CALL_END_N("SHADE_Managed.EngineInterface") + } + + /*---------------------------------------------------------------------------------*/ + /* Helper Functions */ + /*---------------------------------------------------------------------------------*/ + void EngineInterface::loadManagedLibrary() + { + using namespace System::IO; + + std::ostringstream oss; + try + { + oss << "[EngineInterface] Loading " << Convert::ToNative(ManagedLibraryName) << ".dll"; + managedLibFile = File::Open(managedLibPath, FileMode::Open, FileAccess::Read); + scriptContext->LoadFromStream(managedLibFile); + oss.str(""); + oss << "[EngineInterface] Successfully loaded " << Convert::ToNative(ManagedLibraryName) << ".dll"; + Debug::Log(oss.str()); + } + catch (System::Exception^ e) + { + oss << "[EngineInterface] Unable to load " << Convert::ToNative(ManagedLibraryName) << ".dll!" + << "(" << Convert::ToNative(e->ToString()) << ")"; + Debug::LogError(oss.str()); + } + } + + /*---------------------------------------------------------------------------------*/ + /* Exception Handler Functions */ + /*---------------------------------------------------------------------------------*/ + void EngineInterface::unhandledExceptionHandler(System::Object^ sender, System::UnhandledExceptionEventArgs^ e) + { + std::ostringstream oss; + oss << "[EngineInterface] Unhandled managed exception: " + << Convert::ToNative(e->ExceptionObject->GetType()->ToString()) << ": " + << Convert::ToNative(e->ExceptionObject->ToString()); + Debug::LogError(oss.str()); + } +} diff --git a/SHADE_Managed/src/Engine/EngineInterface.hxx b/SHADE_Managed/src/Engine/EngineInterface.hxx new file mode 100644 index 00000000..7bd5e010 --- /dev/null +++ b/SHADE_Managed/src/Engine/EngineInterface.hxx @@ -0,0 +1,90 @@ +/************************************************************************************//*! +\file EngineInterface.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 28, 2021 +\brief Contains the definitions of the managed EngineInterface static class. + + Note: This file is written in C++17/CLI. + +Copyright (C) 2021 DigiPen Institute of Technology. +Reproduction or disclosure of this file or its contents without the prior written consent +of DigiPen Institute of Technology is prohibited. +*//*************************************************************************************/ +#pragma once + +// Project Includes +#include "Utility/DisposableAssemblyLoadContext.hxx" + +namespace SHADE +{ + /// + /// Static class that contains the functions for interfacing with the core + /// PlushieEngine written in C++ for managing the lifecycle of managed code. + /// + private ref class EngineInterface abstract sealed + { + public: + /*-----------------------------------------------------------------------------*/ + /* Constants */ + /*-----------------------------------------------------------------------------*/ + /// + /// Name of the Managed Library that contains the C# scripts written externally. + /// + literal System::String^ ManagedLibraryName = "SHADE_Scripting"; + + /*-----------------------------------------------------------------------------*/ + /* Constructor */ + /*-----------------------------------------------------------------------------*/ + static EngineInterface(); + + /*-----------------------------------------------------------------------------*/ + /* Interop Static Functions */ + /*-----------------------------------------------------------------------------*/ + /// + /// Initialises all required components for managed code. + /// + static void Init(); + /// + /// Unloads the managed script assembly. + /// Take note that this will clear all existing scripts, ensure that the scene + /// is saved before doing so. + /// + static void UnloadScriptAssembly(); + /// + /// Loads the managed script assembly. Ensure this is only called after + /// UnloadScriptAssembly() has been called. + /// + static void LoadScriptAssembly(); + /// + /// Reloads the managed script assembly. + /// Take note that this will clear all existing scripts, ensure that the scene + /// is saved before doing so. + /// Equivalent to calling UnloadScriptAssembly() and then LoadScriptAssembly(). + /// + static void ReloadScriptAssembly(); + /// + /// Cleans up all required components for managed code. + /// + static void Exit(); + + private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ + static DisposableAssemblyLoadContext^ scriptContext; + static System::UnhandledExceptionEventHandler^ exceptionHandler; + static System::String^ managedLibPath; + static System::IO::FileStream^ managedLibFile; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + static void loadManagedLibrary(); + + /*-----------------------------------------------------------------------------*/ + /* Exception Handler Functions */ + /*-----------------------------------------------------------------------------*/ + static void unhandledExceptionHandler(System::Object^ sender, System::UnhandledExceptionEventArgs^ e); + }; +} \ No newline at end of file diff --git a/SHADE_Managed/src/Utility/Debug.cxx b/SHADE_Managed/src/Utility/Debug.cxx index 70392bf1..bba0136f 100644 --- a/SHADE_Managed/src/Utility/Debug.cxx +++ b/SHADE_Managed/src/Utility/Debug.cxx @@ -28,6 +28,10 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* Logging Functions */ /*---------------------------------------------------------------------------------*/ + void Debug::Log(const std::string& str) + { + SHLOG_INFO(str); + } void Debug::Log(System::String^ str) { SHLOG_INFO(Convert::ToNative(str)); @@ -47,6 +51,10 @@ namespace SHADE oss << "[" << throwerName << "] " << Convert::ToNative(str); SHLOG_INFO(oss.str()); } + void Debug::LogWarning(const std::string& str) + { + SHLOG_WARNING(str); + } void Debug::LogWarning(System::String^ str) { SHLOG_WARNING(Convert::ToNative(str)); @@ -66,6 +74,10 @@ namespace SHADE oss << "[" << throwerName << "] " << Convert::ToNative(str); SHLOG_WARNING(oss.str()); } + void Debug::LogError(const std::string& str) + { + SHLOG_ERROR(str); + } void Debug::LogError(System::String^ str) { SHLOG_ERROR(Convert::ToNative(str)); diff --git a/SHADE_Managed/src/Utility/Debug.hxx b/SHADE_Managed/src/Utility/Debug.hxx index e6176792..28f2bc88 100644 --- a/SHADE_Managed/src/Utility/Debug.hxx +++ b/SHADE_Managed/src/Utility/Debug.hxx @@ -98,6 +98,11 @@ namespace SHADE /// Logs a message to the output. /// /// The string to output. + static void Log(const std::string& str); + /// + /// Logs a message to the output. + /// + /// The string to output. static void Log(System::String^ str); /// /// Logs a message to the output with a label such that it looks like this: @@ -133,6 +138,11 @@ namespace SHADE /// Logs a warning message to the output. /// /// The string to output. + static void LogWarning(const std::string& str); + /// + /// Logs a warning message to the output. + /// + /// The string to output. static void LogWarning(System::String^ str); /// /// Logs a warning message to the output with a label such that it looks like this: @@ -168,6 +178,11 @@ namespace SHADE /// Logs a error message to the output. /// /// The string to output. + static void LogError(const std::string& str); + /// + /// Logs a error message to the output. + /// + /// The string to output. static void LogError(System::String^ str); /// /// Logs a error message to the output with a label such that it looks like this: