Added SHScriptEngine and SHDotNetRuntime for managed code execution
This commit is contained in:
parent
ba5bea9d53
commit
548b09df06
|
@ -187,15 +187,24 @@
|
||||||
<ClInclude Include="src\Math\Vector\SHVec4.h" />
|
<ClInclude Include="src\Math\Vector\SHVec4.h" />
|
||||||
<ClInclude Include="src\Meta\SHIsDetected.h" />
|
<ClInclude Include="src\Meta\SHIsDetected.h" />
|
||||||
<ClInclude Include="src\Resource\Handle.h" />
|
<ClInclude Include="src\Resource\Handle.h" />
|
||||||
|
<ClInclude Include="src\Resource\Handle.hpp" />
|
||||||
<ClInclude Include="src\Resource\ResourceLibrary.h" />
|
<ClInclude Include="src\Resource\ResourceLibrary.h" />
|
||||||
|
<ClInclude Include="src\Resource\ResourceLibrary.hpp" />
|
||||||
<ClInclude Include="src\Resource\SparseSet.h" />
|
<ClInclude Include="src\Resource\SparseSet.h" />
|
||||||
|
<ClInclude Include="src\Resource\SparseSet.hpp" />
|
||||||
<ClInclude Include="src\SHpch.h" />
|
<ClInclude Include="src\SHpch.h" />
|
||||||
<ClInclude Include="src\Scene\SHScene.h" />
|
<ClInclude Include="src\Scene\SHScene.h" />
|
||||||
<ClInclude Include="src\Scene\SHSceneManager.h" />
|
<ClInclude Include="src\Scene\SHSceneManager.h" />
|
||||||
|
<ClInclude Include="src\Scripting\SHDotNetRuntime.h" />
|
||||||
|
<ClInclude Include="src\Scripting\SHDotNetRuntime.hpp" />
|
||||||
|
<ClInclude Include="src\Scripting\SHScriptEngine.h" />
|
||||||
<ClInclude Include="src\Tools\SHException.h" />
|
<ClInclude Include="src\Tools\SHException.h" />
|
||||||
<ClInclude Include="src\Tools\SHExceptionHandler.h" />
|
<ClInclude Include="src\Tools\SHExceptionHandler.h" />
|
||||||
<ClInclude Include="src\Tools\SHLogger.h" />
|
<ClInclude Include="src\Tools\SHLogger.h" />
|
||||||
<ClInclude Include="src\Tools\SHUtilities.h" />
|
<ClInclude Include="src\Tools\SHUtilities.h" />
|
||||||
|
<ClInclude Include="src\Tools\SHUtilities.hpp" />
|
||||||
|
<ClInclude Include="src\Tools\SHStringUtils.h" />
|
||||||
|
<ClInclude Include="src\Tools\SHStringUtils.hpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp" />
|
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp" />
|
||||||
|
@ -262,9 +271,12 @@
|
||||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="src\Scene\SHSceneManager.cpp" />
|
<ClCompile Include="src\Scene\SHSceneManager.cpp" />
|
||||||
|
<ClCompile Include="src\Scripting\SHDotNetRuntime.cpp" />
|
||||||
|
<ClCompile Include="src\Scripting\SHScriptEngine.cpp" />
|
||||||
<ClCompile Include="src\Tools\SHException.cpp" />
|
<ClCompile Include="src\Tools\SHException.cpp" />
|
||||||
<ClCompile Include="src\Tools\SHExceptionHandler.cpp" />
|
<ClCompile Include="src\Tools\SHExceptionHandler.cpp" />
|
||||||
<ClCompile Include="src\Tools\SHLogger.cpp" />
|
<ClCompile Include="src\Tools\SHLogger.cpp" />
|
||||||
|
<ClCompile Include="src\Tools\SHStringUtils.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj">
|
<ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj">
|
||||||
|
|
|
@ -109,6 +109,9 @@
|
||||||
<Filter Include="Scene">
|
<Filter Include="Scene">
|
||||||
<UniqueIdentifier>{B3F7140E-1F0C-3DBF-E88D-E01E546139F0}</UniqueIdentifier>
|
<UniqueIdentifier>{B3F7140E-1F0C-3DBF-E88D-E01E546139F0}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Scripting">
|
||||||
|
<UniqueIdentifier>{985A7358-04C5-27CF-4D03-D974B9AC0524}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="Tools">
|
<Filter Include="Tools">
|
||||||
<UniqueIdentifier>{16CF2D0E-82E3-55BF-4B65-F91EB73852F0}</UniqueIdentifier>
|
<UniqueIdentifier>{16CF2D0E-82E3-55BF-4B65-F91EB73852F0}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -327,6 +330,9 @@
|
||||||
<ClInclude Include="src\Math\SHMathHelpers.h">
|
<ClInclude Include="src\Math\SHMathHelpers.h">
|
||||||
<Filter>Math</Filter>
|
<Filter>Math</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Math\SHMathHelpers.hpp">
|
||||||
|
<Filter>Math</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="src\Math\SHMatrix.h">
|
<ClInclude Include="src\Math\SHMatrix.h">
|
||||||
<Filter>Math</Filter>
|
<Filter>Math</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -348,12 +354,21 @@
|
||||||
<ClInclude Include="src\Resource\Handle.h">
|
<ClInclude Include="src\Resource\Handle.h">
|
||||||
<Filter>Resource</Filter>
|
<Filter>Resource</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Resource\Handle.hpp">
|
||||||
|
<Filter>Resource</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="src\Resource\ResourceLibrary.h">
|
<ClInclude Include="src\Resource\ResourceLibrary.h">
|
||||||
<Filter>Resource</Filter>
|
<Filter>Resource</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Resource\ResourceLibrary.hpp">
|
||||||
|
<Filter>Resource</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="src\Resource\SparseSet.h">
|
<ClInclude Include="src\Resource\SparseSet.h">
|
||||||
<Filter>Resource</Filter>
|
<Filter>Resource</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Resource\SparseSet.hpp">
|
||||||
|
<Filter>Resource</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="src\SHpch.h" />
|
<ClInclude Include="src\SHpch.h" />
|
||||||
<ClInclude Include="src\Scene\SHScene.h">
|
<ClInclude Include="src\Scene\SHScene.h">
|
||||||
<Filter>Scene</Filter>
|
<Filter>Scene</Filter>
|
||||||
|
@ -361,6 +376,15 @@
|
||||||
<ClInclude Include="src\Scene\SHSceneManager.h">
|
<ClInclude Include="src\Scene\SHSceneManager.h">
|
||||||
<Filter>Scene</Filter>
|
<Filter>Scene</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Scripting\SHDotNetRuntime.h">
|
||||||
|
<Filter>Scripting</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Scripting\SHDotNetRuntime.hpp">
|
||||||
|
<Filter>Scripting</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Scripting\SHScriptEngine.h">
|
||||||
|
<Filter>Scripting</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="src\Tools\SHException.h">
|
<ClInclude Include="src\Tools\SHException.h">
|
||||||
<Filter>Tools</Filter>
|
<Filter>Tools</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -373,6 +397,15 @@
|
||||||
<ClInclude Include="src\Tools\SHUtilities.h">
|
<ClInclude Include="src\Tools\SHUtilities.h">
|
||||||
<Filter>Tools</Filter>
|
<Filter>Tools</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Tools\SHUtilities.hpp">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Tools\SHStringUtils.h">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Tools\SHStringUtils.hpp">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp">
|
<ClCompile Include="src\Engine\ECS_Base\Components\SHComponent.cpp">
|
||||||
|
@ -559,6 +592,12 @@
|
||||||
<ClCompile Include="src\Scene\SHSceneManager.cpp">
|
<ClCompile Include="src\Scene\SHSceneManager.cpp">
|
||||||
<Filter>Scene</Filter>
|
<Filter>Scene</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Scripting\SHDotNetRuntime.cpp">
|
||||||
|
<Filter>Scripting</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Scripting\SHScriptEngine.cpp">
|
||||||
|
<Filter>Scripting</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="src\Tools\SHException.cpp">
|
<ClCompile Include="src\Tools\SHException.cpp">
|
||||||
<Filter>Tools</Filter>
|
<Filter>Tools</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -568,5 +607,8 @@
|
||||||
<ClCompile Include="src\Tools\SHLogger.cpp">
|
<ClCompile Include="src\Tools\SHLogger.cpp">
|
||||||
<Filter>Tools</Filter>
|
<Filter>Tools</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Tools\SHStringUtils.cpp">
|
||||||
|
<Filter>Tools</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -28,7 +28,7 @@ namespace SHADE
|
||||||
//SHEntityManager::RemoveEntity(this->entityID);
|
//SHEntityManager::RemoveEntity(this->entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityID SHEntity::GetEID() noexcept
|
EntityID SHEntity::GetEID() const noexcept
|
||||||
{
|
{
|
||||||
return this->entityID;
|
return this->entityID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ namespace SHADE
|
||||||
* \return uint32_t
|
* \return uint32_t
|
||||||
* The entityID of this Entity object.
|
* The entityID of this Entity object.
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
EntityID GetEID() noexcept;
|
EntityID GetEID() const noexcept;
|
||||||
|
|
||||||
/*!*************************************************************************
|
/*!*************************************************************************
|
||||||
* \brief Set the Active object
|
* \brief Set the Active object
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*************************************************************************************//*!
|
||||||
|
\file SHDotNetRuntime.cpp
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Oct 2, 2021
|
||||||
|
\brief Contains the definition of the SHDotNetRuntime class.
|
||||||
|
Implementation of code to set up code for SHDotNetRuntime is based on the
|
||||||
|
following repository:
|
||||||
|
https://github.com/mjrousos/SampleCoreCLRHost
|
||||||
|
|
||||||
|
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 Header
|
||||||
|
#include <SHpch.h>
|
||||||
|
// Primary Header
|
||||||
|
#include "SHDotNetRuntime.h"
|
||||||
|
// Standard Library
|
||||||
|
#include <array>
|
||||||
|
// External Dependencies
|
||||||
|
#include <shlwapi.h> // PathRemoveFileSpecA
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Constructors/Destructor */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
SHDotNetRuntime::SHDotNetRuntime(bool autoInit)
|
||||||
|
{
|
||||||
|
if (autoInit)
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SHDotNetRuntime::~SHDotNetRuntime()
|
||||||
|
{
|
||||||
|
if (IsLoaded())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Exit();
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& e)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR(e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Lifecycle Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
void SHDotNetRuntime::Init()
|
||||||
|
{
|
||||||
|
// State checking, in case there was an unload before, we must ensure that the state is valid
|
||||||
|
if (initialised)
|
||||||
|
throw std::runtime_error("[DotNetRuntime] Failed to initialise as it was already initialised or was deinitialised into an invalid state.");
|
||||||
|
|
||||||
|
// Get the current executable directory
|
||||||
|
std::string runtimePath(MAX_PATH, '\0');
|
||||||
|
GetModuleFileNameA(nullptr, runtimePath.data(), MAX_PATH);
|
||||||
|
PathRemoveFileSpecA(runtimePath.data());
|
||||||
|
// Since PathRemoveFileSpecA() removes from data(), the size is not updated, so we must manually update it
|
||||||
|
runtimePath.resize(std::strlen(runtimePath.data()));
|
||||||
|
|
||||||
|
// Do not need to load the library if it was previously loaded
|
||||||
|
if (coreClr == nullptr)
|
||||||
|
{
|
||||||
|
// Construct the CoreCLR path
|
||||||
|
std::string coreClrPath(runtimePath); // Works
|
||||||
|
coreClrPath += "\\coreclr.dll";
|
||||||
|
|
||||||
|
// Load the CoreCLR DLL
|
||||||
|
coreClr = LoadLibraryExA(coreClrPath.c_str(), nullptr, 0);
|
||||||
|
if (!coreClr)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[DotNetRuntime] Error #" << GetLastError() << " Failed to load CoreCLR from \"" << coreClrPath << "\"\n";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Get CoreCLR hosting functions
|
||||||
|
initializeCoreClr = getCoreClrFunctionPtr<coreclr_initialize_ptr>("coreclr_initialize");
|
||||||
|
createManagedDelegate = getCoreClrFunctionPtr<coreclr_create_delegate_ptr>("coreclr_create_delegate");
|
||||||
|
shutdownCoreClr = getCoreClrFunctionPtr<coreclr_shutdown_ptr>("coreclr_shutdown");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Construct AppDomain properties used when starting the runtime
|
||||||
|
// Construct the trusted platform assemblies (TPA) list
|
||||||
|
// This is the list of assemblies that .NET Core can load as
|
||||||
|
// trusted system assemblies (similar to the .NET Framework GAC).
|
||||||
|
// For this host (as with most), assemblies next to CoreCLR will
|
||||||
|
// be included in the TPA list
|
||||||
|
std::string tpaList = buildTpaList(runtimePath);
|
||||||
|
|
||||||
|
// Define CoreCLR properties
|
||||||
|
std::array propertyKeys =
|
||||||
|
{
|
||||||
|
"TRUSTED_PLATFORM_ASSEMBLIES", // Trusted assemblies (like the GAC)
|
||||||
|
"APP_PATHS", // Directories to probe for application assemblies
|
||||||
|
// "APP_NI_PATHS", // Directories to probe for application native images (not used in this sample)
|
||||||
|
// "NATIVE_DLL_SEARCH_DIRECTORIES", // Directories to probe for native dlls (not used in this sample)
|
||||||
|
};
|
||||||
|
std::array propertyValues =
|
||||||
|
{
|
||||||
|
tpaList.c_str(),
|
||||||
|
runtimePath.c_str()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 4: Start the CoreCLR runtime
|
||||||
|
int result = initializeCoreClr
|
||||||
|
(
|
||||||
|
runtimePath.c_str(), // AppDomain base path
|
||||||
|
"SHADEHost", // AppDomain friendly name
|
||||||
|
propertyKeys.size(), // Property count
|
||||||
|
propertyKeys.data(), // Property names
|
||||||
|
propertyValues.data(), // Property values
|
||||||
|
&hostHandle, // Host handle
|
||||||
|
&domainId // AppDomain ID
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if intiialization of CoreCLR failed
|
||||||
|
throwIfFailed("[DotNetRuntime] Failed to initialize CoreCLR.", result);
|
||||||
|
|
||||||
|
initialised = true;
|
||||||
|
SHLOG_INFO("[DotNetRuntime] Successfully loaded the .NET 5.0 Runtime.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHDotNetRuntime::Exit()
|
||||||
|
{
|
||||||
|
// State checking, in case there was an unload before, we must ensure that the state is valid
|
||||||
|
if (!initialised)
|
||||||
|
throw std::runtime_error("[DotNetRuntime] Failed to deinitialise as it was not initialised before.");
|
||||||
|
|
||||||
|
// Shutdown CoreCLR
|
||||||
|
int result = shutdownCoreClr(hostHandle, domainId);
|
||||||
|
throwIfFailed("[DotNetRuntime] Failed to shut down CoreCLR.", result);
|
||||||
|
|
||||||
|
// Unset pointers
|
||||||
|
hostHandle = nullptr;
|
||||||
|
domainId = 0;
|
||||||
|
initialised = false;
|
||||||
|
|
||||||
|
SHLOG_INFO("[DotNetRuntime] Successfully shut down the .NET 5.0 Runtime.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Helper Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
std::string SHDotNetRuntime::buildTpaList(const std::string& directory)
|
||||||
|
{
|
||||||
|
// Constants
|
||||||
|
static const std::string SEARCH_PATH = directory + "\\*.dll";
|
||||||
|
static constexpr char PATH_DELIMITER = ';';
|
||||||
|
|
||||||
|
// Create a osstream object to compile the string
|
||||||
|
std::ostringstream tpaList;
|
||||||
|
|
||||||
|
// Search the current directory for the TPAs (.DLLs)
|
||||||
|
WIN32_FIND_DATAA findData;
|
||||||
|
HANDLE fileHandle = FindFirstFileA(SEARCH_PATH.c_str(), &findData);
|
||||||
|
if (fileHandle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Append the assembly to the list
|
||||||
|
tpaList << directory << '\\' << findData.cFileName << PATH_DELIMITER;
|
||||||
|
|
||||||
|
// Note that the CLR does not guarantee which assembly will be loaded if an assembly
|
||||||
|
// is in the TPA list multiple times (perhaps from different paths or perhaps with different NI/NI.dll
|
||||||
|
// extensions. Therefore, a real host should probably add items to the list in priority order and only
|
||||||
|
// add a file if it's not already present on the list.
|
||||||
|
//
|
||||||
|
// For this simple sample, though, and because we're only loading TPA assemblies from a single path,
|
||||||
|
// and have no native images, we can ignore that complication.
|
||||||
|
}
|
||||||
|
while (FindNextFileA(fileHandle, &findData));
|
||||||
|
FindClose(fileHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tpaList.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHDotNetRuntime::throwIfFailed(const std::string& errMsg, int resultCode)
|
||||||
|
{
|
||||||
|
if (resultCode < 0)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::hex << std::setfill('0') << std::setw(8)
|
||||||
|
<< errMsg
|
||||||
|
<< " Error 0x" << resultCode << "\n";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*************************************************************************************//*!
|
||||||
|
\file SHDotNetRuntime.h
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Oct 2, 2021
|
||||||
|
\brief Contains the interface of a wrapper class for interfacing with the
|
||||||
|
.NET 5 Runtime.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// Standard Libraries
|
||||||
|
#include <iomanip> // std::setfill, std::setw
|
||||||
|
#include <stdexcept> // std::runtime_error
|
||||||
|
#include <string> // std::string
|
||||||
|
#include <sstream> // std::ostringstream
|
||||||
|
// External Dependencies
|
||||||
|
#include <Windows.h> // HMODULE
|
||||||
|
#include <coreclrhost.h> // coreclr_*
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/********************************************************************************//*!
|
||||||
|
@brief Class that encapsulates the state of the .NET Core Runtime lifecycle.
|
||||||
|
*//*********************************************************************************/
|
||||||
|
class SHDotNetRuntime
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
/* Constructors/Destructor */
|
||||||
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Default constructor that immediately initializes the CoreCLR.
|
||||||
|
|
||||||
|
@param[in] autoInit
|
||||||
|
If true, loads the CoreCLR by calling Init().
|
||||||
|
*//*****************************************************************************/
|
||||||
|
SHDotNetRuntime(bool autoInit = true);
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Destructor that unloads the CoreCLR if it has not been unloaded
|
||||||
|
yet.
|
||||||
|
*//*****************************************************************************/
|
||||||
|
~SHDotNetRuntime();
|
||||||
|
|
||||||
|
// Disallow copy and moving
|
||||||
|
SHDotNetRuntime(const SHDotNetRuntime&) = delete;
|
||||||
|
SHDotNetRuntime(SHDotNetRuntime&&) = delete;
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
/* Lifecycle Functions */
|
||||||
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Loads the CoreCLR and grabs pointers to bootstrapping functions and
|
||||||
|
kickstarts the CoreCLR.
|
||||||
|
|
||||||
|
@throws SystemExitException
|
||||||
|
Thrown if there is a failure in loading the CLR and related functions.
|
||||||
|
*//*****************************************************************************/
|
||||||
|
void Init();
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Unloads the CoreCLR.
|
||||||
|
|
||||||
|
@throws SystemExitException
|
||||||
|
Thrown if there is a failure in unloading the CLR.
|
||||||
|
*//*****************************************************************************/
|
||||||
|
void Exit();
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
/* Usage Functions */
|
||||||
|
/*----------------------------------------------------------------------------------*/
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Checks if the DotNetRuntime has successfully been initialised.
|
||||||
|
|
||||||
|
@return True if this DotNetRuntime has been initialised.
|
||||||
|
*//*****************************************************************************/
|
||||||
|
inline bool IsLoaded() { return coreClr != nullptr; }
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Retrieves a function pointer from the a CLR assembly based on the
|
||||||
|
specified assembly, type and function names.
|
||||||
|
|
||||||
|
@tparam FunctionType
|
||||||
|
Type of the function pointer that the specified function name will
|
||||||
|
provide.
|
||||||
|
|
||||||
|
@params[in] assemblyName
|
||||||
|
Name of the CoreCLR assembly that contains the function.
|
||||||
|
@params[in] typeName
|
||||||
|
Name of the CoreCLR type in the assembly that contains the function.
|
||||||
|
Nested types are separated by a period(.).
|
||||||
|
@params[in] functionName
|
||||||
|
Name of the CoreCLR function to get a pointer to.
|
||||||
|
|
||||||
|
@returns Pointer to the function in the assembly that was specified.
|
||||||
|
*//*****************************************************************************/
|
||||||
|
template<typename FunctionType>
|
||||||
|
FunctionType GetFunctionPtr(const std::string_view& assemblyName,
|
||||||
|
const std::string_view& typeName,
|
||||||
|
const std::string_view& functionName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
bool initialised = false;
|
||||||
|
// References to CoreCLR key components
|
||||||
|
HMODULE coreClr = nullptr;
|
||||||
|
void* hostHandle = nullptr;
|
||||||
|
unsigned int domainId = 0;
|
||||||
|
// Function Pointers to CoreCLR functions
|
||||||
|
coreclr_initialize_ptr initializeCoreClr = nullptr;
|
||||||
|
coreclr_create_delegate_ptr createManagedDelegate = nullptr;
|
||||||
|
coreclr_shutdown_ptr shutdownCoreClr = nullptr;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Helper Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Retrieves a function pointer from the CoreCLR based on the specified
|
||||||
|
function name.
|
||||||
|
|
||||||
|
@tparam FunctionType
|
||||||
|
Type of the function pointer that the specified function name will
|
||||||
|
provide.
|
||||||
|
|
||||||
|
@params[in] functionName
|
||||||
|
Name of the CoreCLR function to get a pointer to.
|
||||||
|
|
||||||
|
@returns Pointer to the function in the CoreCLR that was specified.
|
||||||
|
*//*****************************************************************************/
|
||||||
|
template<typename FunctionType>
|
||||||
|
FunctionType getCoreClrFunctionPtr(const std::string& functionName);
|
||||||
|
/****************************************************************************//*!
|
||||||
|
@brief Compiles a semicolon separated string of trusted platform assemblies by
|
||||||
|
searching the specified directory.
|
||||||
|
|
||||||
|
@params[in] directory
|
||||||
|
Path to the directory where the trusted platform assemblies reside.
|
||||||
|
|
||||||
|
@returns Semicolon separated string of trusted platform assemblies.
|
||||||
|
*//*****************************************************************************/
|
||||||
|
static std::string buildTpaList(const std::string& directory);
|
||||||
|
static void throwIfFailed(const std::string& errMsg, int resultCode);
|
||||||
|
};
|
||||||
|
} // namespace PlushieEngine::Scripts
|
||||||
|
|
||||||
|
#include "SHDotNetRuntime.hpp"
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*************************************************************************************//*!
|
||||||
|
\file SHDotNetRuntime.hpp
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Oct 2, 2021
|
||||||
|
\brief Contains the implementation of the template functions of the
|
||||||
|
DotNetRuntime class.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// Primary Include
|
||||||
|
#include "SHDotNetRuntime.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
template<typename FunctionType>
|
||||||
|
FunctionType SHDotNetRuntime::GetFunctionPtr(const std::string_view & assemblyName,
|
||||||
|
const std::string_view & typeName,
|
||||||
|
const std::string_view & functionName)
|
||||||
|
{
|
||||||
|
FunctionType managedDelegate = nullptr;
|
||||||
|
int result = createManagedDelegate
|
||||||
|
(
|
||||||
|
hostHandle,
|
||||||
|
domainId,
|
||||||
|
assemblyName.data(),
|
||||||
|
typeName.data(),
|
||||||
|
functionName.data(),
|
||||||
|
reinterpret_cast<void**>(&managedDelegate)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if it failed
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::hex << std::setfill('0') << std::setw(8)
|
||||||
|
<< "[DotNetRuntime] Failed to get pointer to function \""
|
||||||
|
<< typeName << "." << functionName << "\" in assembly (" << assemblyName << "). "
|
||||||
|
<< "Error 0x" << result << "\n";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return managedDelegate;
|
||||||
|
}
|
||||||
|
template<typename FunctionType>
|
||||||
|
FunctionType SHDotNetRuntime::getCoreClrFunctionPtr(const std::string& functionName)
|
||||||
|
{
|
||||||
|
FunctionType fPtr = reinterpret_cast<FunctionType>(GetProcAddress(coreClr, functionName.c_str()));
|
||||||
|
if (!fPtr)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[DotNetRuntime] Unable to get pointer to function: \"" << functionName << "\"";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
return fPtr;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,509 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file SHScriptEngine.cpp
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Sep 17, 2021
|
||||||
|
\brief Contains the implementation for ScriptEngine class.
|
||||||
|
|
||||||
|
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 "SHScriptEngine.h"
|
||||||
|
// Standard Library
|
||||||
|
#include <fstream> // std::fstream
|
||||||
|
#include <filesystem> // std::filesystem::canonical, std::filesystem::remove
|
||||||
|
// Project Headers
|
||||||
|
#include "Tools/SHLogger.h"
|
||||||
|
#include "Tools/SHStringUtils.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*--------------------------------------------------------------------------------*/
|
||||||
|
/* Static Definitions */
|
||||||
|
/*--------------------------------------------------------------------------------*/
|
||||||
|
const std::string SHScriptEngine::DEFAULT_CSHARP_NAMESPACE = std::string(DEFAULT_CSHARP_LIB_NAME);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Constructors/Destructors */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
SHScriptEngine::SHScriptEngine()
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Lifecycle Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
void SHScriptEngine::Init()
|
||||||
|
{
|
||||||
|
// Do not allow initialization if already initialised
|
||||||
|
if (dotNet.IsLoaded())
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("[ScriptEngine] Attempted to initialise an already loaded DotNetRuntime.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dotNet.Init();
|
||||||
|
|
||||||
|
// Load all the helpers
|
||||||
|
loadFunctions();
|
||||||
|
|
||||||
|
// Generate script assembly if it hasn't been before
|
||||||
|
if (!fileExists(std::string(MANAGED_SCRIPT_LIB_NAME) + ".dll"))
|
||||||
|
{
|
||||||
|
BuildScriptAssembly();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the CSharp Engine
|
||||||
|
csEngineInit();
|
||||||
|
|
||||||
|
// Link events
|
||||||
|
// - Entity Creation
|
||||||
|
/*onEntityCreate = [this](const SHEntity& e)
|
||||||
|
{
|
||||||
|
csGOLibNotifyNewEntity(e.GetEID());
|
||||||
|
};
|
||||||
|
ECS::OnEntityCreated += onEntityCreate;*/
|
||||||
|
// - Entity Destruction
|
||||||
|
/*onEntityDestroy = [this](const SHEntity& e)
|
||||||
|
{
|
||||||
|
csScriptsRemoveAll(e.GetEID());
|
||||||
|
csGOLibNotifyDestroyEntity(e.GetEID());
|
||||||
|
};
|
||||||
|
ECS::OnEntityDestroy += onEntityDestroy;*/
|
||||||
|
}
|
||||||
|
void SHScriptEngine::UnloadScriptAssembly()
|
||||||
|
{
|
||||||
|
csEngineUnloadScripts();
|
||||||
|
}
|
||||||
|
void SHScriptEngine::LoadScriptAssembly()
|
||||||
|
{
|
||||||
|
csEngineLoadScripts();
|
||||||
|
}
|
||||||
|
void SHScriptEngine::ReloadScriptAssembly()
|
||||||
|
{
|
||||||
|
csEngineReloadScripts();
|
||||||
|
}
|
||||||
|
void SHScriptEngine::ExecuteFixedUpdates()
|
||||||
|
{
|
||||||
|
csScriptsExecuteFixedUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHScriptEngine::ExecuteOnTrigger()
|
||||||
|
{
|
||||||
|
csScriptsExecuteOnTrigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHScriptEngine::Exit()
|
||||||
|
{
|
||||||
|
// Do not allow deinitialization if not initialised
|
||||||
|
if (!dotNet.IsLoaded())
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("[ScriptEngine] Attempted to clean up an unloaded DotNetRuntime.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlink events
|
||||||
|
/*ECS::OnEntityCreated -= onEntityCreate;
|
||||||
|
ECS::OnEntityDestroy -= onEntityDestroy;*/
|
||||||
|
|
||||||
|
// Clean up the CSharp Engine
|
||||||
|
csEngineExit();
|
||||||
|
|
||||||
|
// Shut down the CLR
|
||||||
|
dotNet.Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Script Manipulation Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
bool SHScriptEngine::AddScript(const SHEntity& entity, const std::string_view& scriptName) const
|
||||||
|
{
|
||||||
|
return csScriptsAdd(entity.GetEID(), scriptName.data());
|
||||||
|
}
|
||||||
|
void SHScriptEngine::RemoveAllScripts(const SHEntity& entity) const
|
||||||
|
{
|
||||||
|
csScriptsRemoveAll(entity.GetEID());
|
||||||
|
}
|
||||||
|
void SHScriptEngine::RemoveAllScriptsImmediately(const SHEntity& entity, bool callOnDestroy) const
|
||||||
|
{
|
||||||
|
csScriptsRemoveAllImmediately(entity.GetEID(), callOnDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Script Serialisation Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
std::string SHScriptEngine::SerialiseScripts(const SHEntity& entity) const
|
||||||
|
{
|
||||||
|
// Create buffer needed to store serialised script data
|
||||||
|
constexpr int BUFFER_SIZE = 10240;
|
||||||
|
std::unique_ptr<char> buffer { new char[BUFFER_SIZE] };
|
||||||
|
std::memset(buffer.get(), 0, BUFFER_SIZE);
|
||||||
|
|
||||||
|
// Attempt to serialise the script
|
||||||
|
std::string result;
|
||||||
|
if (csScriptsSerialise(entity.GetEID(), buffer.get(), BUFFER_SIZE))
|
||||||
|
{
|
||||||
|
result = std::string(buffer.get());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return an empty string since we failed to serialise
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Script Serialisation Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
void SHScriptEngine::DeserialiseScript(const SHEntity& entity, const std::string& yaml) const
|
||||||
|
{
|
||||||
|
csScriptDeserialise(entity.GetEID(), yaml.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Script Editor Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
void SHScriptEngine::RenderScriptsInInspector(const SHEntity& entity) const
|
||||||
|
{
|
||||||
|
csEditorRenderScripts(entity.GetEID());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Static Utility Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
bool SHScriptEngine::BuildScriptAssembly(bool debug)
|
||||||
|
{
|
||||||
|
constexpr std::string_view BUILD_LOG_PATH = "../Build.log";
|
||||||
|
|
||||||
|
// Prepare directory (delete useless files)
|
||||||
|
deleteFolder("net5.0");
|
||||||
|
deleteFolder("ref");
|
||||||
|
deleteFolder("../PlushieGameManaged");
|
||||||
|
deleteFolder("../obj");
|
||||||
|
|
||||||
|
// Attempt to build the assembly
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[ScriptEngine] Building " << (debug ? " debug " : "") << "Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
|
||||||
|
SHLOG_INFO(oss.str());
|
||||||
|
oss.str("");
|
||||||
|
const bool BUILD_SUCCESS = execProcess
|
||||||
|
(
|
||||||
|
L"C:\\Windows\\system32\\cmd.exe",
|
||||||
|
L"/K \"dotnet build \"../PlushieGameManaged.csproj\" -c Debug -o \"./tmp/\" -fl -flp:LogFile=build.log;Verbosity=quiet & exit\""
|
||||||
|
) == 0;
|
||||||
|
if (BUILD_SUCCESS)
|
||||||
|
{
|
||||||
|
// Copy to built dll to the working directory and replace
|
||||||
|
std::filesystem::copy_file("./tmp/PlushieGameManaged.dll", "PlushieGameManaged.dll", std::filesystem::copy_options::overwrite_existing);
|
||||||
|
|
||||||
|
oss << "[ScriptEngine] Successfully built Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
|
||||||
|
SHLOG_INFO(oss.str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oss << "[ScriptEngine] Failed to build Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
|
||||||
|
SHLOG_ERROR(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up built files
|
||||||
|
deleteFolder("./tmp");
|
||||||
|
|
||||||
|
// Read the build log and output to the console
|
||||||
|
dumpBuildLog(BUILD_LOG_PATH);
|
||||||
|
// Delete the build log file since we no longer need it
|
||||||
|
deleteFile(BUILD_LOG_PATH);
|
||||||
|
|
||||||
|
return BUILD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHScriptEngine::GenerateScriptsCsProjFile(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
// Sample
|
||||||
|
static std::string_view FILE_CONTENTS =
|
||||||
|
"<Project Sdk=\"Microsoft.NET.Sdk\">\n\
|
||||||
|
<PropertyGroup>\n\
|
||||||
|
<TargetFramework>net5.0</TargetFramework>\n\
|
||||||
|
<Platforms>x64</Platforms>\n\
|
||||||
|
<Configurations>Release;Debug</Configurations>\n\
|
||||||
|
</PropertyGroup>\n\
|
||||||
|
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n\
|
||||||
|
<OutputPath>.\\bin_Release-x64</OutputPath>\n\
|
||||||
|
<PlatformTarget>x64</PlatformTarget>\n\
|
||||||
|
</PropertyGroup>\n\
|
||||||
|
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\"> \n\
|
||||||
|
<OutputPath>.\\bin_Debug-x64</OutputPath>\n\
|
||||||
|
<PlatformTarget>x64</PlatformTarget>\n\
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>\n\
|
||||||
|
<Optimize>false</Optimize>\n\
|
||||||
|
<DebugType>full</DebugType>\n\
|
||||||
|
<DebugSymbols>true</DebugSymbols>\n\
|
||||||
|
</PropertyGroup>\n\
|
||||||
|
<ItemGroup>\n\
|
||||||
|
<Compile Remove=\"bin\**\" />\n\
|
||||||
|
<EmbeddedResource Remove=\"Assets\**\" />\n\
|
||||||
|
<EmbeddedResource Remove=\"bin\**\" />\n\
|
||||||
|
<None Remove=\"bin\**\" />\n\
|
||||||
|
</ItemGroup>\n\
|
||||||
|
<ItemGroup>\n\
|
||||||
|
<None Remove=\".gitignore\" />\n\
|
||||||
|
<None Remove=\".gitmodules\" />\n\
|
||||||
|
</ItemGroup>\n\
|
||||||
|
<ItemGroup>\n\
|
||||||
|
<Reference Include=\"PlushieAPI\">\n\
|
||||||
|
<HintPath>.\\bin\\PlushieAPI.dll</HintPath>\n\
|
||||||
|
</Reference>\n\
|
||||||
|
</ItemGroup>\n\
|
||||||
|
</Project>";
|
||||||
|
|
||||||
|
// Attempt to create the file
|
||||||
|
std::ofstream file(path);
|
||||||
|
if (!file.is_open())
|
||||||
|
throw std::runtime_error("Unable to create CsProj file!");
|
||||||
|
|
||||||
|
// Fill the file
|
||||||
|
file << FILE_CONTENTS;
|
||||||
|
|
||||||
|
// Close
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Helper Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
void SHScriptEngine::loadFunctions()
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[ScriptEngine] Loading \"" << DEFAULT_CSHARP_LIB_NAME << "\" CLR library.";
|
||||||
|
SHLOG_INFO(oss.str());
|
||||||
|
|
||||||
|
// Load functions
|
||||||
|
csEngineInit = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
|
||||||
|
"Init"
|
||||||
|
);
|
||||||
|
csEngineLoadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
|
||||||
|
"LoadScriptAssembly"
|
||||||
|
);
|
||||||
|
csEngineUnloadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
|
||||||
|
"UnloadScriptAssembly"
|
||||||
|
);
|
||||||
|
csEngineReloadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
|
||||||
|
"ReloadScriptAssembly"
|
||||||
|
);
|
||||||
|
csEngineExit = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
|
||||||
|
"Exit"
|
||||||
|
);
|
||||||
|
csScriptsFrameSetUp = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"FrameSetUp"
|
||||||
|
);
|
||||||
|
csScriptsExecuteOnTrigger = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"ExecuteOnTrigger"
|
||||||
|
);
|
||||||
|
csScriptsExecuteFixedUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"ExecuteFixedUpdate"
|
||||||
|
);
|
||||||
|
csScriptsExecuteUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"ExecuteUpdate"
|
||||||
|
);
|
||||||
|
csScriptsExecuteLateUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"ExecuteLateUpdate"
|
||||||
|
);
|
||||||
|
csScriptsFrameCleanUp = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"FrameCleanUp"
|
||||||
|
);
|
||||||
|
csScriptsAdd = dotNet.GetFunctionPtr<CsScriptManipFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"AddScriptViaName"
|
||||||
|
);
|
||||||
|
csScriptsRemoveAll = dotNet.GetFunctionPtr<CsScriptBasicFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"RemoveAllScripts"
|
||||||
|
);
|
||||||
|
csScriptsRemoveAllImmediately = dotNet.GetFunctionPtr<CsScriptOptionalFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"RemoveAllScriptsImmediately"
|
||||||
|
);
|
||||||
|
csScriptsSerialise = dotNet.GetFunctionPtr<CsScriptSerialiseFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"SerialiseScripts"
|
||||||
|
);
|
||||||
|
csScriptsSerialiseJson = dotNet.GetFunctionPtr<CsScriptSerialiseJsonFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"SerialiseScriptsJson"
|
||||||
|
);
|
||||||
|
csScriptDeserialise = dotNet.GetFunctionPtr<CsScriptDeserialiseFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
|
||||||
|
"DeserialiseScript"
|
||||||
|
);
|
||||||
|
csGOLibNotifyNewEntity = dotNet.GetFunctionPtr<CsScriptBasicFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".GameObjectLibrary",
|
||||||
|
"NotifyNewGameObject"
|
||||||
|
);
|
||||||
|
csGOLibNotifyDestroyEntity = dotNet.GetFunctionPtr<CsScriptBasicFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".GameObjectLibrary",
|
||||||
|
"NotifyDestroyGameObject"
|
||||||
|
);
|
||||||
|
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
|
||||||
|
(
|
||||||
|
DEFAULT_CSHARP_LIB_NAME,
|
||||||
|
DEFAULT_CSHARP_NAMESPACE + ".Editor",
|
||||||
|
"RenderScriptsInInspector"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)
|
||||||
|
{
|
||||||
|
std::ifstream buildLog(buildLogPath);
|
||||||
|
|
||||||
|
// Fail to open
|
||||||
|
if (!buildLog.is_open())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Process line by line
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(buildLog, line))
|
||||||
|
{
|
||||||
|
if (line.find("error") != line.npos)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR(line);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_WARNING(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SHScriptEngine::deleteFile(const std::string_view& filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::filesystem::remove(std::filesystem::canonical(filePath));
|
||||||
|
}
|
||||||
|
catch (...) {} // Ignore deletion failures
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHScriptEngine::deleteFolder(const std::string_view& filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::filesystem::remove_all(std::filesystem::canonical(filePath));
|
||||||
|
}
|
||||||
|
catch (...) {} // Ignore deletion failures
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHScriptEngine::fileExists(const std::string_view& filePath)
|
||||||
|
{
|
||||||
|
std::error_code error;
|
||||||
|
if (std::filesystem::exists(filePath, error))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD SHScriptEngine::execProcess(const std::wstring& path, const std::wstring& args)
|
||||||
|
{
|
||||||
|
STARTUPINFOW startInfo;
|
||||||
|
PROCESS_INFORMATION procInfo;
|
||||||
|
ZeroMemory(&startInfo, sizeof(startInfo));
|
||||||
|
ZeroMemory(&procInfo, sizeof(procInfo));
|
||||||
|
startInfo.cb = sizeof(startInfo);
|
||||||
|
|
||||||
|
std::wstring argsWstr = args;
|
||||||
|
|
||||||
|
// Start Process
|
||||||
|
const auto SUCCESS = CreateProcess
|
||||||
|
(
|
||||||
|
path.data(), argsWstr.data(),
|
||||||
|
nullptr, nullptr, false, NULL, nullptr, nullptr,
|
||||||
|
&startInfo, &procInfo
|
||||||
|
);
|
||||||
|
|
||||||
|
// Error Check
|
||||||
|
if (!SUCCESS)
|
||||||
|
{
|
||||||
|
auto err = GetLastError();
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[ScriptEngine] Failed to launch process. Error code: " << std::hex << err
|
||||||
|
<< " (" << SHStringUtils::GetWin32ErrorMessage(err) << ")";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for execution to end
|
||||||
|
DWORD status;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const auto SUCCESS = GetExitCodeProcess(procInfo.hProcess, &status);
|
||||||
|
if (!SUCCESS)
|
||||||
|
{
|
||||||
|
auto err = GetLastError();
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[ScriptEngine] Failed to query process. Error code: " << std::hex << err
|
||||||
|
<< " (" << SHStringUtils::GetWin32ErrorMessage(err) << ")";
|
||||||
|
throw std::runtime_error(oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break only if process ends
|
||||||
|
if (status != STILL_ACTIVE)
|
||||||
|
{
|
||||||
|
CloseHandle(procInfo.hProcess);
|
||||||
|
CloseHandle(procInfo.hThread);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,258 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file ScriptEngine.h
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Sep 17, 2021
|
||||||
|
\brief Contains the interface for ScriptEngine class.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// STL Includes
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
// Project Headers
|
||||||
|
#include "SHDotNetRuntime.h"
|
||||||
|
#include "Engine/ECS_Base/SHECSMacros.h"
|
||||||
|
#include "Engine/ECS_Base/Entity/SHEntity.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages initialisation of the DotNetRuntime and interfacing with CLR code written
|
||||||
|
/// and executed on .NET.
|
||||||
|
/// </summary>
|
||||||
|
class SHScriptEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constructors & Destructors */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Default Constructor
|
||||||
|
/// </summary>
|
||||||
|
SHScriptEngine();
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Lifecycle Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises the DotNetRuntime and retrieves function pointers to all
|
||||||
|
/// functions on the CLR used to interface with the engine.
|
||||||
|
/// </summary>
|
||||||
|
void Init();
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the managed script assembly. Ensure this is only called after
|
||||||
|
/// UnloadScriptAssembly() has been called.
|
||||||
|
/// </summary>
|
||||||
|
void UnloadScriptAssembly();
|
||||||
|
/// <summary>
|
||||||
|
/// Unloads the managed script assembly.
|
||||||
|
/// Take note that this will clear all existing scripts, ensure that the scene
|
||||||
|
/// is saved before doing so.
|
||||||
|
/// </summary>
|
||||||
|
void LoadScriptAssembly();
|
||||||
|
/// <summary>
|
||||||
|
/// Reloads the managed script assembly.
|
||||||
|
/// Take note that this will clear all existing scripts, ensure that the scene
|
||||||
|
/// is saved before doing so.
|
||||||
|
/// </summary>
|
||||||
|
void ReloadScriptAssembly();
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the FixedUpdate()s of the PlushieScripts that are attached to
|
||||||
|
/// Entities.
|
||||||
|
/// </summary>
|
||||||
|
void ExecuteFixedUpdates();
|
||||||
|
/// <summary>
|
||||||
|
/// Executes the OnTrigger() family of functions of the PlushieScripts that are
|
||||||
|
/// attached to Entities.
|
||||||
|
/// </summary>
|
||||||
|
void ExecuteOnTrigger();
|
||||||
|
/// <summary>
|
||||||
|
/// Shuts down the DotNetRuntime.
|
||||||
|
/// </summary>
|
||||||
|
void Exit();
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Script Manipulation Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a Script to a specified Entity. Note that while you can call this
|
||||||
|
/// multiple times on a specified Entity, it will work for all intents and
|
||||||
|
/// purposes but GetScript<T>() (C# only) currently only
|
||||||
|
/// gives you the first PlushieScript added of the specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The entity to add a script to.</param>
|
||||||
|
/// <param name="scriptName">Type name of the script to add.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// True if successfully added. False otherwise with the error logged to the
|
||||||
|
/// console.
|
||||||
|
/// </returns>
|
||||||
|
bool AddScript(const SHEntity& entity, const std::string_view& scriptName) const;
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all Scripts attached to the specified Entity. Does not do anything
|
||||||
|
/// if the specified Entity is invalid or does not have any PlushieScripts
|
||||||
|
/// attached.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The entity to remove the scripts from.</param>
|
||||||
|
void RemoveAllScripts(const SHEntity& entity) const;
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all Scripts attached to the specified Entity. Unlike
|
||||||
|
/// RemoveAllScripts(), this removes all the scripts immediately.
|
||||||
|
/// Does not do anything if the specified Entity is invalid or does not have any
|
||||||
|
/// PlushieScripts attached.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The entity to remove the scripts from.</param>
|
||||||
|
/// <param name="callOnDestroy">
|
||||||
|
/// Whether or not to call OnDestroy on the scripts. This is ignored if not in
|
||||||
|
/// play mode.
|
||||||
|
/// </param>
|
||||||
|
void RemoveAllScriptsImmediately(const SHEntity& entity, bool callOnDestroy) const;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Script Serialisation Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a JSON string that represents the set of Scripts attached to the
|
||||||
|
/// specified Entity.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity"> The Entity to Serialise.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// String that represents the set of scripts attached to the specified Entity.
|
||||||
|
/// </returns>
|
||||||
|
std::string SerialiseScripts(const SHEntity& entity) const;
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the specified JSON string and creates a Script for the specified Entity
|
||||||
|
/// based on the specified JSON string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The Entity to deserialise a Script on to.</param>
|
||||||
|
/// <param name="yaml">
|
||||||
|
/// The JSON string that represents the Script to load into the Entity.
|
||||||
|
/// </param>
|
||||||
|
void DeserialiseScript(const SHEntity& entity, const std::string& yaml) const;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Script Editor Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Renders the set of attached PlushieScripts for the specified Entity into the
|
||||||
|
/// inspector.
|
||||||
|
/// <br/>
|
||||||
|
/// This function is meant for consumption from native code in the inspector
|
||||||
|
/// rendering code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entity">The Entity to render the PlushieScripts of.</param>
|
||||||
|
void RenderScriptsInInspector(const SHEntity& entity) const;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Static Utility Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Utilises execution of a external batch file for invoking the dotnet build
|
||||||
|
/// tool to compile C# scripts in the Assets folder into the PlushieGameManaged
|
||||||
|
/// C# assembly DLL.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="debug">
|
||||||
|
/// Whether or not a debug build will be built. Only debug built C# assemblies
|
||||||
|
/// can be debugged.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>Whether or not the build succeeded.</returns>
|
||||||
|
static bool BuildScriptAssembly(bool debug = false);
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a .csproj file for editing and compiling the C# scripts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">File path to the generated file.</param>
|
||||||
|
static void GenerateScriptsCsProjFile(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
using CsFuncPtr = void(*)(void);
|
||||||
|
using CsScriptManipFuncPtr = bool(*)(EntityID, const char*);
|
||||||
|
using CsScriptBasicFuncPtr = void(*)(EntityID);
|
||||||
|
using CsScriptOptionalFuncPtr = void(*)(EntityID, bool);
|
||||||
|
using CsScriptSerialiseFuncPtr = bool(*)(EntityID, char*, int);
|
||||||
|
using CsScriptDeserialiseFuncPtr = bool(*)(EntityID, const char*);
|
||||||
|
using CsScriptSerialiseJsonFuncPtr = bool(*)(EntityID, void*);
|
||||||
|
using CsScriptEditorFuncPtr = void(*)(EntityID);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Constants */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
static constexpr std::string_view DEFAULT_CSHARP_LIB_NAME = "SHADEAPI";
|
||||||
|
static constexpr std::string_view MANAGED_SCRIPT_LIB_NAME = "SHADEManaged";
|
||||||
|
static const std::string DEFAULT_CSHARP_NAMESPACE;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
SHDotNetRuntime dotNet {false};
|
||||||
|
// Function Pointers to CLR Code
|
||||||
|
// - Engine Init
|
||||||
|
CsFuncPtr csEngineInit = nullptr;
|
||||||
|
CsFuncPtr csEngineLoadScripts = nullptr;
|
||||||
|
CsFuncPtr csEngineUnloadScripts = nullptr;
|
||||||
|
CsFuncPtr csEngineReloadScripts = nullptr;
|
||||||
|
CsFuncPtr csEngineExit = nullptr;
|
||||||
|
// - Scripts Store
|
||||||
|
CsFuncPtr csScriptsFrameSetUp = nullptr;
|
||||||
|
CsFuncPtr csScriptsExecuteOnTrigger = nullptr;
|
||||||
|
CsFuncPtr csScriptsExecuteFixedUpdate = nullptr;
|
||||||
|
CsFuncPtr csScriptsExecuteUpdate = nullptr;
|
||||||
|
CsFuncPtr csScriptsExecuteLateUpdate = nullptr;
|
||||||
|
CsFuncPtr csScriptsFrameCleanUp = nullptr;
|
||||||
|
CsScriptManipFuncPtr csScriptsAdd = nullptr;
|
||||||
|
CsScriptBasicFuncPtr csScriptsRemoveAll = nullptr;
|
||||||
|
CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr;
|
||||||
|
CsScriptSerialiseFuncPtr csScriptsSerialise = nullptr;
|
||||||
|
CsScriptDeserialiseFuncPtr csScriptDeserialise = nullptr;
|
||||||
|
CsScriptSerialiseJsonFuncPtr csScriptsSerialiseJson = nullptr;
|
||||||
|
CsScriptSerialiseJsonFuncPtr csScriptDeserialiseJson = nullptr;
|
||||||
|
// - GameObject Library
|
||||||
|
CsScriptBasicFuncPtr csGOLibNotifyNewEntity = nullptr;
|
||||||
|
CsScriptBasicFuncPtr csGOLibNotifyDestroyEntity = nullptr;
|
||||||
|
// - Editor
|
||||||
|
CsScriptEditorFuncPtr csEditorRenderScripts = nullptr;
|
||||||
|
// Delegates
|
||||||
|
/*ECS::EntityEvent::Delegate onEntityCreate;
|
||||||
|
ECS::EntityEvent::Delegate onEntityDestroy;*/
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Helper Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/// <summary>
|
||||||
|
/// Loads all the function pointers to CLR code that we need to execute.
|
||||||
|
/// </summary>
|
||||||
|
void loadFunctions();
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the file via the specified path that represents a build log of error
|
||||||
|
/// and warning messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buildLogPath">
|
||||||
|
/// File path to the build log of script builds done by BuildScriptAssembly() to
|
||||||
|
/// dump and process.
|
||||||
|
/// </param>
|
||||||
|
static void dumpBuildLog(const std::string_view& buildLogPath);
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the file as specified by the file path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">File path to the file to delete.</param>
|
||||||
|
static void deleteFile(const std::string_view& filePath);
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the folder and all files in it as specified by the file path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">File path to the file to delete.</param>
|
||||||
|
static void deleteFolder(const std::string_view& filePath);
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a specified file exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">File path to the file to check.</param>
|
||||||
|
/// <returns> True if the file exists </returns>
|
||||||
|
static bool fileExists(const std::string_view& filePath);
|
||||||
|
static DWORD execProcess(const std::wstring& path, const std::wstring& args);
|
||||||
|
};
|
||||||
|
} // namespace PlushieEngine
|
|
@ -0,0 +1,52 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file StringUtilities.cpp
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Nov 29, 2021
|
||||||
|
\brief Contains the definition of functions for working with strings.
|
||||||
|
|
||||||
|
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 Header
|
||||||
|
#include <SHpch.h>
|
||||||
|
// Primary Header
|
||||||
|
#include "SHStringUtils.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Utility Functions */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
std::vector<std::string> SHStringUtils::Split(const std::string& str, const char& delim)
|
||||||
|
{
|
||||||
|
return Split<char>(str, delim);
|
||||||
|
}
|
||||||
|
std::vector<std::wstring> SHStringUtils::Split(const std::wstring& str, const wchar_t& delim)
|
||||||
|
{
|
||||||
|
return Split<wchar_t>(str, delim);
|
||||||
|
}
|
||||||
|
std::string SHStringUtils::WstrToStr(const std::wstring& wstr)
|
||||||
|
{
|
||||||
|
static std::vector<char> buffer;
|
||||||
|
const int STR_SIZE = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.size()), nullptr, 0, nullptr, nullptr) + 1 /* Null Terminator */;
|
||||||
|
buffer.resize(STR_SIZE);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.size()), buffer.data(), MAX_PATH, nullptr, nullptr);
|
||||||
|
return std::string(buffer.data());
|
||||||
|
}
|
||||||
|
std::wstring SHStringUtils::StrToWstr(const std::string& str)
|
||||||
|
{
|
||||||
|
static std::vector<wchar_t> buffer;
|
||||||
|
const int WSTR_SIZE = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), nullptr, 0) + 1 /* Null Terminator */;
|
||||||
|
buffer.resize(WSTR_SIZE);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), buffer.data(), WSTR_SIZE);
|
||||||
|
return std::wstring(buffer.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SHStringUtils::GetWin32ErrorMessage(unsigned long errorCode)
|
||||||
|
{
|
||||||
|
return std::system_category().message(errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PlushieEngine
|
|
@ -0,0 +1,81 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file StringUtilities.h
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Nov 29, 2021
|
||||||
|
\brief Contains the declaration of functions for working with files and folders.
|
||||||
|
|
||||||
|
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
|
||||||
|
// Standard Libraries
|
||||||
|
#include <string> // std::basic_string
|
||||||
|
#include <vector> // std::vector
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains useful functions for operating on strings.
|
||||||
|
/// </summary>
|
||||||
|
class SHStringUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
/* Utility Functions */
|
||||||
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Splits a string separated by a specified delimiter into a vector of strings.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Internal type of each element in the string.</typeparam>
|
||||||
|
/// <param name="str">Read only reference to the string to split.</param>
|
||||||
|
/// <param name="delim">Read only reference to the delimiter.</param>
|
||||||
|
/// <returns>Vector of strings that have been split.</returns>
|
||||||
|
template<typename T>
|
||||||
|
static std::vector<std::basic_string<T>> Split(const std::basic_string<T>& str, const T& delim);
|
||||||
|
/// <summary>
|
||||||
|
/// Splits a string separated by a specified delimiter into a vector of strings.
|
||||||
|
/// Overload of Split<T>() to allow for string literals to be accepted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">Read only reference to the string to split.</param>
|
||||||
|
/// <param name="delim">Read only reference to the delimiter.</param>
|
||||||
|
/// <returns>Vector of strings that have been split.</returns>
|
||||||
|
static std::vector<std::string> Split(const std::string& str, const char& delim);
|
||||||
|
/// <summary>
|
||||||
|
/// Splits a string separated by a specified delimiter into a vector of strings.
|
||||||
|
/// Overload of Split<T>() to allow for wide string literals to be accepted.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">Read only reference to the string to split.</param>
|
||||||
|
/// <param name="delim">Read only reference to the delimiter.</param>
|
||||||
|
/// <returns>Vector of strings that have been split.</returns>
|
||||||
|
static std::vector<std::wstring> Split(const std::wstring& str, const wchar_t& delim);
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a wstring to a string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="wstr">wstring to convert.</param>
|
||||||
|
/// <returns>The converted wstring in string form.</returns>
|
||||||
|
static std::string WstrToStr(const std::wstring& wstr);
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a string to a wstring.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">string to convert.</param>
|
||||||
|
/// <returns>The converted string in wstring form.</returns>
|
||||||
|
static std::wstring StrToWstr(const std::string& str);
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the error message associated with a Win32 error code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="errorCode">Win32 error code to decode.</param>
|
||||||
|
/// <returns>String that represents the Win32 error.</returns>
|
||||||
|
static std::string GetWin32ErrorMessage(unsigned long errorCode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*-------------------------------------------------------------------------------*/
|
||||||
|
/* Constructors/Destructors */
|
||||||
|
/*-------------------------------------------------------------------------------*/
|
||||||
|
SHStringUtils() = delete;
|
||||||
|
};
|
||||||
|
} // namespace PlushieEngine
|
||||||
|
|
||||||
|
#include "SHStringUtils.hpp"
|
|
@ -0,0 +1,46 @@
|
||||||
|
/************************************************************************************//*!
|
||||||
|
\file StringUtilities.hpp
|
||||||
|
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||||
|
\par email: kahwei.tng\@digipen.edu
|
||||||
|
\date Nov 29, 2021
|
||||||
|
\brief Contains the implementation of template functions for working with files
|
||||||
|
and folders.
|
||||||
|
|
||||||
|
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
|
||||||
|
// Primary Header
|
||||||
|
#include "SHStringUtils.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*-------------------------------------------------------------------------------*/
|
||||||
|
/* Template Function Definitions */
|
||||||
|
/*-------------------------------------------------------------------------------*/
|
||||||
|
template<typename T>
|
||||||
|
inline std::vector<std::basic_string<T>> SHStringUtils::Split(const std::basic_string<T>& str, const T& delim)
|
||||||
|
{
|
||||||
|
std::vector<std::basic_string<T>> results;
|
||||||
|
std::basic_string<T> remaining = str;
|
||||||
|
|
||||||
|
// Go through looking for delimiters
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const size_t DELIM_POS = remaining.find_first_of(delim);
|
||||||
|
results.emplace_back(remaining.substr(0, DELIM_POS));
|
||||||
|
|
||||||
|
// Check if we hit the end of the string
|
||||||
|
if (DELIM_POS == remaining.npos)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, cut the remainder
|
||||||
|
remaining = remaining.substr(DELIM_POS + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
} // namespace PlushieEngine
|
Loading…
Reference in New Issue