diff --git a/Dependencies.bat b/Dependencies.bat
index d7730a50..0b1e1a54 100644
--- a/Dependencies.bat
+++ b/Dependencies.bat
@@ -17,10 +17,11 @@ echo "J - tracy"
echo "K - RTTR"
echo "L - yamlcpp"
echo "M - SDL"
+echo "N - dotnet"
echo ---------------------------------------------------
echo.
-choice /C ABCDEFGHIJKLM /T 10 /D A
+choice /C ABCDEFGHIJKLMN /T 10 /D A
set _e=%ERRORLEVEL%
if %_e%==1 goto VMA
@@ -36,6 +37,7 @@ if %_e%==10 goto tracy
if %_e%==11 goto RTTR
if %_e%==12 goto yamlcpp
if %_e%==13 goto SDL
+if %_e%==14 goto dotnet
:VMA
echo -----------------------VMA----------------------------
@@ -53,7 +55,7 @@ if %_e%==3 (goto :done) else (goto :assimp)
echo -----------------------assimp----------------------------
rmdir "Dependencies/assimp" /S /Q
git clone https://github.com/SHADE-DP/assimp.git "Dependencies/assimp"
-if %_e%==4 (goto :done) else (goto :ktx)
+if %_e%==4 (goto :done) else (goto :spdlog)
@REM :ktx
@REM rmdir "Dependencies/ktx" /S /Q
@@ -120,6 +122,20 @@ robocopy "Dependencies/SDL/tmp/SDL2-2.24.0/lib/x64" "Dependencies/SDL/lib/" /ns
robocopy "Dependencies/SDL/tmp/SDL2-2.24.0/include/" "Dependencies/SDL/include/" /ns /nfl /ndl /nc /njh
rmdir "Dependencies/SDL/tmp/" /s /q
powershell -Command "& {Remove-Item "Dependencies/SDL/SDL.zip"}"
+if %_e%==13 (goto :done) else (goto :dotnet)
+
+:dotnet
+echo -----------------------dotnet----------------------------
+rmdir "Dependencies/dotnet" /S /Q
+mkdir "Dependencies/dotnet/include"
+mkdir "Dependencies/dotnet/bin"
+powershell -Command "& {wget https://raw.githubusercontent.com/dotnet/runtime/main/src/coreclr/hosts/inc/coreclrhost.h -OutFile "Dependencies/dotnet/include/coreclrhost.h"}"
+powershell -Command "& {wget https://download.visualstudio.microsoft.com/download/pr/8686fa48-b378-424e-908b-afbd66d6e120/2d75d5c3574fb5d917c5a3cd3f624287/dotnet-sdk-6.0.400-win-x64.zip -OutFile "Dependencies/dotnet/dotnet.zip"}"
+powershell -Command "& {Expand-Archive -LiteralPath Dependencies/dotnet/dotnet.zip -DestinationPath Dependencies/dotnet/tmp}"
+robocopy "Dependencies/dotnet/tmp/shared/Microsoft.NETCore.App/6.0.8/" "Dependencies/dotnet/bin/" *.dll /ns /nfl /ndl /nc /njh
+rmdir "Dependencies/dotnet/tmp/" /s /q
+del "Dependencies/dotnet/dotnet.zip"
+powershell -Command "& {Remove-Item "Dependencies/dotnet/dotnet.zip"}"
:done
echo DONE!
diff --git a/Dependencies.lua b/Dependencies.lua
index d2d6cdfd..9877a70e 100644
--- a/Dependencies.lua
+++ b/Dependencies.lua
@@ -13,3 +13,4 @@ IncludeDir["RTTR"] = "%{wks.location}/Dependencies/RTTR"
IncludeDir["reactphysics3d"] = "%{wks.location}/Dependencies/reactphysics3d"
IncludeDir["SDL"] = "%{wks.location}/Dependencies/SDL"
IncludeDir["VULKAN"] = "$(VULKAN_SDK)"
+IncludeDir["dotnet"] = "%{wks.location}/Dependencies/dotnet"
diff --git a/SHADE.sln b/SHADE.sln
index 96aa6455..e317c752 100644
--- a/SHADE.sln
+++ b/SHADE.sln
@@ -26,6 +26,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SHADE_Engine", "SHADE_Engin
{C0FF640D-2C14-8DBE-F595-301E616989EF} = {C0FF640D-2C14-8DBE-F595-301E616989EF}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SHADE_Managed", "SHADE_Managed\SHADE_Managed.vcxproj", "{16DB1400-829B-9036-4BD6-D9B3B755D512}"
+ ProjectSection(ProjectDependencies) = postProject
+ {88F1A057-74BE-FB62-9DD7-E90A890331F1} = {88F1A057-74BE-FB62-9DD7-E90A890331F1}
+ {C0FF640D-2C14-8DBE-F595-301E616989EF} = {C0FF640D-2C14-8DBE-F595-301E616989EF}
+ {3F92E998-2BF5-783D-D47A-B1F3C0BC44C0} = {3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -64,6 +71,10 @@ Global
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Debug|x64.Build.0 = Debug|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Release|x64.ActiveCfg = Release|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Release|x64.Build.0 = Release|x64
+ {16DB1400-829B-9036-4BD6-D9B3B755D512}.Debug|x64.ActiveCfg = Debug|x64
+ {16DB1400-829B-9036-4BD6-D9B3B755D512}.Debug|x64.Build.0 = Debug|x64
+ {16DB1400-829B-9036-4BD6-D9B3B755D512}.Release|x64.ActiveCfg = Release|x64
+ {16DB1400-829B-9036-4BD6-D9B3B755D512}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/SHADE_Application/SHADE_Application.vcxproj b/SHADE_Application/SHADE_Application.vcxproj
index 23bb5e3e..268076af 100644
--- a/SHADE_Application/SHADE_Application.vcxproj
+++ b/SHADE_Application/SHADE_Application.vcxproj
@@ -61,7 +61,7 @@
Level4
4251;%(DisableSpecificWarnings)
_DEBUG;%(PreprocessorDefinitions)
- ..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)
+ ..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;..\Dependencies\dotnet\include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)
EditAndContinue
Disabled
false
@@ -84,7 +84,7 @@
Level4
4251;%(DisableSpecificWarnings)
_RELEASE;%(PreprocessorDefinitions)
- ..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)
+ ..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;..\Dependencies\dotnet\include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)
Full
true
true
@@ -120,6 +120,9 @@
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}
+
+ {16DB1400-829B-9036-4BD6-D9B3B755D512}
+
diff --git a/SHADE_Application/premake5.lua b/SHADE_Application/premake5.lua
index 60281236..9aa1707b 100644
--- a/SHADE_Application/premake5.lua
+++ b/SHADE_Application/premake5.lua
@@ -37,6 +37,7 @@ project "SHADE_Application"
links
{
"SHADE_Engine",
+ "SHADE_Managed",
"SDL2.lib",
"SDL2main.lib"
}
diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp
index 2ce30a2f..171f4995 100644
--- a/SHADE_Application/src/Application/SBApplication.cpp
+++ b/SHADE_Application/src/Application/SBApplication.cpp
@@ -14,6 +14,8 @@
#include
#include
+#include "Scripting/SHScriptEngine.h"
+
namespace Sandbox
{
bool paused = false;
@@ -36,6 +38,8 @@ namespace Sandbox
#else
#endif
+ // Set up scripting
+ SHADE::SHScriptEngine::Init();
}
void SBApplication::Update(void)
@@ -52,6 +56,9 @@ namespace Sandbox
void SBApplication::Exit(void)
{
+ // Shutdown scripting
+ SHADE::SHScriptEngine::Exit();
+
SDL_DestroyWindow(sdlWindow);
#ifdef SHEDITOR
#else
diff --git a/SHADE_Engine/SHADE_Engine.vcxproj b/SHADE_Engine/SHADE_Engine.vcxproj
index 5818e4f5..4fd19678 100644
--- a/SHADE_Engine/SHADE_Engine.vcxproj
+++ b/SHADE_Engine/SHADE_Engine.vcxproj
@@ -61,7 +61,7 @@
Level4
4251;%(DisableSpecificWarnings)
_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;SH_API_EXPORT;_DEBUG;%(PreprocessorDefinitions)
- src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\SDL\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;%(AdditionalIncludeDirectories)
+ src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\SDL\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;..\Dependencies\dotnet\include;%(AdditionalIncludeDirectories)
EditAndContinue
Disabled
false
@@ -78,7 +78,8 @@
xcopy /s /r /y /q "$(SolutionDir)/Dependencies/spdlog/bin" "$(OutDir)"
-xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
+xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
+xcopy /s /r /y /q "$(SolutionDir)/Dependencies/dotnet/bin" "$(OutDir)"
@@ -88,7 +89,7 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"Level4
4251;%(DisableSpecificWarnings)
_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;SH_API_EXPORT;_RELEASE;%(PreprocessorDefinitions)
- src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\SDL\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;%(AdditionalIncludeDirectories)
+ src;..\Dependencies\assimp\include;..\Dependencies\imgui;..\Dependencies\imguizmo;..\Dependencies\imnodes;..\Dependencies\msdf;..\Dependencies\msdf\msdfgen;..\Dependencies\spdlog\include;..\Dependencies\tracy;..\Dependencies\VMA\include;..\Dependencies\yamlcpp\include;..\Dependencies\SDL\include;..\Dependencies\RTTR\include;..\Dependencies\reactphysics3d\include;$(VULKAN_SDK)\include;$(VULKAN_SDK)\Source\SPIRV-Reflect;..\Dependencies\dotnet\include;%(AdditionalIncludeDirectories)
Full
true
true
@@ -108,7 +109,8 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
xcopy /s /r /y /q "$(SolutionDir)/Dependencies/spdlog/bin" "$(OutDir)"
-xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
+xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
+xcopy /s /r /y /q "$(SolutionDir)/Dependencies/dotnet/bin" "$(OutDir)"
@@ -185,6 +187,7 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
+
@@ -192,19 +195,28 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
+
+
+
+
+
+
+
+
+
@@ -274,10 +286,13 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
+
+
+
diff --git a/SHADE_Engine/SHADE_Engine.vcxproj.filters b/SHADE_Engine/SHADE_Engine.vcxproj.filters
index a1022dc7..4eabf09d 100644
--- a/SHADE_Engine/SHADE_Engine.vcxproj.filters
+++ b/SHADE_Engine/SHADE_Engine.vcxproj.filters
@@ -115,6 +115,9 @@
{B3F7140E-1F0C-3DBF-E88D-E01E546139F0}
+
+ {985A7358-04C5-27CF-4D03-D974B9AC0524}
+
{16CF2D0E-82E3-55BF-4B65-F91EB73852F0}
@@ -339,6 +342,9 @@
Math
+
+ Math
+
Math
@@ -360,12 +366,21 @@
Resource
+
+ Resource
+
Resource
+
+ Resource
+
Resource
+
+ Resource
+
@@ -378,6 +393,15 @@
Scene
+
+ Scripting
+
+
+ Scripting
+
+
+ Scripting
+
Tools
@@ -390,9 +414,18 @@
Tools
+
+ Tools
+
+
+ Tools
+
Tools
+
+ Tools
+
@@ -588,6 +621,12 @@
Scene
+
+ Scripting
+
+
+ Scripting
+
Tools
@@ -600,5 +639,8 @@
Tools
+
+ Tools
+
\ No newline at end of file
diff --git a/SHADE_Engine/premake5.lua b/SHADE_Engine/premake5.lua
index 2446e380..d56d78cf 100644
--- a/SHADE_Engine/premake5.lua
+++ b/SHADE_Engine/premake5.lua
@@ -12,6 +12,7 @@ project "SHADE_Engine"
files
{
"%{prj.location}/src/**.h",
+ "%{prj.location}/src/**.hpp",
"%{prj.location}/src/**.c",
"%{prj.location}/src/**.cpp",
"%{prj.location}/src/**.glsl",
@@ -35,7 +36,8 @@ project "SHADE_Engine"
"%{IncludeDir.RTTR}/include",
"%{IncludeDir.reactphysics3d}/include",
"%{IncludeDir.VULKAN}/include",
- "%{IncludeDir.VULKAN}/Source/SPIRV-Reflect"
+ "%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
+ "%{IncludeDir.dotnet}/include",
}
libdirs
@@ -60,7 +62,7 @@ project "SHADE_Engine"
"SDL2.lib",
"SDL2main.lib",
"shaderc_shared.lib",
- "shlwapi"
+ "shlwapi.lib"
}
disablewarnings
@@ -73,7 +75,7 @@ project "SHADE_Engine"
"_LIB",
"_GLFW_INCLUDE_NONE",
"MSDFGEN_USE_CPP11",
- "NOMINMAX",
+ "NOMINMAX",
"SH_API_EXPORT"
}
@@ -94,7 +96,8 @@ project "SHADE_Engine"
postbuildcommands
{
"xcopy /s /r /y /q \"%{IncludeDir.spdlog}/bin\" \"$(OutDir)\"",
- "xcopy /r /y /q \"%{IncludeDir.SDL}/lib/SDL2.dll\" \"$(OutDir)\""
+ "xcopy /r /y /q \"%{IncludeDir.SDL}/lib/SDL2.dll\" \"$(OutDir)\"",
+ "xcopy /s /r /y /q \"%{IncludeDir.dotnet}/bin\" \"$(OutDir)\""
}
warnings 'Extra'
diff --git a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp
index 6005fb01..edf29ec7 100644
--- a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp
+++ b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.cpp
@@ -28,7 +28,7 @@ namespace SHADE
//SHEntityManager::RemoveEntity(this->entityID);
}
- EntityID SHEntity::GetEID() noexcept
+ EntityID SHEntity::GetEID() const noexcept
{
return this->entityID;
}
diff --git a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h
index 685ba99a..9077b0b9 100644
--- a/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h
+++ b/SHADE_Engine/src/ECS_Base/Entity/SHEntity.h
@@ -78,7 +78,7 @@ namespace SHADE
* \return uint32_t
* The entityID of this Entity object.
***************************************************************************/
- EntityID GetEID() noexcept;
+ EntityID GetEID() const noexcept;
/*!*************************************************************************
* \brief Set the Active object
diff --git a/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp b/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp
new file mode 100644
index 00000000..89603524
--- /dev/null
+++ b/SHADE_Engine/src/Scripting/SHDotNetRuntime.cpp
@@ -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
+// Primary Header
+#include "SHDotNetRuntime.h"
+// Standard Library
+#include
+// External Dependencies
+#include // 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");
+ createManagedDelegate = getCoreClrFunctionPtr("coreclr_create_delegate");
+ shutdownCoreClr = getCoreClrFunctionPtr("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
+ static_cast(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 6.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 6.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());
+ }
+ }
+}
diff --git a/SHADE_Engine/src/Scripting/SHDotNetRuntime.h b/SHADE_Engine/src/Scripting/SHDotNetRuntime.h
new file mode 100644
index 00000000..efb9e54b
--- /dev/null
+++ b/SHADE_Engine/src/Scripting/SHDotNetRuntime.h
@@ -0,0 +1,207 @@
+/*************************************************************************************//*!
+\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 // std::setfill, std::setw
+#include // std::runtime_error
+#include // std::string
+#include // std::ostringstream
+// External Dependencies
+#include // HMODULE
+#include // coreclr_*
+
+namespace SHADE
+{
+ /*************************************************************************************/
+ /*!
+
+ class SHDotNetRuntime
+
+ \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 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 std::runtime_error
+ Thrown if there is a failure in loading the CLR and related functions.
+
+ */
+ /***********************************************************************************/
+ void Init();
+ /***********************************************************************************/
+ /*!
+
+ \brief
+ Unloads the CoreCLR.
+
+ \throws std::runtime_error
+ 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() const noexcept { return initialised; }
+
+ /***********************************************************************************/
+ /*!
+
+ \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.
+ \param assemblyName
+ Name of the CoreCLR assembly that contains the function.
+ \param typeName
+ Name of the CoreCLR type in the assembly that contains the function. Nested types
+ are separated by a period(.).
+ \param functionName
+ Name of the CoreCLR function to get a pointer to.
+ \return
+ Pointer to the function in the assembly that was specified.
+
+ */
+ /***********************************************************************************/
+ template
+ FunctionType GetFunctionPtr(const std::string_view& assemblyName,
+ const std::string_view& typeName,
+ const std::string_view& functionName) const;
+
+ 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.
+ \param functionName
+ Name of the CoreCLR function to get a pointer to.
+ \return
+ Pointer to the function in the CoreCLR that was specified.
+
+ */
+ /***********************************************************************************/
+ template
+ FunctionType getCoreClrFunctionPtr(const std::string& functionName);
+ /***********************************************************************************/
+ /*!
+
+ \brief
+ Compiles a semicolon separated string of trusted platform assemblies by
+ searching the specified directory.
+
+ \param directory
+ Path to the directory where the trusted platform assemblies reside.
+ \return
+ Semicolon separated string of trusted platform assemblies.
+
+ */
+ /***********************************************************************************/
+ static std::string buildTpaList(const std::string& directory);
+ /***********************************************************************************/
+ /*!
+
+ \brief
+ Takes in a Win32 result code and throws an exception it if there is an error.
+
+ \param errMsg
+ Error message to display if the resultCode is a failure code.
+ \param resultCode
+ Result code of the function to check.
+
+ */
+ /***********************************************************************************/
+ static void throwIfFailed(const std::string& errMsg, int resultCode);
+ };
+}
+
+#include "SHDotNetRuntime.hpp"
diff --git a/SHADE_Engine/src/Scripting/SHDotNetRuntime.hpp b/SHADE_Engine/src/Scripting/SHDotNetRuntime.hpp
new file mode 100644
index 00000000..ae8f28e5
--- /dev/null
+++ b/SHADE_Engine/src/Scripting/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
+ FunctionType SHDotNetRuntime::GetFunctionPtr(const std::string_view & assemblyName,
+ const std::string_view & typeName,
+ const std::string_view & functionName) const
+ {
+ FunctionType managedDelegate = nullptr;
+ int result = createManagedDelegate
+ (
+ hostHandle,
+ domainId,
+ assemblyName.data(),
+ typeName.data(),
+ functionName.data(),
+ reinterpret_cast(&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
+ FunctionType SHDotNetRuntime::getCoreClrFunctionPtr(const std::string& functionName)
+ {
+ FunctionType fPtr = reinterpret_cast(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;
+ }
+}
diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp
new file mode 100644
index 00000000..47c722dd
--- /dev/null
+++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp
@@ -0,0 +1,506 @@
+/************************************************************************************//*!
+\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
+// Primary Header
+#include "SHScriptEngine.h"
+// Standard Library
+#include // std::fstream
+#include // 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("SHADE");
+ SHDotNetRuntime SHScriptEngine::dotNet { false };
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineInit = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineLoadScripts = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineUnloadScripts = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineReloadScripts = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csEngineExit = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsFrameSetUp = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsExecuteFixedUpdate = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsExecuteUpdate = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsExecuteLateUpdate = nullptr;
+ SHScriptEngine::CsFuncPtr SHScriptEngine::csScriptsFrameCleanUp = nullptr;
+ SHScriptEngine::CsScriptManipFuncPtr SHScriptEngine::csScriptsAdd = nullptr;
+ SHScriptEngine::CsScriptBasicFuncPtr SHScriptEngine::csScriptsRemoveAll = nullptr;
+ SHScriptEngine::CsScriptOptionalFuncPtr SHScriptEngine::csScriptsRemoveAllImmediately = nullptr;
+ SHScriptEngine::CsScriptSerialiseFuncPtr SHScriptEngine::csScriptsSerialise = nullptr;
+ SHScriptEngine::CsScriptDeserialiseFuncPtr SHScriptEngine::csScriptDeserialise = nullptr;
+ SHScriptEngine::CsScriptSerialiseYamlFuncPtr SHScriptEngine::csScriptsSerialiseYaml = nullptr;
+ SHScriptEngine::CsScriptSerialiseYamlFuncPtr SHScriptEngine::csScriptDeserialiseYaml = nullptr;
+ SHScriptEngine::CsScriptEditorFuncPtr SHScriptEngine::csEditorRenderScripts = nullptr;
+
+ /*---------------------------------------------------------------------------------*/
+ /* 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 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::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)
+ {
+ return csScriptsAdd(entity.GetEID(), scriptName.data());
+ }
+ void SHScriptEngine::RemoveAllScripts(const SHEntity& entity)
+ {
+ csScriptsRemoveAll(entity.GetEID());
+ }
+ void SHScriptEngine::RemoveAllScriptsImmediately(const SHEntity& entity, bool callOnDestroy)
+ {
+ csScriptsRemoveAllImmediately(entity.GetEID(), callOnDestroy);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Script Serialisation Functions */
+ /*---------------------------------------------------------------------------------*/
+ std::string SHScriptEngine::SerialiseScripts(const SHEntity& entity)
+ {
+ // Create buffer needed to store serialised script data
+ constexpr int BUFFER_SIZE = 10240;
+ std::unique_ptr 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)
+ {
+ csScriptDeserialise(entity.GetEID(), yaml.c_str());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Script Editor Functions */
+ /*---------------------------------------------------------------------------------*/
+ void SHScriptEngine::RenderScriptsInInspector(const SHEntity& entity)
+ {
+ csEditorRenderScripts(entity.GetEID());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Static Utility Functions */
+ /*---------------------------------------------------------------------------------*/
+ bool SHScriptEngine::BuildScriptAssembly(bool debug)
+ {
+ constexpr std::string_view BUILD_LOG_PATH = "../Build.log";
+
+ // Generate csproj file if it doesn't exist
+ static const std::filesystem::path CSPROJ_PATH = "../SHADE_Scripting.csproj";
+ if (!std::filesystem::exists(CSPROJ_PATH))
+ {
+ GenerateScriptsCsProjFile(CSPROJ_PATH);
+ }
+
+ // Prepare directory (delete useless files)
+ deleteFolder("net6.0");
+ deleteFolder("ref");
+ deleteFolder("../SHADE_Scripting");
+ 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 \"../SHADE_Scripting.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/SHADE_Scripting.dll", "SHADE_Scripting.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 =
+"\n\
+ \n\
+ net6.0\n\
+ x64\n\
+ Release;Debug\n\
+ \n\
+ \n\
+ .\\bin_Release-x64\n\
+ x64\n\
+ \n\
+ \n\
+ .\\bin_Debug-x64\n\
+ x64\n\
+ DEBUG;TRACE\n\
+ false\n\
+ full\n\
+ true\n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ \n\
+ .\\bin\\SHADE_Managed.dll\n\
+ \n\
+ \n\
+";
+
+ // 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
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
+ "Init"
+ );
+ csEngineLoadScripts = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
+ "LoadScriptAssembly"
+ );
+ csEngineUnloadScripts = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
+ "UnloadScriptAssembly"
+ );
+ csEngineReloadScripts = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
+ "ReloadScriptAssembly"
+ );
+ csEngineExit = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
+ "Exit"
+ );
+ csScriptsFrameSetUp = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "FrameSetUp"
+ );
+ csScriptsExecuteFixedUpdate = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "ExecuteFixedUpdate"
+ );
+ csScriptsExecuteUpdate = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "ExecuteUpdate"
+ );
+ csScriptsExecuteLateUpdate = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "ExecuteLateUpdate"
+ );
+ csScriptsFrameCleanUp = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "FrameCleanUp"
+ );
+ csScriptsAdd = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "AddScriptViaName"
+ );
+ csScriptsRemoveAll = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "RemoveAllScripts"
+ );
+ csScriptsRemoveAllImmediately = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "RemoveAllScriptsImmediately"
+ );
+ /*csScriptsSerialise = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "SerialiseScripts"
+ );
+ csScriptsSerialiseYaml = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "SerialiseScriptsYaml"
+ );
+ csScriptDeserialise = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "DeserialiseScript"
+ );
+ csScriptDeserialiseYaml = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
+ "SerialiseScriptsYaml"
+ );
+ csEditorRenderScripts = dotNet.GetFunctionPtr
+ (
+ 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;
+ }
+ }
+ }
+
+}
diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h
new file mode 100644
index 00000000..442c0053
--- /dev/null
+++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h
@@ -0,0 +1,247 @@
+/************************************************************************************//*!
+\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
+
+// Project Headers
+#include "SHDotNetRuntime.h"
+#include "ECS_Base/SHECSMacros.h"
+#include "ECS_Base/Entity/SHEntity.h"
+#include "SH_API.h"
+
+namespace SHADE
+{
+ ///
+ /// Manages initialisation of the DotNetRuntime and interfacing with CLR code written
+ /// and executed on .NET.
+ ///
+ class SH_API SHScriptEngine
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructor */
+ /*-----------------------------------------------------------------------------*/
+ SHScriptEngine() = delete;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Lifecycle Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Initialises the DotNetRuntime and retrieves function pointers to all
+ /// functions on the CLR used to interface with the engine.
+ ///
+ static void Init();
+ ///
+ /// Loads the managed script assembly. Ensure this is only called after
+ /// UnloadScriptAssembly() has been called.
+ ///
+ static void UnloadScriptAssembly();
+ ///
+ /// 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 LoadScriptAssembly();
+ ///
+ /// Reloads the managed script assembly.
+ /// Take note that this will clear all existing scripts, ensure that the scene
+ /// is saved before doing so.
+ ///
+ static void ReloadScriptAssembly();
+ ///
+ /// Executes the FixedUpdate()s of the Scripts that are attached to
+ /// Entities.
+ ///
+ static void ExecuteFixedUpdates();
+ ///
+ /// Shuts down the DotNetRuntime.
+ ///
+ static void Exit();
+
+ /*-----------------------------------------------------------------------------*/
+ /* Script Manipulation Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// 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 Script added of the specified type.
+ ///
+ /// The entity to add a script to.
+ /// Type name of the script to add.
+ ///
+ /// True if successfully added. False otherwise with the error logged to the
+ /// console.
+ ///
+ static bool AddScript(const SHEntity& entity, const std::string_view& scriptName);
+ ///
+ /// Removes all Scripts attached to the specified Entity. Does not do anything
+ /// if the specified Entity is invalid or does not have any Scripts
+ /// attached.
+ ///
+ /// The entity to remove the scripts from.
+ static void RemoveAllScripts(const SHEntity& entity);
+ ///
+ /// 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
+ /// Scripts attached.
+ ///
+ /// The entity to remove the scripts from.
+ ///
+ /// Whether or not to call OnDestroy on the scripts. This is ignored if not in
+ /// play mode.
+ ///
+ static void RemoveAllScriptsImmediately(const SHEntity& entity, bool callOnDestroy);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Script Serialisation Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Generates a JSON string that represents the set of Scripts attached to the
+ /// specified Entity.
+ ///
+ /// The Entity to Serialise.
+ ///
+ /// String that represents the set of scripts attached to the specified Entity.
+ ///
+ static std::string SerialiseScripts(const SHEntity& entity);
+ ///
+ /// Loads the specified JSON string and creates a Script for the specified Entity
+ /// based on the specified JSON string.
+ ///
+ /// The Entity to deserialise a Script on to.
+ ///
+ /// The YAML string that represents the Script to load into the Entity.
+ ///
+ static void DeserialiseScript(const SHEntity& entity, const std::string& yaml);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Script Editor Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Renders the set of attached Scripts for the specified Entity into the
+ /// inspector.
+ ///
+ /// This function is meant for consumption from native code in the inspector
+ /// rendering code.
+ ///
+ /// The Entity to render the Scripts of.
+ static void RenderScriptsInInspector(const SHEntity& entity);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Static Utility Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Utilises execution of a external batch file for invoking the dotnet build
+ /// tool to compile C# scripts in the Assets folder into the SHADE_Scripting
+ /// C# assembly DLL.
+ ///
+ ///
+ /// Whether or not a debug build will be built. Only debug built C# assemblies
+ /// can be debugged.
+ ///
+ /// Whether or not the build succeeded.
+ static bool BuildScriptAssembly(bool debug = false);
+ ///
+ /// Generates a .csproj file for editing and compiling the C# scripts.
+ ///
+ /// File path to the generated file.
+ 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 CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*);
+ using CsScriptEditorFuncPtr = void(*)(EntityID);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Constants */
+ /*-----------------------------------------------------------------------------*/
+ 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;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Data Members */
+ /*-----------------------------------------------------------------------------*/
+ static SHDotNetRuntime dotNet;
+ // Function Pointers to CLR Code
+ // - Engine Lifecycle
+ static CsFuncPtr csEngineInit;
+ static CsFuncPtr csEngineLoadScripts;
+ static CsFuncPtr csEngineUnloadScripts;
+ static CsFuncPtr csEngineReloadScripts;
+ static CsFuncPtr csEngineExit;
+ // - Scripts Store
+ static CsFuncPtr csScriptsFrameSetUp;
+ static CsFuncPtr csScriptsExecuteFixedUpdate;
+ static CsFuncPtr csScriptsExecuteUpdate;
+ static CsFuncPtr csScriptsExecuteLateUpdate;
+ static CsFuncPtr csScriptsFrameCleanUp;
+ static CsScriptManipFuncPtr csScriptsAdd;
+ static CsScriptBasicFuncPtr csScriptsRemoveAll;
+ static CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately;
+ static CsScriptSerialiseFuncPtr csScriptsSerialise;
+ static CsScriptDeserialiseFuncPtr csScriptDeserialise;
+ static CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml;
+ static CsScriptSerialiseYamlFuncPtr csScriptDeserialiseYaml;
+ // - Editor
+ static CsScriptEditorFuncPtr csEditorRenderScripts;
+ // Delegates
+ /*ECS::EntityEvent::Delegate onEntityCreate;
+ ECS::EntityEvent::Delegate onEntityDestroy;*/
+
+ /*-----------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Loads all the function pointers to CLR code that we need to execute.
+ ///
+ static void loadFunctions();
+ ///
+ /// Reads the file via the specified path that represents a build log of error
+ /// and warning messages.
+ ///
+ ///
+ /// File path to the build log of script builds done by BuildScriptAssembly() to
+ /// dump and process.
+ ///
+ static void dumpBuildLog(const std::string_view& buildLogPath);
+ ///
+ /// Deletes the file as specified by the file path.
+ ///
+ /// File path to the file to delete.
+ static void deleteFile(const std::string_view& filePath);
+ ///
+ /// Deletes the folder and all files in it as specified by the file path.
+ ///
+ /// File path to the file to delete.
+ static void deleteFolder(const std::string_view& filePath);
+ ///
+ /// Checks if a specified file exists.
+ ///
+ /// File path to the file to check.
+ /// True if the file exists
+ static bool fileExists(const std::string_view& filePath);
+ static DWORD execProcess(const std::wstring& path, const std::wstring& args);
+ };
+}
diff --git a/SHADE_Engine/src/Tools/SHStringUtils.cpp b/SHADE_Engine/src/Tools/SHStringUtils.cpp
new file mode 100644
index 00000000..a2594888
--- /dev/null
+++ b/SHADE_Engine/src/Tools/SHStringUtils.cpp
@@ -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
+// Primary Header
+#include "SHStringUtils.h"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Utility Functions */
+ /*---------------------------------------------------------------------------------*/
+ std::vector SHStringUtils::Split(const std::string& str, const char& delim)
+ {
+ return Split(str, delim);
+ }
+ std::vector SHStringUtils::Split(const std::wstring& str, const wchar_t& delim)
+ {
+ return Split(str, delim);
+ }
+ std::string SHStringUtils::WstrToStr(const std::wstring& wstr)
+ {
+ static std::vector buffer;
+ const int STR_SIZE = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.size()), nullptr, 0, nullptr, nullptr) + 1 /* Null Terminator */;
+ buffer.resize(STR_SIZE);
+ WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast(wstr.size()), buffer.data(), MAX_PATH, nullptr, nullptr);
+ return std::string(buffer.data());
+ }
+ std::wstring SHStringUtils::StrToWstr(const std::string& str)
+ {
+ static std::vector buffer;
+ const int WSTR_SIZE = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), nullptr, 0) + 1 /* Null Terminator */;
+ buffer.resize(WSTR_SIZE);
+ MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), buffer.data(), WSTR_SIZE);
+ return std::wstring(buffer.data());
+ }
+
+ std::string SHStringUtils::GetWin32ErrorMessage(unsigned long errorCode)
+ {
+ return std::system_category().message(errorCode);
+ }
+
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Tools/SHStringUtils.h b/SHADE_Engine/src/Tools/SHStringUtils.h
new file mode 100644
index 00000000..1c895b99
--- /dev/null
+++ b/SHADE_Engine/src/Tools/SHStringUtils.h
@@ -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 // std::basic_string
+#include // std::vector
+
+namespace SHADE
+{
+ ///
+ /// Contains useful functions for operating on strings.
+ ///
+ class SHStringUtils
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Utility Functions */
+ /*-----------------------------------------------------------------------------*/
+
+ ///
+ /// Splits a string separated by a specified delimiter into a vector of strings.
+ ///
+ /// Internal type of each element in the string.
+ /// Read only reference to the string to split.
+ /// Read only reference to the delimiter.
+ /// Vector of strings that have been split.
+ template
+ static std::vector> Split(const std::basic_string& str, const T& delim);
+ ///
+ /// Splits a string separated by a specified delimiter into a vector of strings.
+ /// Overload of Split() to allow for string literals to be accepted.
+ ///
+ /// Read only reference to the string to split.
+ /// Read only reference to the delimiter.
+ /// Vector of strings that have been split.
+ static std::vector Split(const std::string& str, const char& delim);
+ ///
+ /// Splits a string separated by a specified delimiter into a vector of strings.
+ /// Overload of Split() to allow for wide string literals to be accepted.
+ ///
+ /// Read only reference to the string to split.
+ /// Read only reference to the delimiter.
+ /// Vector of strings that have been split.
+ static std::vector Split(const std::wstring& str, const wchar_t& delim);
+ ///
+ /// Converts a wstring to a string.
+ ///
+ /// wstring to convert.
+ /// The converted wstring in string form.
+ static std::string WstrToStr(const std::wstring& wstr);
+ ///
+ /// Converts a string to a wstring.
+ ///
+ /// string to convert.
+ /// The converted string in wstring form.
+ static std::wstring StrToWstr(const std::string& str);
+ ///
+ /// Retrieves the error message associated with a Win32 error code.
+ ///
+ /// Win32 error code to decode.
+ /// String that represents the Win32 error.
+ static std::string GetWin32ErrorMessage(unsigned long errorCode);
+
+ private:
+ /*-------------------------------------------------------------------------------*/
+ /* Constructors/Destructors */
+ /*-------------------------------------------------------------------------------*/
+ SHStringUtils() = delete;
+ };
+}
+
+#include "SHStringUtils.hpp"
diff --git a/SHADE_Engine/src/Tools/SHStringUtils.hpp b/SHADE_Engine/src/Tools/SHStringUtils.hpp
new file mode 100644
index 00000000..8b83187a
--- /dev/null
+++ b/SHADE_Engine/src/Tools/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
+ inline std::vector> SHStringUtils::Split(const std::basic_string& str, const T& delim)
+ {
+ std::vector> results;
+ std::basic_string 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;
+ }
+}
\ No newline at end of file
diff --git a/SHADE_Managed/SHADE_Managed.vcxproj.filters b/SHADE_Managed/SHADE_Managed.vcxproj.filters
new file mode 100644
index 00000000..c1901bac
--- /dev/null
+++ b/SHADE_Managed/SHADE_Managed.vcxproj.filters
@@ -0,0 +1,113 @@
+
+
+
+
+ {6B7DD516-5735-1764-C03C-F0BFAC13B254}
+
+
+ {DBC7D3B0-C769-FE86-B024-12DB9C6585D7}
+
+
+ {AFF4887C-9B2B-8A0D-4418-7010302E060F}
+
+
+ {4D6F1AE8-B94E-9983-C266-245A2EC5FFE4}
+
+
+ {594615A9-C525-9444-CE3D-1F1B3A9CFAA5}
+
+
+
+
+ Components
+
+
+ Engine
+
+
+ Engine
+
+
+ Engine
+
+
+ Engine
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+
+ Scripts
+
+
+ Scripts
+
+
+ Utility
+
+
+ Utility
+
+
+ Utility
+
+
+
+
+
+ Components
+
+
+ Engine
+
+
+ Engine
+
+
+ Engine
+
+
+ Engine
+
+
+ Math
+
+
+ Math
+
+
+ Math
+
+
+
+ Scripts
+
+
+ Scripts
+
+
+ Utility
+
+
+ Utility
+
+
+ Utility
+
+
+
+
+ Components
+
+
+ Engine
+
+
+
\ No newline at end of file
diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua
new file mode 100644
index 00000000..092e92af
--- /dev/null
+++ b/SHADE_Managed/premake5.lua
@@ -0,0 +1,74 @@
+project "SHADE_Managed"
+ kind "SharedLib"
+ language "C++"
+ clr "NetCore"
+ dotnetframework "net6.0"
+ cppdialect "C++17"
+ targetdir (outputdir)
+ objdir (interdir)
+ systemversion "latest"
+ pchheader "SHpch.h"
+ pchsource "%{prj.location}/src/SHpch.cpp"
+ staticruntime "off"
+
+ files
+ {
+ "%{prj.location}/src/**.hxx",
+ "%{prj.location}/src/**.h++",
+ "%{prj.location}/src/**.cxx",
+ "%{prj.location}/src/**.h",
+ "%{prj.location}/src/**.hpp",
+ "%{prj.location}/src/**.c",
+ "%{prj.location}/src/**.cpp",
+ }
+
+ includedirs
+ {
+ "%{prj.location}/src",
+ "%{IncludeDir.spdlog}/include",
+ "%{IncludeDir.imgui}",
+ "%{IncludeDir.imguizmo}",
+ "%{IncludeDir.imnodes}",
+ "%{IncludeDir.yamlcpp}",
+ "%{IncludeDir.RTTR}/include",
+ "%{wks.location}/SHADE_Engine/src"
+ }
+
+ links
+ {
+ "yaml-cpp",
+ "imgui",
+ "SHADE_Engine"
+ }
+
+ disablewarnings
+ {
+ "4251"
+ }
+
+ defines
+ {
+ "NOMINMAX"
+ }
+
+ flags
+ {
+ "MultiProcessorCompile"
+ }
+
+ dependson
+ {
+ "yaml-cpp",
+ "imgui",
+ "SHADE_Engine"
+ }
+
+ warnings 'Extra'
+
+ filter "configurations:Debug"
+ symbols "On"
+ defines {"_DEBUG"}
+
+ filter "configurations:Release"
+ optimize "On"
+ defines{"_RELEASE"}
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/Components/Component.cxx b/SHADE_Managed/src/Components/Component.cxx
new file mode 100644
index 00000000..a6afc5cc
--- /dev/null
+++ b/SHADE_Managed/src/Components/Component.cxx
@@ -0,0 +1,107 @@
+/************************************************************************************//*!
+\file Component.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 27, 2021
+\brief Contains the definition of the functions for the Component 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 "Components/Component.hxx"
+// External Dependencies
+#include "Engine/ECS.hxx"
+// Project Headers
+#include "Scripts/ScriptStore.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Component Access Functions */
+ /*---------------------------------------------------------------------------------*/
+ generic
+ T BaseComponent::AddComponent()
+ {
+ return ECS::AddComponent(owner.GetEntity());
+ }
+ generic
+ T BaseComponent::GetComponent()
+ {
+ return ECS::GetComponent(owner.GetEntity());
+ }
+ generic
+ void BaseComponent::RemoveComponent()
+ {
+ ECS::RemoveComponent(owner.GetEntity());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Script Access Functions */
+ /*---------------------------------------------------------------------------------*/
+ generic
+ T BaseComponent::AddScript()
+ {
+ return ScriptStore::AddScript(owner.GetEntity());
+ }
+ generic
+ T BaseComponent::GetScript()
+ {
+ return ScriptStore::GetScript(owner.GetEntity());
+ }
+
+ generic
+ System::Collections::Generic::IEnumerable^ BaseComponent::GetScripts()
+ {
+ return ScriptStore::GetScripts(owner.GetEntity());
+ }
+
+ generic
+ void BaseComponent::RemoveScript()
+ {
+ ScriptStore::RemoveScript(owner.GetEntity());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Constructors */
+ /*---------------------------------------------------------------------------------*/
+ BaseComponent::BaseComponent(Entity entity)
+ : owner { entity }
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*---------------------------------------------------------------------------------*/
+ bool BaseComponent::Equals(BaseComponent^ other)
+ {
+ if (other == nullptr)
+ return false;
+ return owner == other->owner;
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Object */
+ /*---------------------------------------------------------------------------------*/
+ bool BaseComponent::Equals(Object^ o)
+ {
+ try
+ {
+ BaseComponent^ cmp = safe_cast(o);
+ return Equals(cmp);
+ }
+ catch (System::InvalidCastException^)
+ {
+ return false;
+ }
+ }
+
+ int BaseComponent::GetHashCode()
+ {
+ return owner.GetHashCode();
+ }
+}
diff --git a/SHADE_Managed/src/Components/Component.h++ b/SHADE_Managed/src/Components/Component.h++
new file mode 100644
index 00000000..e2a20998
--- /dev/null
+++ b/SHADE_Managed/src/Components/Component.h++
@@ -0,0 +1,41 @@
+/************************************************************************************//*!
+\file Component.h++
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 27, 2021
+\brief Contains the definition of templated functions for the managed Component
+ classes.
+
+ 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
+
+// Primary Include
+#include "Component.hxx"
+// Project includes
+#include "Utility/Convert.hxx"
+#include "Engine/ECS.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Constructors */
+ /*---------------------------------------------------------------------------------*/
+ template
+ Component::Component(Entity entity)
+ : BaseComponent { entity }
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*---------------------------------------------------------------------------------*/
+ template
+ typename Component::NativeComponent* Component::GetNativeComponent()
+ {
+ return ECS::GetNativeComponent(owner.GetEntity());
+ }
+}
diff --git a/SHADE_Managed/src/Components/Component.hxx b/SHADE_Managed/src/Components/Component.hxx
new file mode 100644
index 00000000..670e4e21
--- /dev/null
+++ b/SHADE_Managed/src/Components/Component.hxx
@@ -0,0 +1,200 @@
+/************************************************************************************//*!
+\file Component.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 27, 2021
+\brief Contains the definition of the managed Component classes with the
+ declaration of functions for working with it.
+
+ 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
+
+// External Dependencies
+#include "ECS_Base/Components/SHComponent.h"
+// Project Includes
+#include "Engine/Entity.hxx"
+#include "Scripts/Script.hxx"
+
+namespace SHADE
+{
+ ///
+ /// Class that serves as the base for a wrapper class to Components in native code.
+ ///
+ public ref class BaseComponent : public System::IEquatable
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Properties */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Retrieves the GameObject that this Component belongs to.
+ ///
+ property GameObject Owner
+ {
+ GameObject get() { return owner; }
+ }
+
+ /*-----------------------------------------------------------------------------*/
+ /* Component Access Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Adds a Component to this GameObject.
+ ///
+ /// Type of the Component to add.
+ /// Reference to the Component that was added.
+ generic where T : BaseComponent
+ T AddComponent();
+ ///
+ /// Gets a Component from this GameObject.
+ ///
+ /// Type of the Component to get.
+ ///
+ /// Reference to the Component or null if this GameObject does not have the
+ /// specified Component.
+ ///
+ generic where T : BaseComponent
+ T GetComponent();
+ ///
+ /// Removes a Component from this GameObject. If no Component exists to begin
+ /// with, nothing happens.
+ ///
+ /// Type of the Component to get.
+ generic where T : BaseComponent
+ void RemoveComponent();
+
+ /*-----------------------------------------------------------------------------*/
+ /* Script Access Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Adds a Script of the specified type to this GameObject.
+ ///
+ /// Type of Script to add.
+ /// Reference to the created Script.
+ generic where T : ref class, Script
+ T AddScript();
+ ///
+ /// Retrieves a Script of the specified type from this GameObject.
+ /// If multiple Scripts of the same specified type are added on the same
+ /// GameObject, this will retrieve the first one added.
+ ///
+ /// Type of Script to add.
+ /// Reference to the Script to retrieve.
+ generic where T : ref class, Script
+ T GetScript();
+ ///
+ /// Retrieves a immutable list of Scripts of the specified type from this
+ /// GameObject.
+ ///
+ /// Type of Scripts to Get.
+ /// Immutable list of Scripts of the specified type.
+ generic where T : ref class, Script
+ System::Collections::Generic::IEnumerable^ GetScripts();
+ ///
+ /// Removes all Scripts of the specified type from this GameObject.
+ ///
+ /// Type of PLushieScripts to remove.
+ generic where T : ref class, Script
+ void RemoveScript();
+
+ protected:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Constructor for BaseComponent to tie it to a specific Entity.
+ /// Constructors of derived Components should call this Constructor.
+ ///
+ /// Entity that this Component will be tied to.
+ BaseComponent(Entity entity);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Data Members */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Entity that this Component belongs to.
+ ///
+ GameObject owner;
+
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with an object of the same type.
+ ///
+ /// The object to compare with.
+ /// True if both objects are the same.
+ virtual bool Equals(BaseComponent^ other);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Object */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with another unboxed object.
+ ///
+ /// The unboxed object to compare with.
+ /// True if both objects are the same.
+ bool Equals(Object^ o) override;
+ ///
+ /// Gets a unique hash for this object.
+ ///
+ /// Unique hash for this object.
+ int GetHashCode() override;
+ };
+
+ ///
+ /// C++ template for the BaseComponent class used to generate common template-able
+ /// functions and types.
+ ///
+ ///
+ /// Type of the native component that this Component wraps.
+ ///
+ template
+ public ref class Component : public BaseComponent
+ {
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Type Definitions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Type of the native component that this Component wraps.
+ ///
+ using NativeComponent = NativeType;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Retrieves a pointer to the native unmanaged component that is tied to the
+ /// Entity described by the owner value.
+ ///
+ ///
+ /// Pointer to the native component. Will be nullptr if it does not exist.
+ ///
+ ///
+ /// Thrown if the internal ID stored by this native component is invalid.
+ ///
+ ///
+ /// Thrown if an attempt to retrieve the native component fails.
+ ///
+ NativeComponent* GetNativeComponent();
+
+ protected:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Constructor for Component to tie it to a specific Entity.
+ /// Constructors of derived Components should call this Constructor.
+ ///
+ /// Entity that this Component will be tied to.
+ Component(Entity entity);
+ };
+}
+
+#include "Component.h++"
diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx
new file mode 100644
index 00000000..5aceceee
--- /dev/null
+++ b/SHADE_Managed/src/Engine/ECS.cxx
@@ -0,0 +1,255 @@
+/************************************************************************************//*!
+\file ECS.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 28, 2021
+\brief Contains the definition of the functions for the ECS managed 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 "ECS.hxx"
+// Standard Library
+#include
+#include
+// External Dependencies
+#include "ECS_Base/System/SHEntityManager.h"
+// Project Headers
+#include "Utility/Convert.hxx"
+#include "Utility/Debug.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Component Manipulation Functions */
+ /*---------------------------------------------------------------------------------*/
+ generic
+ T ECS::AddComponent(EntityID entity)
+ {
+ System::Type^ componentType = T::typeid;
+
+ // Check if entity is correct
+ if (!SHEntityManager::IsValidEID(entity))
+ {
+ std::ostringstream oss;
+ oss << "[ECS] Attempted to add Component \""
+ << msclr::interop::marshal_as(componentType->Name)
+ << "\" to invalid Entity.";
+ Debug::LogError(oss.str());
+ return T();
+ }
+
+ // Add based on the correct component
+ for each(ComponentSet^ type in componentMap)
+ {
+ if (componentType == type->Type)
+ {
+ // Attempt to add
+ type->AddFunction(entity);
+
+ // Return the managed component
+ return createManagedComponent(entity);
+ }
+ }
+
+ std::ostringstream oss;
+ oss << "[ECS] Failed to add unsupported Component \""
+ << Convert::ToNative(componentType->Name)
+ << "\" to Entity #"
+ << entity;
+ Debug::LogError(oss.str());
+ return T();
+ }
+ generic
+ T ECS::GetComponent(EntityID entity)
+ {
+ System::Type^ componentType = T::typeid;
+
+ // Check if entity is correct
+ if (!SHEntityManager::IsValidEID(entity))
+ {
+ std::ostringstream oss;
+ oss << "[ECS] Attempted to retrieve Component \""
+ << Convert::ToNative(componentType->Name)
+ << "\" from invalid Entity.";
+ Debug::LogError(oss.str());
+ return T();
+ }
+
+ // Get based on the correct component
+ for each(ComponentSet^ type in componentMap)
+ {
+ if (componentType == type->Type)
+ {
+ if (type->HasFunction(entity))
+ {
+ return createManagedComponent(entity);
+ }
+ else
+ {
+ return T();
+ }
+ }
+ }
+
+ std::ostringstream oss;
+ oss << "[ECS] Failed to retrieve unsupported Component \""
+ << Convert::ToNative(componentType->Name)
+ << "\" to Entity #"
+ << entity;
+ Debug::LogError(oss.str());
+ return T();
+ }
+
+ generic
+ T ECS::GetComponentInChildren(EntityID entity)
+ {
+ System::Type^ componentType = T::typeid;
+
+ // Check if entity is correct
+ if (!SHEntityManager::IsValidEID(entity))
+ {
+ std::ostringstream oss;
+ oss << "[ECS] Attempted to retrieve Component \""
+ << Convert::ToNative(componentType->Name)
+ << "\" from invalid Entity.";
+ Debug::LogError(oss.str());
+ return T();
+ }
+
+ // Get Transform component and get the children list
+ throw gcnew System::NotImplementedException;
+ //Pls::Transform* tf = Pls::ECS::GetComponent(entity);
+ //if (tf == nullptr)
+ // return T();
+
+ //// Search direct children first
+ //for (const auto& child : tf->GetChildren())
+ //{
+ // T component = GetComponent(child);
+ // if (component != nullptr)
+ // return component;
+ //}
+
+ //// Search their children
+ //for (const auto& child : tf->GetChildren())
+ //{
+ // T script = GetComponentInChildren(child);
+ // if (script != nullptr)
+ // return script;
+ //}
+
+ // None here
+ return T();
+ }
+
+ generic
+ T ECS::EnsureComponent(EntityID entity)
+ {
+ if (HasComponent(entity))
+ {
+ AddComponent(entity);
+ }
+
+ return GetComponent(entity);
+ }
+ generic
+ bool ECS::HasComponent(EntityID entity)
+ {
+ System::Type^ componentType = T::typeid;
+
+ // Check if entity is correct
+ if (!SHEntityManager::IsValidEID(entity))
+ {
+ std::ostringstream oss;
+ oss << "[ECS] Attempted to check existence of Component \""
+ << Convert::ToNative(componentType->Name)
+ << "\" from invalid Entity.";
+ Debug::LogError(oss.str());
+ return false;
+ }
+
+ // Add based on the correct component
+ for each(ComponentSet^ type in componentMap)
+ {
+ if (componentType == type->Type)
+ {
+ return type->HasFunction(entity);
+ }
+ }
+
+ std::ostringstream oss;
+ oss << "[ECS] Attempted to check existence of unsupported Component \""
+ << msclr::interop::marshal_as(componentType->Name)
+ << "\" from Entity #"
+ << entity;
+ Debug::LogError(oss.str());
+
+ return false;
+ }
+ generic
+ void ECS::RemoveComponent(EntityID entity)
+ {
+ System::Type^ componentType = T::typeid;
+
+ // Check if entity is correct
+ if (!SHEntityManager::IsValidEID(entity))
+ {
+ std::ostringstream oss;
+ oss << "[ECS] Attempted to remove Component \""
+ << Convert::ToNative(componentType->Name)
+ << "\" from invalid Entity.";
+ Debug::LogError(oss.str());
+ }
+
+ // Add based on the correct component
+ for each(ComponentSet^ type in componentMap)
+ {
+ if (componentType == type->Type)
+ {
+ type->RemoveFunction(entity);
+ return;
+ }
+ }
+
+ std::ostringstream oss;
+ oss << "[ECS] Attempted to remove unsupported Component \""
+ << msclr::interop::marshal_as(componentType->Name)
+ << "\" from Entity #"
+ << entity;
+ Debug::LogError(oss.str());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Constructors */
+ /*---------------------------------------------------------------------------------*/
+ static ECS::ECS()
+ {
+ // TODO
+ // componentMap.Add(createComponentSet());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*---------------------------------------------------------------------------------*/
+ generic
+ T ECS::createManagedComponent(EntityID entity)
+ {
+ using namespace System::Reflection;
+
+ array^ params = gcnew array{ static_cast(entity) };
+ return safe_cast(System::Activator::CreateInstance
+ (
+ T::typeid,
+ BindingFlags::Instance | BindingFlags::NonPublic | BindingFlags::CreateInstance,
+ nullptr, params, nullptr)
+ );
+ }
+}
diff --git a/SHADE_Managed/src/Engine/ECS.h++ b/SHADE_Managed/src/Engine/ECS.h++
new file mode 100644
index 00000000..e5ede5f2
--- /dev/null
+++ b/SHADE_Managed/src/Engine/ECS.h++
@@ -0,0 +1,60 @@
+/************************************************************************************//*!
+\file ECS.h++
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 27, 2021
+\brief Contains the definition of templated functions for the managed Component
+ classes.
+
+ 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
+
+// Primary Include
+#include "ECS.hxx"
+// External Dependencies
+#include "ECS_Base/System/SHComponentManager.h"
+#include "ECS_Base/System/SHEntityManager.h"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*---------------------------------------------------------------------------------*/
+ template
+ NativeComponent* ECS::GetNativeComponent(Entity entity)
+ {
+ // Get native Entity
+ SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity);
+
+ // Entity Validity Check
+ if (nativeEntity == nullptr)
+ throw gcnew System::InvalidOperationException("Attempted to get native Component to an invalid Entity.");
+
+ // Null Check
+ NativeComponent* component = SHComponentManager::GetComponent_s(nativeEntity);
+ if (component == nullptr)
+ throw gcnew System::NullReferenceException("Attempted to get a native Component that does not exist.");
+
+ return component;
+ }
+ /*---------------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*---------------------------------------------------------------------------------*/
+ template
+ ECS::ComponentSet ECS::createComponentSet()
+ {
+ return ComponentSet
+ {
+ ManagedType::typeid,
+ SHComponentManager::AddComponent,
+ SHComponentManager::EnsureComponent,
+ SHComponentManager::HasComponent,
+ SHComponentManager::RemoveComponent
+ };
+ }
+}
diff --git a/SHADE_Managed/src/Engine/ECS.hxx b/SHADE_Managed/src/Engine/ECS.hxx
new file mode 100644
index 00000000..72c88e11
--- /dev/null
+++ b/SHADE_Managed/src/Engine/ECS.hxx
@@ -0,0 +1,174 @@
+/************************************************************************************//*!
+\file ECS.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 28, 2021
+\brief Contains the definitions of the GameObject managed class which define an
+ abstraction for working with Entities in managed code.
+
+ 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
+
+// External Dependencies
+#include "ECS_Base/System/SHComponentManager.h"
+// Project Includes
+#include "Components/Component.hxx"
+
+namespace SHADE
+{
+ ///
+ /// Static class which contains functions that map Pls::ECS's Component manipulation
+ /// functions to managed generic functions.
+ ///
+ private ref class ECS abstract sealed
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Component Manipulation Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Adds a Component to the specified Entity.
+ ///
+ /// Type of the Component to add.
+ ///
+ /// Entity object that should have the specified Component added to.
+ ///
+ /// Reference to the Component that was added.
+ generic where T : BaseComponent
+ static T AddComponent(EntityID entity);
+ ///
+ /// Gets a Component from the specified Entity.
+ ///
+ /// Type of the Component to get.
+ /// Entity object to get the Component from.
+ ///
+ /// Reference to the Component or null if the Entity does not have the
+ /// specified Component.
+ ///
+ generic where T : BaseComponent
+ static T GetComponent(EntityID entity);
+ ///
+ /// Retrieves the first Component from the specified GameObjectt's children that
+ /// matches the specified type.
+ ///
+ /// Type of the Component to get.
+ /// Entity object to get the Component from.
+ ///
+ /// Reference to the Component or null if the Entity does not have the
+ /// specified Component.
+ ///
+ generic where T : BaseComponent
+ static T GetComponentInChildren(EntityID entity);
+ ///
+ /// Ensures a Component on the specified Entity.
+ ///
+ /// Type of the Component to ensure.
+ /// Entity object to ensure the Component on.
+ /// Reference to the Component.
+ generic where T : BaseComponent
+ static T EnsureComponent(EntityID entity);
+ ///
+ /// Checks if the specified Entity has the specified Component.
+ ///
+ /// Type of the Component to check for.
+ /// Entity object to check for the Component.
+ ///
+ /// True if the specified Entity has the specified Component. False otherwise.
+ ///
+ generic where T : BaseComponent
+ static bool HasComponent(EntityID entity);
+ ///
+ /// Removes a Component from the specified Entity.
+ ///
+ /// Type of the Component to remove.
+ ///
+ /// Entity object that should have the specified Component removed from/
+ ///
+ generic where T : BaseComponent
+ static void RemoveComponent(EntityID entity);
+
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Type Definitions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Pointer to a function for Component manipulation operations.
+ ///
+ using ComponentFunc = void(*)(const EntityID&);
+ using ComponentHasFunc = bool(*)(const EntityID&);
+ ///
+ /// Contains a set of Component related data used for resolving operations for
+ /// each Component.
+ ///
+ value struct ComponentSet
+ {
+ public:
+ System::Type^ Type;
+ ComponentFunc AddFunction;
+ ComponentHasFunc HasFunction;
+ ComponentFunc RemoveFunction;
+
+ };
+
+ /*-----------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Retrieves a pointer to the native unmanaged component of the specified
+ /// Entity.
+ ///
+ ///
+ /// Pointer to the native component. Will be nullptr if it does not exist.
+ ///
+ ///
+ /// Thrown if the Entity specified is invalid.
+ ///
+ ///
+ /// Thrown if an attempt to retrieve the native component fails.
+ ///
+ template
+ static NativeComponent* GetNativeComponent(Entity entity);
+
+ private:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Static constructor to initialize static data
+ ///
+ static ECS();
+
+ /*-----------------------------------------------------------------------------*/
+ /* Static Data Members */
+ /*-----------------------------------------------------------------------------*/
+ static System::Collections::Generic::List componentMap;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Creates a ComponentSet for a pair of Native and Managed Components.
+ ///
+ /// Type of the Native Component.
+ /// Type of the Managed Component.
+ /// ComponentSet for the parameters specified.
+ template
+ static ComponentSet createComponentSet();
+ ///
+ /// Creates an instance of the Managed representation of a Component with a
+ /// native Entity.
+ ///
+ /// Type of Component to create.
+ /// Native Entity that this Component is tied to.
+ /// The created Managed representation of the Component.
+ generic where T : BaseComponent
+ static T createManagedComponent(EntityID entity);
+ };
+}
+
+#include "ECS.h++"
diff --git a/SHADE_Managed/src/Engine/EngineInterface.cxx b/SHADE_Managed/src/Engine/EngineInterface.cxx
new file mode 100644
index 00000000..2009b2e5
--- /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
+{
+ /*---------------------------------------------------------------------------------*/
+ /* 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")
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Constructor */
+ /*---------------------------------------------------------------------------------*/
+ static EngineInterface::EngineInterface()
+ {
+ exceptionHandler = gcnew System::UnhandledExceptionEventHandler(unhandledExceptionHandler);
+ managedLibPath = System::Reflection::Assembly::GetExecutingAssembly()->Location->Replace("SHADE_Managed.dll", ManagedLibraryName + ".dll");
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* 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^, 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..4fd8f7b3
--- /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";
+
+ /*-----------------------------------------------------------------------------*/
+ /* 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:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructor */
+ /*-----------------------------------------------------------------------------*/
+ static EngineInterface();
+
+ /*-----------------------------------------------------------------------------*/
+ /* 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/Engine/Entity.cxx b/SHADE_Managed/src/Engine/Entity.cxx
new file mode 100644
index 00000000..ba1a31c6
--- /dev/null
+++ b/SHADE_Managed/src/Engine/Entity.cxx
@@ -0,0 +1,28 @@
+/************************************************************************************//*!
+\file Entity.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 28, 2021
+\brief Contains the definition of the functions for the EntityUtils managed
+ 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 "Entity.hxx"
+// External Dependencies
+#include "ECS_Base/System/SHEntityManager.h"
+
+namespace SHADE
+{
+ bool EntityUtils::IsValid(Entity^ entity)
+ {
+ return SHEntityManager::IsValidEID(static_cast(entity));
+ }
+}
diff --git a/SHADE_Managed/src/Engine/Entity.hxx b/SHADE_Managed/src/Engine/Entity.hxx
new file mode 100644
index 00000000..7be9340b
--- /dev/null
+++ b/SHADE_Managed/src/Engine/Entity.hxx
@@ -0,0 +1,41 @@
+/************************************************************************************//*!
+\file Entity.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 28, 2021
+\brief Contains the definitions of a managed Entity identifier and declarations
+ of useful utility functions for working with Entity identifiers.
+
+ 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
+
+// External Dependencies
+#include "ECS_Base/Entity/SHEntity.h"
+
+namespace SHADE
+{
+ ///
+ /// Managed representation of a native ECS Entity.
+ ///
+ using Entity = System::UInt32;
+
+ ///
+ /// Static class that contains useful utility functions for working with Entity.
+ ///
+ private ref class EntityUtils abstract sealed
+ {
+ public:
+ ///
+ /// Checks if the specified entity is valid. This is done by checking if it
+ /// matches Pls::Entity::INVALID.
+ ///
+ /// The Entity to check.
+ /// True if the specified Entity is valid.
+ static bool IsValid(Entity^ entity);
+ };
+}
diff --git a/SHADE_Managed/src/Engine/GameObject.cxx b/SHADE_Managed/src/Engine/GameObject.cxx
new file mode 100644
index 00000000..3896fac5
--- /dev/null
+++ b/SHADE_Managed/src/Engine/GameObject.cxx
@@ -0,0 +1,201 @@
+/************************************************************************************//*!
+\file GameObject.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 28, 2021
+\brief Contains the definition of the functions for the GameObject managed 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 "GameObject.hxx"
+// External Dependencies
+#include "ECS_Base/System/SHEntityManager.h"
+// Project Headers
+#include "ECS.hxx"
+#include "Scripts/ScriptStore.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*---------------------------------------------------------------------------------*/
+ GameObject GameObject::Create()
+ {
+ return GameObject(SHEntityManager::CreateEntity());
+ }
+
+ void GameObject::Destroy(GameObject obj)
+ {
+ SHEntityManager::DestroyEntity(static_cast(obj.GetEntity()));
+ }
+
+ System::Nullable GameObject::Find(System::String ^ name)
+ {
+ // Search the GameObjectLibrary for an Entity with the specified name
+ throw gcnew System::NotImplementedException();
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Properties */
+ /*---------------------------------------------------------------------------------*/
+ System::String^ GameObject::Name::get()
+ {
+ return Convert::ToCLI(GetNativeEntity().name);
+
+ }
+ bool GameObject::IsActiveSelf::get()
+ {
+ return GetNativeEntity().isActive;
+ }
+ bool GameObject::IsActiveInHierarchy::get()
+ {
+ throw gcnew System::NotImplementedException();
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* GameObject Property Functions */
+ /*---------------------------------------------------------------------------------*/
+ void GameObject::SetName(System::String^ name)
+ {
+ GetNativeEntity().name = Convert::ToNative(name);
+ }
+ void GameObject::SetActive(bool active)
+ {
+ GetNativeEntity().isActive = active;
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Component Functions */
+ /*---------------------------------------------------------------------------------*/
+ generic
+ T GameObject::AddComponent()
+ {
+ return ECS::AddComponent(entity);
+ }
+
+ generic
+ T GameObject::GetComponent()
+ {
+ return ECS::GetComponent(entity);
+ }
+
+ generic
+ T GameObject::GetComponentInChildren()
+ {
+ return ECS::GetComponentInChildren(entity);
+ }
+
+ generic
+ T GameObject::EnsureComponent()
+ {
+ return ECS::EnsureComponent(entity);
+ }
+
+ generic
+ void GameObject::RemoveComponent()
+ {
+ ECS::RemoveComponent(entity);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Script Access Functions */
+ /*---------------------------------------------------------------------------------*/
+ generic
+ T GameObject::AddScript()
+ {
+ return ScriptStore::AddScript(entity);
+ }
+
+ generic
+ T GameObject::GetScript()
+ {
+ return ScriptStore::GetScript(entity);
+ }
+
+ generic
+ T GameObject::GetScriptInChildren()
+ {
+ return ScriptStore::GetScriptInChildren(entity);
+ }
+
+ generic
+ System::Collections::Generic::IEnumerable^ GameObject::GetScripts()
+ {
+ return ScriptStore::GetScripts(entity);
+ }
+
+ generic
+ void GameObject::RemoveScript()
+ {
+ ScriptStore::RemoveScript(entity);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Constructors */
+ /*---------------------------------------------------------------------------------*/
+ GameObject::GameObject(const SHEntity& entity)
+ : entity { entity.GetEID() }
+ {}
+
+ GameObject::GameObject(Entity entity)
+ : entity { entity }
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* Getters */
+ /*---------------------------------------------------------------------------------*/
+ SHEntity& GameObject::GetNativeEntity()
+ {
+ SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity);
+ if (nativeEntity == nullptr)
+ throw gcnew System::InvalidOperationException("[GameObject] Unable to obtain native Entity for GameObject.");
+
+ return *nativeEntity;
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*---------------------------------------------------------------------------------*/
+ bool GameObject::Equals(GameObject other)
+ {
+ return entity == other.entity;
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Object */
+ /*---------------------------------------------------------------------------------*/
+ bool GameObject::Equals(Object^ o)
+ {
+ try
+ {
+ GameObject^ cmp = safe_cast(o);
+ return Equals(cmp);
+ }
+ catch (System::InvalidCastException^)
+ {
+ return false;
+ }
+ }
+
+ int GameObject::GetHashCode()
+ {
+ return entity.GetHashCode();
+ }
+
+ bool GameObject::operator==(GameObject lhs, GameObject rhs)
+ {
+ return lhs.Equals(rhs);
+ }
+
+ bool GameObject::operator!=(GameObject lhs, GameObject rhs)
+ {
+ return !(lhs == rhs);
+ }
+}
diff --git a/SHADE_Managed/src/Engine/GameObject.hxx b/SHADE_Managed/src/Engine/GameObject.hxx
new file mode 100644
index 00000000..723d9cec
--- /dev/null
+++ b/SHADE_Managed/src/Engine/GameObject.hxx
@@ -0,0 +1,282 @@
+/************************************************************************************//*!
+\file GameObject.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 28, 2021
+\brief Contains the definitions of the GameObject managed class which define an
+ abstraction for working with Entities in managed code.
+
+ 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 "Entity.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Forward Declarations */
+ /*---------------------------------------------------------------------------------*/
+ ref class Script;
+ ref class BaseComponent;
+
+ /*---------------------------------------------------------------------------------*/
+ /* Class Definitions */
+ /*---------------------------------------------------------------------------------*/
+ ///
+ /// Lightweight object for an PlushieEngine Entity that allows for easy access
+ /// to Component and Script operations.
+ ///
+ public value class GameObject : public System::IEquatable
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Creates a new GameObject in the current Scene. If multiple Scenes are loaded,
+ /// and you would like to create an object in a specific Scene, call the Scene's
+ /// CreateGameObject().
+ ///
+ /// GameObject that represents the newly created GameObject.
+ static GameObject Create();
+ ///
+ /// Destroys the specified GameObject. Note that the specified GameObject will no
+ /// longer be a valid GameObject after this function is called.
+ ///
+ /// The GameObject to be destroyed.
+ static void Destroy(GameObject obj);
+ ///
+ /// Retrieves a GameObject with the specified name. If there are multiple
+ /// GameObjects with the same name, the first found GameObject will be retrieved.
+ /// There is no guaranteed order of which GameObject is considered "first".
+ ///
+ /// Name of the GameObject to find.
+ /// GameObject that has the specified name. Null if not found.
+ static System::Nullable Find(System::String^ name);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Properties */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Name of the object that this Entity represents.
+ ///
+ property System::String^ Name
+ {
+ System::String^ get();
+ }
+ ///
+ /// Whether or not this Entity alone, is active. This does not mean that this
+ /// object is active in the scene. For example, if this Entity's parent is not
+ /// active, then this Entity would also be not active.
+ ///
+ property bool IsActiveSelf
+ {
+ bool get();
+ }
+ ///
+ /// Whether or not this Entity is active in the Scene hierarchy.
+ ///
+ property bool IsActiveInHierarchy
+ {
+ bool get();
+ }
+
+ /*-----------------------------------------------------------------------------*/
+ /* GameObject Property Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Sets the name of this GameObject.
+ ///
+ /// The name to set.
+ void SetName(System::String^ name);
+ ///
+ /// Sets the active state of this GameObject.
+ ///
+ /// The actual "activeness" of this GameObject is still dependent on the parents'
+ /// active states.
+ ///
+ ///
+ /// Whether to activate or deactivate this GameObject.
+ ///
+ void SetActive(bool active);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Component Access Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Adds a Component to this GameObject.
+ ///
+ /// Type of the Component to add.
+ /// Reference to the Component that was added.
+ generic where T : BaseComponent
+ T AddComponent();
+ ///
+ /// Gets a Component from this GameObject.
+ ///
+ /// Type of the Component to get.
+ ///
+ /// Reference to the Component or null if this GameObject does not have the
+ /// specified Component.
+ ///
+ generic where T : BaseComponent
+ T GetComponent();
+ ///
+ /// Retrieves the first Component from this GameObject's children that matches
+ /// the specified type.
+ ///
+ /// Type of the Component to get.
+ ///
+ /// Reference to the Component or null if neither of this GameObject's children
+ /// does not have the specified Component.
+ ///
+ generic where T : BaseComponent
+ T GetComponentInChildren();
+ ///
+ /// Ensures a Component on this GameObject.
+ ///
+ /// Type of the Component to ensure.
+ ///
+ /// Reference to the Component.
+ ///
+ generic where T : BaseComponent
+ T EnsureComponent();
+ ///
+ /// Removes a Component from this GameObject. If no Component exists to begin
+ /// with, nothing happens.
+ ///
+ /// Type of the Component to get.
+ generic where T : BaseComponent
+ void RemoveComponent();
+
+ /*-----------------------------------------------------------------------------*/
+ /* Script Access Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Adds a Script of the specified type to this GameObject.
+ ///
+ /// Type of Script to add.
+ /// Reference to the created Script.
+ generic where T : ref class, Script
+ T AddScript();
+ ///
+ /// Retrieves a Script of the specified type from this GameObject.
+ /// If multiple Scripts of the same specified type are added on the same
+ /// GameObject, this will retrieve the first one added.
+ ///
+ /// Type of Script to retrieve.
+ /// Reference to the Script to retrieve.
+ generic where T : ref class, Script
+ T GetScript();
+ ///
+ /// Retrieves a Script of the specified type from child GameObjects.
+ /// If multiple Scripts of the same specified type are added on the same
+ /// child GameObject, this will retrieve the first one added.
+ ///
+ /// Type of Script to retrieve.
+ /// Reference to the Script to retrieve.
+ generic where T : ref class, Script
+ T GetScriptInChildren();
+ ///
+ /// Retrieves a immutable list of Scripts of the specified type from this
+ /// GameObject.
+ ///
+ /// Type of Scripts to retrieve.
+ /// Immutable list of Scripts of the specified type.
+ generic where T : ref class, Script
+ System::Collections::Generic::IEnumerable^ GetScripts();
+ ///
+ /// Removes all Scripts of the specified type from this GameObject.
+ ///
+ /// Type of PLushieScripts to remove.
+ generic where T : ref class, Script
+ void RemoveScript();
+
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Constructor for the GameObject.
+ ///
+ ///
+ /// The ECS Entity that this GameObject should represent.
+ ///
+ GameObject(const SHEntity& entity);
+ ///
+ /// Constructor for the GameObject.
+ ///
+ ///
+ /// Managed numerical representation of the ECS Entity that this GameObject
+ /// should represent.
+ ///
+ GameObject(Entity entity);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Getters */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Retrieves the CLR Entity object that this GameObject represents.
+ ///
+ /// Entity object that this GameObject represents.
+ inline Entity GetEntity() { return entity; }
+ ///
+ /// Retrieves the native Entity object that this GameObject represents.
+ ///
+ /// Native Entity object that this GameObject represents.
+ SHEntity& GetNativeEntity();
+
+ private:
+ /*-----------------------------------------------------------------------------*/
+ /* Data Members */
+ /*-----------------------------------------------------------------------------*/
+ Entity entity;
+
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with an object of the same type.
+ ///
+ /// The object to compare with.
+ /// True if both objects are the same.
+ virtual bool Equals(GameObject other);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Object */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with another unboxed object.
+ ///
+ /// The unboxed object to compare with.
+ /// True if both objects are the same.
+ bool Equals(Object^ o) override;
+ ///
+ /// Gets a unique hash for this object.
+ ///
+ /// Unique hash for this object.
+ int GetHashCode() override;
+ ///
+ /// Checks if two GameObject references are the same.
+ ///
+ /// GameObject to check.
+ /// Another GameObject to check with.
+ /// True if both Components are the same.
+ static bool operator==(GameObject lhs, GameObject rhs);
+ ///
+ /// Checks if two GameObject references are different.
+ ///
+ /// GameObject to check.
+ /// Another GameObject to check with.
+ /// True if both Components are different.
+ static bool operator!=(GameObject lhs, GameObject rhs);
+ };
+
+}
+
diff --git a/SHADE_Managed/src/Math/Math.cxx b/SHADE_Managed/src/Math/Math.cxx
new file mode 100644
index 00000000..5ec850a1
--- /dev/null
+++ b/SHADE_Managed/src/Math/Math.cxx
@@ -0,0 +1,57 @@
+/************************************************************************************//*!
+\file Math.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Nov 11, 2021
+\brief Contains the implementation of the functions of the managed Math struct.
+
+ 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 "Math/Math.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Utility Functions */
+ /*---------------------------------------------------------------------------------*/
+ double Math::Wrap(double value, double min, double max)
+ {
+ while (value < min)
+ {
+ value = max - (min - value);
+ }
+ while (value > max)
+ {
+ value = min + (value - max);
+ }
+ return value;
+ }
+ double Math::DegreesToRadians(double degrees)
+ {
+ return degrees * Deg2Rad;
+ }
+ double Math::RadiansToDegrees(double radians)
+ {
+ return radians * Rad2Deg;
+ }
+ double Math::Lerp(double a, double b, double t)
+ {
+ return LerpUnclamped(a, b, System::Math::Clamp(t, 0.0, 1.0));
+ }
+ double Math::LerpUnclamped(double a, double b, double t)
+ {
+ return a + t * (b - a);
+ }
+
+ double Math::InverseLerp(double a, double b, double value)
+ {
+ return (value - a) / (b - a);
+ }
+}
diff --git a/SHADE_Managed/src/Math/Math.hxx b/SHADE_Managed/src/Math/Math.hxx
new file mode 100644
index 00000000..3ddc5149
--- /dev/null
+++ b/SHADE_Managed/src/Math/Math.hxx
@@ -0,0 +1,92 @@
+/************************************************************************************//*!
+\file Math.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Nov 11, 2021
+\brief Contains the definition of the managed Math 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
+
+namespace SHADE
+{
+ ///
+ /// Contains utility Math functions.
+ ///
+ public ref class Math abstract sealed
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Static Constants */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Degrees-to-radians conversion constant
+ ///
+ static constexpr double Deg2Rad = System::Math::PI / 180.0;
+ ///
+ /// Radians-to-degrees conversion constant
+ ///
+ static constexpr double Rad2Deg = 180.0 / System::Math::PI;
+ ///
+ /// Small value used for single precision floating point comparisons.
+ ///
+ static constexpr float Epsilon = 0.001f;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Utility Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Wraps a value if they get to low or too high.
+ ///
+ /// Value to wrap.
+ /// Minimum value to wrap at.
+ /// Maximum value to wrap at.
+ /// Wrapped value.
+ static double Wrap(double value, double min, double max);
+ ///
+ /// Converts an angle from degree representation to radian representation.
+ ///
+ /// Degree-based angle to convert.
+ /// The specified angle in radians.
+ static double DegreesToRadians(double degrees);
+ ///
+ /// Converts an angle from radian representation to degree representation.
+ ///
+ /// Radian-based angle to convert.
+ /// The specified angle in degrees.
+ static double RadiansToDegrees(double radians);
+ ///
+ /// Linearly interpolates between a and b by t.
+ /// The parameter t is clamped to the range [0, 1].
+ ///
+ /// The start value.
+ /// The end value.
+ /// The interpolation value between the two double.
+ /// The interpolated double result between the two double values.
+ static double Lerp(double a, double b, double t);
+ ///
+ /// Linearly interpolates between a and b by t.
+ /// The parameter t is not clamped and a value based on a and b is supported.
+ /// If t is less than zero, or greater than one, then LerpUnclamped will result
+ /// in a return value outside the range a to b.
+ ///
+ /// The start value.
+ /// The end value.
+ /// The interpolation value between the two double.
+ /// The interpolated double result between the two double values.
+ static double LerpUnclamped(double a, double b, double t);
+ ///
+ /// Calculates the linear parameter t that produces the interpolant value within the range [a, b].
+ ///
+ /// Start value.
+ /// End value.
+ /// Value between start and end.
+ /// Percentage of value between start and end.
+ static double InverseLerp(double a, double b, double value);
+ };
+}
diff --git a/SHADE_Managed/src/Math/Vector2.cxx b/SHADE_Managed/src/Math/Vector2.cxx
new file mode 100644
index 00000000..d40e2323
--- /dev/null
+++ b/SHADE_Managed/src/Math/Vector2.cxx
@@ -0,0 +1,263 @@
+/************************************************************************************//*!
+\file Vector2.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Nov 2, 2021
+\brief Contains the definitions of functions of the Vector2 struct.
+
+ 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 "Math/Vector2.hxx"
+// Standard Libraries
+#include
+#include
+// Project Headers
+#include "Math.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Constructors */
+ /*---------------------------------------------------------------------------------*/
+ Vector2::Vector2(double _x)
+ : Vector2 { _x, 0.0 }
+ {}
+ Vector2::Vector2(double _x, double _y)
+ : x { _x }
+ , y { _y }
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* Usage Functions */
+ /*---------------------------------------------------------------------------------*/
+ void Vector2::Normalise()
+ {
+ *this = GetNormalised();
+ }
+
+ Vector2 Vector2::GetNormalised()
+ {
+ return *this / GetMagnitude();
+ }
+
+ double Vector2::GetMagnitude()
+ {
+ return sqrt(x * x + y * y);
+ }
+
+ double Vector2::GetSqrMagnitude()
+ {
+ return x * x + y * y;
+ }
+
+ double Vector2::AngleFromRightRadians()
+ {
+ return atan2(y, x);
+ }
+
+ double Vector2::AngleFromRightDegrees()
+ {
+ return Math::RadiansToDegrees(AngleFromRightRadians());
+ }
+
+ bool Vector2::IsNearPoint(Vector2 point)
+ {
+ return IsNearPoint(point, Math::Epsilon);
+ }
+
+ bool Vector2::IsNearPoint(Vector2 point, double tolerance)
+ {
+ return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*---------------------------------------------------------------------------------*/
+ bool Vector2::Equals(Object^ o)
+ {
+ try
+ {
+ Vector2 vec = safe_cast(o);
+ return Equals(vec);
+ }
+ catch (System::InvalidCastException^)
+ {
+ return false;
+ }
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Object Overrides */
+ /*---------------------------------------------------------------------------------*/
+ bool Vector2::Equals(Vector2 other)
+ {
+ return IsNear(*this, other);
+ }
+ int Vector2::GetHashCode()
+ {
+ const int HASH = 19;
+ return x.GetHashCode() * HASH + y.GetHashCode();
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*---------------------------------------------------------------------------------*/
+ bool Vector2::IsNear(Vector2 lhs, Vector2 rhs)
+ {
+ return IsNear(lhs, rhs, Math::Epsilon);
+ }
+ bool Vector2::IsNear(Vector2 lhs, Vector2 rhs, double tolerance)
+ {
+ return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
+ &&
+ (std::abs(lhs.y) - std::abs(rhs.y)) < tolerance;
+ }
+ double Vector2::Dot(Vector2 lhs, Vector2 rhs)
+ {
+ return lhs.x * rhs.x + lhs.y * rhs.y;
+ }
+
+ Vector2 Vector2::Perpendicular(Vector2 lhs)
+ {
+ return Perpendicular(lhs, true);
+ }
+
+ Vector2 Vector2::Perpendicular(Vector2 lhs, bool inward)
+ {
+ if (inward)
+ {
+ return Vector2
+ (
+ -lhs.y, lhs.x
+ );
+ }
+ else
+ {
+ return Vector2
+ (
+ lhs.y, -lhs.x
+ );
+ }
+ }
+
+ Vector2 Vector2::Project(Vector2 vec, Vector2 direction)
+ {
+ return direction.GetNormalised() * vec.GetMagnitude();
+ }
+ Vector2 Vector2::Reflect(Vector2 vec, Vector2 normal)
+ {
+ return vec - (Project(vec, normal.GetNormalised()) * 2.0);
+ }
+ Vector2 Vector2::RotateRadians(Vector2 vec, double radians)
+ {
+ const double SINE = sin(radians);
+ const double COSINE = cos(radians);
+
+ return Vector2
+ (
+ vec.x * COSINE - vec.y * SINE,
+ vec.x * SINE + vec.y * COSINE
+ );
+ }
+ Vector2 Vector2::RotateDegrees(Vector2 vec, double degrees)
+ {
+ return RotateRadians(vec, Math::DegreesToRadians(degrees));
+ }
+ Vector2 Vector2::Min(Vector2 lhs, Vector2 rhs)
+ {
+ double lx = lhs.x, rx = rhs.x;
+ double ly = lhs.y, ry = rhs.y;
+
+ return Vector2(std::min(lx, rx),
+ std::min(ly, ry));
+ }
+ Vector2 Vector2::Max(Vector2 lhs, Vector2 rhs)
+ {
+ double lx = lhs.x, rx = rhs.x;
+ double ly = lhs.y, ry = rhs.y;
+
+ return Vector2(std::max(lx, rx),
+ std::max(ly, ry));
+ }
+ Vector2 Vector2::Lerp(Vector2 a, Vector2 b, double t)
+ {
+ return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
+ }
+ Vector2 Vector2::LerpUnclamped(Vector2 a, Vector2 b, double t)
+ {
+ return a + ((b - a) * t);
+ }
+ Vector2 Vector2::MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta)
+ {
+ // Ignore if it is exactly on the same point
+ if (current == target)
+ return target;
+
+ // Calculate new position
+ Vector2 DELTA = (target - current).GetNormalised() * maxDistanceDelta;
+ Vector2 newPos = current + DELTA;
+
+ // Check if check if is behind or ahead of target
+ Vector2 DIFF = target - newPos;
+ if (Dot(DELTA, DIFF) < 0.0)
+ {
+ newPos = target;
+ }
+ return newPos;
+ }
+ Vector2 Vector2::operator+(Vector2 lhs, Vector2 rhs)
+ {
+ return Vector2
+ (
+ lhs.x + rhs.x,
+ lhs.y + rhs.y
+ );
+ }
+ Vector2 Vector2::operator-(Vector2 lhs, Vector2 rhs)
+ {
+ return Vector2
+ (
+ lhs.x - rhs.x,
+ lhs.y - rhs.y
+ );
+ }
+ Vector2 Vector2::operator*(Vector2 lhs, Vector2 rhs)
+ {
+ return Vector2
+ (
+ lhs.x * rhs.x,
+ lhs.y * rhs.y
+ );
+ }
+ Vector2 Vector2::operator*(Vector2 lhs, double rhs)
+ {
+ return Vector2
+ (
+ lhs.x * rhs,
+ lhs.y * rhs
+ );
+ }
+ Vector2 Vector2::operator/(Vector2 lhs, double rhs)
+ {
+ return Vector2
+ (
+ lhs.x / rhs,
+ lhs.y / rhs
+ );
+ }
+ bool Vector2::operator==(Vector2 lhs, Vector2 rhs)
+ {
+ return lhs.Equals(rhs);
+ }
+ bool Vector2::operator!=(Vector2 lhs, Vector2 rhs)
+ {
+ return !(lhs == rhs);
+ }
+} // namespace PlushieAPI::Mathematics
\ No newline at end of file
diff --git a/SHADE_Managed/src/Math/Vector2.hxx b/SHADE_Managed/src/Math/Vector2.hxx
new file mode 100644
index 00000000..69a6110f
--- /dev/null
+++ b/SHADE_Managed/src/Math/Vector2.hxx
@@ -0,0 +1,396 @@
+/************************************************************************************//*!
+\file Vector2.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Nov 2, 2021
+\brief Contains the definitions of Vector2 struct.
+
+ 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
+
+// Standard Libraries
+#include
+
+namespace SHADE
+{
+ ///
+ /// CLR version of the the PlushieEngine's Vector2 class that represents a
+ /// 2-Dimensional Vector. Designed to closely match Unity's Vector2 struct.
+ ///
+ [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
+ public value struct Vector2 : public System::IEquatable
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Constants */
+ /*-----------------------------------------------------------------------------*/
+ #pragma region Constants
+ ///
+ /// Shorthand for writing Vector2(0, -1).
+ ///
+ static initonly Vector2 Down = Vector2(0.0, -1.0);
+ ///
+ /// Shorthand for writing Vector2(-1, 0).
+ ///
+ static initonly Vector2 Left = Vector2(-1.0, 0.0);
+ ///
+ /// Shorthand for writing Vector2(double.NegativeInfinity,
+ /// double.NegativeInfinity).
+ ///
+ static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits::lowest(), std::numeric_limits::lowest());
+ ///
+ /// Shorthand for writing Vector2(1, 1).
+ ///
+ static initonly Vector2 One = Vector2(1.0, 1.0);
+ ///
+ /// Shorthand for writing Vector2(double.PositiveInfinity,
+ /// double.PositiveInfinity).
+ ///
+ static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits::max(), std::numeric_limits::max());
+ ///
+ /// Shorthand for writing Vector2(1, 0).
+ ///
+ static initonly Vector2 Right = Vector2(1.0, 0.0);
+ ///
+ /// Shorthand for writing Vector2(0, 1).
+ ///
+ static initonly Vector2 Up = Vector2(0.0, 1.0);
+ ///
+ /// Shorthand for writing Vector2(0, 0).
+ ///
+ static initonly Vector2 Zero = Vector2(0.0, 0.0);
+ #pragma endregion
+
+ /*-----------------------------------------------------------------------------*/
+ /* Public Members */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// X-component of the Vector2.
+ ///
+ double x;
+ ///
+ /// Y-component of the Vector2.
+ ///
+ double y;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Constructor to construct a Vector2 with the specified components with the
+ /// Y-component set to 0.0.
+ ///
+ /// X-coordinate to set.
+ Vector2(double _x);
+ ///
+ /// Constructor to construct a Vector2 with the specified components..
+ ///
+ /// X-coordinate to set.
+ /// Y-coordinate to set.
+ Vector2(double _x, double _y);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Usage Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Normalises this current Vector2. This changes the data of this Vector2.
+ /// If you would like to get a copy, use GetNormalised() instead.
+ /// This function does nothing to a zero vector.
+ ///
+ void Normalise();
+ ///
+ /// Creates a copy of this Vector2 and returns a normalized version.
+ ///
+ ///
+ /// Returns a normalised copy of this Vector2.
+ /// If this Vector2 is a zero vector, a zero vector will be returned.
+ ///
+ Vector2 GetNormalised();
+ ///
+ /// Calculates and returns the magnitude of this Vector2. Note that this function
+ /// incurs a performance cost from the square root calculation. If you do not
+ /// need the precise magnitude, consider using GetSqrMagnitude() instead.
+ ///
+ /// Returns the length of this Vector2.
+ double GetMagnitude();
+ ///
+ /// Calculates and returns the squared magnitude of this Vector2.
+ ///
+ /// Returns the squared length of this Vector2.
+ double GetSqrMagnitude();
+ ///
+ /// Calculates and returns the angle of this vector from the right vector. This
+ /// function returns values between -Math.PI and Math.PI.
+ ///
+ /// Returns the angle of this vector from the right vector in radians.
+ double AngleFromRightRadians();
+ ///
+ /// Calculates and returns the angle of this vector from the right vector. This
+ /// function returns values between -180.0 and 180.0.
+ ///
+ /// Returns the angle of this vector from the right vector in degrees.
+ double AngleFromRightDegrees();
+ ///
+ /// Checks if a specified point is near this Vector2 that represents a point with
+ /// a tolerance value of PLS_EPSILON.
+ ///
+ /// The other point to check if we are near.
+ ///
+ /// True if this Vector2 representing a point and the specified point are within
+ /// the range of the specified tolerance. False otherwise.
+ ///
+ bool IsNearPoint(Vector2 point);
+ ///
+ /// Checks if a specified point is near this Vector2 that represents a point.
+ ///
+ /// The other point to check if we are near.
+ ///
+ /// The amount of tolerance before we consider these points as "near".
+ ///
+ ///
+ /// True if this Vector2 representing a point and the specified point are within
+ /// the range of the specified tolerance. False otherwise.
+ ///
+ bool IsNearPoint(Vector2 point, double tolerance);
+
+ /*-----------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with an object of the same type.
+ ///
+ /// The object to compare with.
+ /// True if both objects are the same.
+ virtual bool Equals(Vector2 other);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Object */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with another unboxed object.
+ ///
+ /// The unboxed object to compare with.
+ /// True if both objects are the same.
+ bool Equals(Object^ o) override;
+ ///
+ /// Gets a unique hash for this object.
+ ///
+ /// Unique hash for this object.
+ int GetHashCode() override;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Checks if two specified Vector2s are near in value.
+ ///
+ /// Vector2 to check if is near in value.
+ /// Another Vector2 to check if is near in value.
+ ///
+ /// True if the two Vector2s are within the tolerance value specified
+ ///
+ static bool IsNear(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Checks if two specified Vector2s are near in value.
+ ///
+ /// Vector2 to check if is near in value.
+ /// Another Vector2 to check if is near in value.
+ ///
+ /// Amount of tolerance to do the comparison with.
+ ///
+ ///
+ /// True if the two Vector2s are within the tolerance value specified
+ ///
+ static bool IsNear(Vector2 lhs, Vector2 rhs, double tolerance);
+ ///
+ /// Computes and returns the dot product of 2 specified Vector2s.
+ ///
+ /// Vector2 to calculate dot product with.
+ /// Another Vector2 to calculate dot product with.
+ ///
+ /// Scalar value representing the dot product of the two Vector2s.
+ ///
+ static double Dot(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Computes the inward perpendicular Vector2 to the specified Vector2.
+ /// Equivalent to calling Perpendicular(lhs, true). This means, the
+ /// resultant Vector2 is rotated 90-degrees in a counter-clockwise.
+ ///
+ /// Vector2 to find a perpendicular of.
+ ///
+ /// The perpendicular Vector2 relative to the specified Vector2.
+ ///
+ static Vector2 Perpendicular(Vector2 lhs);
+ ///
+ /// Computes a perpendicular Vector2 to the specified Vector2.
+ ///
+ /// Vector2 to find a perpendicular of.
+ ///
+ /// Whether the inward perpendicular Vector is retrieved. If true, the
+ /// resultant vector is rotated 90-degrees in a counter-clockwise.
+ ///
+ /// The perpendicular Vector2 relative to the specified Vector2.
+ ///
+ static Vector2 Perpendicular(Vector2 lhs, bool inward);
+ ///
+ /// Computes and returns a Vector2 projection.
+ ///
+ /// Vector2 to project.
+ /// Vector2 to project onto.
+ /// The Vector2 that represents the projected vec onto direction.
+ static Vector2 Project(Vector2 vec, Vector2 direction);
+ ///
+ /// Reflects a Vector2 across another Vector2.
+ ///
+ /// A Vector2 to reflect.
+ /// A normal to reflect the Vector2 across.
+ /// The Vector2 that represents vec reflected across normal.
+ static Vector2 Reflect(Vector2 vec, Vector2 normal);
+ ///
+ /// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise
+ /// direction.
+ ///
+ /// A Vector2 to rotate.
+ ///
+ /// Angle to rotate the vector by in an anti-clockwise direction in radians.
+ ///
+ /// The Vector2 that represents the rotated vector.
+ static Vector2 RotateRadians(Vector2 vec, double radians);
+ ///
+ /// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise
+ /// direction.
+ ///
+ /// A Vector2 to rotate.
+ ///
+ /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
+ ///
+ /// The Vector2 that represents the rotated vector.
+ static Vector2 RotateDegrees(Vector2 vec, double degrees);
+ ///
+ /// Computes and returns a Vector2 that is made from the smallest components of
+ /// the two specified Vector2s.
+ ///
+ /// Vector2 to calculate minimum Vector2 with.
+ /// Another Vector2 to calculate minimum Vector2 with.
+ ///
+ /// The Vector2 that contains the smallest components of the two specified
+ /// Vector2s.
+ ///
+ static Vector2 Min(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Computes and returns a Vector2 that is made from the largest components of
+ /// the two specified Vector2s.
+ ///
+ /// Vector2 to calculate maximum Vector2 with.
+ /// Another Vector2 to calculate maximum Vector2 with.
+ ///
+ /// The Vector2 that contains the largest components of the two specified
+ /// Vector2s.
+ ///
+ static Vector2 Max(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Linearly interpolates between two specified points.
+ /// This is most commonly used to find a point some fraction of the way along a
+ /// line between two endpoints.
+ ///
+ /// The start Vector2, returned when t = 0.0.
+ /// The end Vector2, returned when t = 1.0.
+ ///
+ /// Value used to interpolate between a and b which is clamped to
+ /// the range[0, 1].
+ ///
+ /// The interpolated Vector2.
+ static Vector2 Lerp(Vector2 a, Vector2 b, double t);
+ ///
+ /// Linearly interpolates between two specified points.
+ /// This is most commonly used to find a point some fraction of the way along a
+ /// line between two endpoints.
+ /// Unlike Lerp(), t is not clamped to a range at all.
+ ///
+ /// The start Vector2, returned when t = 0.0.
+ /// The end Vector2, returned when t = 1.0.
+ /// Value used to interpolate between a and b.
+ /// The interpolated Vector2.
+ static Vector2 LerpUnclamped(Vector2 a, Vector2 b, double t);
+ ///
+ /// Moves a point current towards target.
+ /// Similar to Lerp(), however, the function will ensure that the distance never
+ /// exceeds maxDistanceDelta. Negative values of maxDistanceDelta pushes the
+ /// vector away from target
+ ///
+ /// The current position of the point.
+ /// The target position to move to.
+ /// Maximum distance moved per call.
+ /// Vector representing the moved point.
+ static Vector2 MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Overloaded Operators */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Adds two Vector2s together and returns the result.
+ ///
+ /// Vector2 to add.
+ /// Another Vector2 to add.
+ /// The result of lhs added to rhs
+ static Vector2 operator+(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Subtracts a Vector2 from another Vector2 and returns the result.
+ ///
+ /// Vector2 to subtract from.
+ /// Another Vector2 to subtract.
+ /// The result of rhs subtracted from lhs.
+ static Vector2 operator-(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Calculates the component-wise multiplication of two Vector2s and returns the
+ /// result.
+ ///
+ /// Vector2 to multiply with.
+ /// Another Vector2 to multiply with.
+ /// The result of rhs subtracted from lhs.
+ static Vector2 operator*(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Calculates the multiplication of a Vector2 with a scalar value and returns
+ /// the result.
+ ///
+ /// Vector2 to multiply with.
+ /// Scalar to multiply with.
+ /// The result of the scalar multiplication.
+ static Vector2 operator*(Vector2 lhs, double rhs);
+ ///
+ /// Calculates the division of a Vector2 with a scalar value and returns
+ /// the result.
+ ///
+ /// Scalar to divide with.
+ /// Vector2 to divide with.
+ /// The result of the scalar division.
+ static Vector2 operator/(Vector2 lhs, double rhs);
+ ///
+ /// Checks if two Vector2s are approximately equal. This is equivalent to
+ /// calling Vector2.IsNear() with default tolerance values.
+ ///
+ /// Vector2 to compare.
+ /// Another Vector2 to compare.
+ ///
+ /// True if all components are approximately equal within the default
+ /// tolerance value.
+ ///
+ static bool operator==(Vector2 lhs, Vector2 rhs);
+ ///
+ /// Checks if two Vector2s are not approximately equal. This is equivalent to
+ /// calling !Vector2.IsNear() with default tolerance values.
+ ///
+ /// Vector2 to compare.
+ /// Another Vector2 to compare.
+ ///
+ /// True if all components are not approximately equal within the default
+ /// tolerance value.
+ ///
+ static bool operator!=(Vector2 lhs, Vector2 rhs);
+ };
+}
diff --git a/SHADE_Managed/src/Math/Vector3.cxx b/SHADE_Managed/src/Math/Vector3.cxx
new file mode 100644
index 00000000..26ff5a72
--- /dev/null
+++ b/SHADE_Managed/src/Math/Vector3.cxx
@@ -0,0 +1,278 @@
+/************************************************************************************//*!
+\file Vector3.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 24, 2021
+\brief Contains the definitions of functions of the Vector3 struct.
+
+ 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 "Vector3.hxx"
+// Standard Libraries
+#include
+#include
+// Project Headers
+#include "Math.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Constructors */
+ /*---------------------------------------------------------------------------------*/
+ Vector3::Vector3(double _x)
+ : Vector3 {_x, 0.0, 0.0}
+ {}
+ Vector3::Vector3(double _x, double _y)
+ : Vector3 {_x, _y, 0.0}
+ {}
+ Vector3::Vector3(double _x, double _y, double _z)
+ : x { _x }
+ , y { _y }
+ , z { _z }
+ {}
+ Vector3::Vector3(Vector2 vec)
+ : Vector3(vec.x, vec.y)
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* Usage Functions */
+ /*---------------------------------------------------------------------------------*/
+ void Vector3::Normalise()
+ {
+ *this = GetNormalised();
+ }
+
+ Vector3 Vector3::GetNormalised()
+ {
+ return *this / GetSqrMagnitude();
+ }
+
+ double Vector3::GetMagnitude()
+ {
+ return sqrt(x * x + y * y + z * z);
+ }
+
+ double Vector3::GetSqrMagnitude()
+ {
+ return x * x + y * y + z * z;
+ }
+
+ double Vector3::Angle2DFromRightRadians()
+ {
+ return atan2(y, x);
+ }
+
+ double Vector3::Angle2DFromRightDegrees()
+ {
+ return Math::RadiansToDegrees(Angle2DFromRightRadians());
+ }
+
+ bool Vector3::IsNearPoint(Vector3 point)
+ {
+ return IsNearPoint(point, Math::Epsilon);
+ }
+
+ bool Vector3::IsNearPoint(Vector3 point, double tolerance)
+ {
+ return (*this - point).GetSqrMagnitude() < (tolerance * tolerance);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*---------------------------------------------------------------------------------*/
+ bool Vector3::Equals(Object^ o)
+ {
+ try
+ {
+ Vector3 vec = safe_cast(o);
+ return Equals(vec);
+ }
+ catch (System::InvalidCastException^)
+ {
+ return false;
+ }
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Object Overrides */
+ /*---------------------------------------------------------------------------------*/
+ bool Vector3::Equals(Vector3 other)
+ {
+ return IsNear(*this, other);
+ }
+ int Vector3::GetHashCode()
+ {
+ const int HASH = 19;
+ const int HASH2 = 23;
+ return x.GetHashCode() * HASH + y.GetHashCode() * HASH2 + z.GetHashCode();
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*---------------------------------------------------------------------------------*/
+ bool Vector3::IsNear(Vector3 lhs, Vector3 rhs)
+ {
+ return IsNear(lhs, rhs, Math::Epsilon);
+ }
+ bool Vector3::IsNear(Vector3 lhs, Vector3 rhs, double tolerance)
+ {
+ return (std::abs(lhs.x) - std::abs(rhs.x)) < tolerance
+ &&
+ (std::abs(lhs.y) - std::abs(rhs.y)) < tolerance
+ &&
+ (std::abs(lhs.z) - std::abs(rhs.z)) < tolerance;
+ }
+ double Vector3::Dot(Vector3 lhs, Vector3 rhs)
+ {
+ return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
+ }
+ Vector3 Vector3::Cross(Vector3 lhs, Vector3 rhs)
+ {
+ return Vector3(lhs.y * rhs.z - lhs.z * rhs.y,
+ lhs.z * rhs.x - lhs.x * rhs.z,
+ lhs.x * rhs.y - lhs.y * rhs.x);
+ }
+ Vector3 Vector3::Project(Vector3 vec, Vector3 direction)
+ {
+ return direction.GetNormalised() * vec.GetMagnitude();
+ }
+ Vector3 Vector3::Reflect(Vector3 vec, Vector3 normal)
+ {
+ return vec - (Project(vec, normal.GetNormalised()) * 2.0);
+ }
+ Vector3 Vector3::RotateRadians(Vector3 vec, double radians)
+ {
+ const double SINE = sin(radians);
+ const double COSINE = cos(radians);
+
+ return Vector3
+ (
+ vec.x * COSINE - vec.y * SINE,
+ vec.x * SINE + vec.y * COSINE,
+ vec.z
+ );
+ }
+ Vector3 Vector3::RotateDegrees(Vector3 vec, double degrees)
+ {
+ return RotateRadians(vec, Math::DegreesToRadians(degrees));
+ }
+ Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs)
+ {
+ double lx = lhs.x, rx = rhs.x;
+ double ly = lhs.y, ry = rhs.y;
+ double lz = lhs.z, rz = rhs.z;
+
+ return Vector3(std::min(lx, rx),
+ std::min(ly, ry),
+ std::min(lz, rz));
+ }
+ Vector3 Vector3::Max(Vector3 lhs, Vector3 rhs)
+ {
+ double lx = lhs.x, rx = rhs.x;
+ double ly = lhs.y, ry = rhs.y;
+ double lz = lhs.z, rz = rhs.z;
+
+ return Vector3(std::max(lx, rx),
+ std::max(ly, ry),
+ std::max(lz, rz));
+ }
+ Vector3 Vector3::Lerp(Vector3 a, Vector3 b, double t)
+ {
+ return LerpUnclamped(a, b, std::clamp(t, 0.0, 1.0));
+ }
+ Vector3 Vector3::LerpUnclamped(Vector3 a, Vector3 b, double t)
+ {
+ return a + ((b - a) * t);
+ }
+ Vector3 Vector3::MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta)
+ {
+ // Ignore if it is exactly on the same point
+ if (current == target)
+ return target;
+
+ // Calculate new position
+ Vector3 DELTA = (target - current).GetNormalised() * maxDistanceDelta;
+ Vector3 newPos = current + DELTA;
+
+ // Check if check if is behind or ahead of target
+ Vector3 DIFF = target - newPos;
+ if (Dot(DELTA, DIFF) < 0.0)
+ {
+ newPos = target;
+ }
+ return newPos;
+ }
+ Vector3 Vector3::operator+(Vector3 lhs, Vector3 rhs)
+ {
+ return Vector3
+ (
+ lhs.x + rhs.x,
+ lhs.y + rhs.y,
+ lhs.z + rhs.z
+ );
+ }
+ Vector3 Vector3::operator-(Vector3 lhs, Vector3 rhs)
+ {
+ return Vector3
+ (
+ lhs.x - rhs.x,
+ lhs.y - rhs.y,
+ lhs.z - rhs.z
+ );
+ }
+ Vector3 Vector3::operator*(Vector3 lhs, Vector3 rhs)
+ {
+ return Vector3
+ (
+ lhs.x * rhs.x,
+ lhs.y * rhs.y,
+ lhs.z * rhs.z
+ );
+ }
+ Vector3 Vector3::operator*(Vector3 lhs, double rhs)
+ {
+ return Vector3
+ (
+ lhs.x * rhs,
+ lhs.y * rhs,
+ lhs.z * rhs
+ );
+ }
+ Vector3 Vector3::operator/(Vector3 lhs, double rhs)
+ {
+ return Vector3
+ (
+ lhs.x / rhs,
+ lhs.y / rhs,
+ lhs.z / rhs
+ );
+ }
+ bool Vector3::operator==(Vector3 lhs, Vector3 rhs)
+ {
+ return lhs.Equals(rhs);
+ }
+ bool Vector3::operator!=(Vector3 lhs, Vector3 rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Conversion Operators */
+ /*---------------------------------------------------------------------------------*/
+ Vector3::operator Vector2(Vector3 vec)
+ {
+ return Vector2(vec.x, vec.y);
+ }
+
+ Vector3::operator Vector3(Vector2 vec)
+ {
+ return Vector3(vec);
+ }
+} // namespace PlushieAPI::Mathematics
\ No newline at end of file
diff --git a/SHADE_Managed/src/Math/Vector3.hxx b/SHADE_Managed/src/Math/Vector3.hxx
new file mode 100644
index 00000000..e6cdc7d4
--- /dev/null
+++ b/SHADE_Managed/src/Math/Vector3.hxx
@@ -0,0 +1,425 @@
+/************************************************************************************//*!
+\file Vector3.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 24, 2021
+\brief Contains the definitions of Vector3 struct.
+
+ 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
+
+// Standard Libraries
+#include
+// Project Includes
+#include "Vector2.hxx"
+
+namespace SHADE
+{
+ ///
+ /// CLR version of the the PlushieEngine's Vector3 class that represents a
+ /// 3-Dimensional Vector. Designed to closely match Unity's Vector3 struct.
+ ///
+ [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
+ public value struct Vector3 : public System::IEquatable
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Constants */
+ /*-----------------------------------------------------------------------------*/
+ #pragma region Constants
+ ///
+ /// Shorthand for writing Vector3(0, 0, -1).
+ ///
+ static initonly Vector3 Back = Vector3(0.0, 0.0, -1.0);
+ ///
+ /// Shorthand for writing Vector3(0, -1, 0).
+ ///
+ static initonly Vector3 Down = Vector3(0.0, -1.0, 0.0);
+ ///
+ /// Shorthand for writing Vector3(0, 0, 1).
+ ///
+ static initonly Vector3 Forward = Vector3(0.0, 0.0, 1.0);
+ ///
+ /// Shorthand for writing Vector3(-1, 0, 0).
+ ///
+ static initonly Vector3 Left = Vector3(-1.0, 0.0, 0.0);
+ ///
+ /// Shorthand for writing Vector3(double.NegativeInfinity,
+ /// double.NegativeInfinity, double.NegativeInfinity).
+ ///
+ static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits::lowest(),
+ std::numeric_limits::lowest(),
+ std::numeric_limits::lowest());
+ ///
+ /// Shorthand for writing Vector3(1, 1, 1).
+ ///
+ static initonly Vector3 One = Vector3(1.0, 1.0, 1.0);
+ ///
+ /// Shorthand for writing Vector3(double.PositiveInfinity,
+ /// double.PositiveInfinity, double.PositiveInfinity).
+ ///
+ static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits::max(),
+ std::numeric_limits::max(),
+ std::numeric_limits::max());
+ ///
+ /// Shorthand for writing Vector3(1, 0, 0).
+ ///
+ static initonly Vector3 Right = Vector3(1.0, 0.0, 0.0);
+ ///
+ /// Shorthand for writing Vector3(0, 1, 0).
+ ///
+ static initonly Vector3 Up = Vector3(0.0, 1.0, 0.0);
+ ///
+ /// Shorthand for writing Vector3(0, 0, 0).
+ ///
+ static initonly Vector3 Zero = Vector3(0.0, 0.0, 0.0);
+ #pragma endregion
+
+ /*-----------------------------------------------------------------------------*/
+ /* Public Members */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// X-component of the Vector3.
+ ///
+ double x;
+ ///
+ /// Y-component of the Vector3.
+ ///
+ double y;
+ ///
+ /// Z-component of the Vector3.
+ ///
+ double z;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Constructor to construct a Vector3 with the specified components with the
+ /// Y and Z-component set to 0.0.
+ ///
+ /// X-coordinate to set.
+ Vector3(double _x);
+ ///
+ /// Constructor to construct a Vector3 with the specified components with the
+ /// Z-component set to 0.0.
+ ///
+ /// X-coordinate to set.
+ /// Y-coordinate to set.
+ Vector3(double _x, double _y);
+ ///
+ /// Constructor to construct a Vector3 with the specified components.
+ ///
+ /// X-coordinate to set.
+ /// Y-coordinate to set.
+ /// Z-coordinate to set.
+ Vector3(double _x, double _y, double _z);
+ ///
+ /// Conversion constructor to construct a Vector3 using a Vector2.
+ ///
+ ///
+ Vector3(Vector2 vec);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Usage Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Normalises this current Vector3. This changes the data of this Vector3.
+ /// If you would like to get a copy, use GetNormalised() instead.
+ /// This function does nothing to a zero vector.
+ ///
+ void Normalise();
+ ///
+ /// Creates a copy of this Vector3 and returns a normalized version.
+ ///
+ ///
+ /// Returns a normalised copy of this Vector3.
+ /// If this Vector3 is a zero vector, a zero vector will be returned.
+ ///
+ Vector3 GetNormalised();
+ ///
+ /// Calculates and returns the magnitude of this Vector3. Note that this function
+ /// incurs a performance cost from the square root calculation. If you do not
+ /// need the precise magnitude, consider using GetSqrMagnitude() instead.
+ ///
+ /// Returns the length of this Vector3.
+ double GetMagnitude();
+ ///
+ /// Calculates and returns the squared magnitude of this Vector3.
+ ///
+ /// Returns the squared length of this Vector3.
+ double GetSqrMagnitude();
+ ///
+ /// Calculates and returns the angle of this vector from the right vector. This
+ /// function returns values between -Math.PI and Math.PI.
+ ///
+ /// Returns the angle of this vector from the right vector in radians.
+ double Angle2DFromRightRadians();
+ ///
+ /// Calculates and returns the angle of this vector from the right vector. This
+ /// function returns values between -180.0 and 180.0.
+ ///
+ /// Returns the angle of this vector from the right vector in degrees.
+ double Angle2DFromRightDegrees();
+ ///
+ /// Checks if a specified point is near this Vector3 that represents a point with
+ /// a tolerance value of PLS_EPSILON.
+ ///
+ /// The other point to check if we are near.
+ ///
+ /// True if this Vector3 representing a point and the specified point are within
+ /// the range of the specified tolerance. False otherwise.
+ ///
+ bool IsNearPoint(Vector3 point);
+ ///
+ /// Checks if a specified point is near this Vector3 that represents a point.
+ ///
+ /// The other point to check if we are near.
+ ///
+ /// The amount of tolerance before we consider these points as "near".
+ ///
+ ///
+ /// True if this Vector3 representing a point and the specified point are within
+ /// the range of the specified tolerance. False otherwise.
+ ///
+ bool IsNearPoint(Vector3 point, double tolerance);
+
+ /*-----------------------------------------------------------------------------*/
+ /* IEquatable */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with an object of the same type.
+ ///
+ /// The object to compare with.
+ /// True if both objects are the same.
+ virtual bool Equals(Vector3 other);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Object */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Compares equality with another unboxed object.
+ ///
+ /// The unboxed object to compare with.
+ /// True if both objects are the same.
+ bool Equals(Object^ o) override;
+ ///
+ /// Gets a unique hash for this object.
+ ///
+ /// Unique hash for this object.
+ int GetHashCode() override;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Static Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Checks if two specified Vector3s are near in value.
+ ///
+ /// Vector3 to check if is near in value.
+ /// Another Vector3 to check if is near in value.
+ ///
+ /// True if the two Vector3s are within the tolerance value specified
+ ///
+ static bool IsNear(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Checks if two specified Vector3s are near in value.
+ ///
+ /// Vector3 to check if is near in value.
+ /// Another Vector3 to check if is near in value.
+ /// Amount of tolerance to do the comparison with.
+ ///
+ /// True if the two Vector3s are within the tolerance value specified
+ ///
+ static bool IsNear(Vector3 lhs, Vector3 rhs, double tolerance);
+ ///
+ /// Computes and returns the dot product of 2 specified Vector3s.
+ ///
+ /// Vector3 to calculate dot product with.
+ /// Another Vector3 to calculate dot product with.
+ /// Scalar value representing the dot product of the two Vector3s.
+ static double Dot(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Computes and returns the cross product of 2 specified Vector3s.
+ ///
+ /// Vector3 to calculate cross product with.
+ /// Another Vector3 to calculate cross product with.
+ /// The cross product of the two Vector3s.
+ static Vector3 Cross(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Computes and returns a Vector3 projection.
+ ///
+ /// Vector3 to project.
+ /// Vector3 to project onto.
+ /// The Vector3 that represents the projected vec onto direction.
+ static Vector3 Project(Vector3 vec, Vector3 direction);
+ ///
+ /// Reflects a Vector3 across another Vector3.
+ ///
+ /// A Vector3 to reflect.
+ /// A normal to reflect the Vector3 across.
+ /// The Vector3 that represents vec reflected across normal.
+ static Vector3 Reflect(Vector3 vec, Vector3 normal);
+ ///
+ /// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise
+ /// direction.
+ ///
+ /// A Vector3 to rotate.
+ ///
+ /// Angle to rotate the vector by in an anti-clockwise direction in radians.
+ ///
+ /// The Vector3 that represents the rotated vector.
+ static Vector3 RotateRadians(Vector3 vec, double radians);
+ ///
+ /// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise
+ /// direction.
+ ///
+ /// A Vector3 to rotate.
+ ///
+ /// Angle to rotate the vector by in an anti-clockwise direction in degrees.
+ ///
+ /// The Vector3 that represents the rotated vector.
+ static Vector3 RotateDegrees(Vector3 vec, double degrees);
+ ///
+ /// Computes and returns a Vector3 that is made from the smallest components of
+ /// the two specified Vector3s.
+ ///
+ /// Vector3 to calculate minimum Vector3 with.
+ /// Another Vector3 to calculate minimum Vector3 with.
+ ///
+ /// The Vector3 that contains the smallest components of the two specified
+ /// Vector3s.
+ ///
+ static Vector3 Min(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Computes and returns a Vector3 that is made from the largest components of
+ /// the two specified Vector3s.
+ ///
+ /// Vector3 to calculate maximum Vector3 with.
+ /// Another Vector3 to calculate maximum Vector3 with.
+ ///
+ /// The Vector3 that contains the largest components of the two specified
+ /// Vector3s.
+ ///
+ static Vector3 Max(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Linearly interpolates between two specified points.
+ /// This is most commonly used to find a point some fraction of the way along a
+ /// line between two endpoints.
+ ///
+ /// The start Vector3, returned when t = 0.0.
+ /// The end Vector3, returned when t = 1.0.
+ ///
+ /// Value used to interpolate between a and b which is clamped to
+ /// the range[0, 1].
+ ///
+ /// The interpolated Vector3.
+ static Vector3 Lerp(Vector3 a, Vector3 b, double t);
+ ///
+ /// Linearly interpolates between two specified points.
+ /// This is most commonly used to find a point some fraction of the way along a
+ /// line between two endpoints.
+ /// Unlike Lerp(), t is not clamped to a range at all.
+ ///
+ /// The start Vector3, returned when t = 0.0.
+ /// The end Vector3, returned when t = 1.0.
+ /// Value used to interpolate between a and b.
+ /// The interpolated Vector3.
+ static Vector3 LerpUnclamped(Vector3 a, Vector3 b, double t);
+ ///
+ /// Moves a point current towards target.
+ /// Similar to Lerp(), however, the function will ensure that the distance never
+ /// exceeds maxDistanceDelta. Negative values of maxDistanceDelta pushes the
+ /// vector away from target
+ ///
+ /// The current position of the point.
+ /// The target position to move to.
+ /// Maximum distance moved per call.
+ /// Vector representing the moved point.
+ static Vector3 MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Overloaded Operators */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Adds two Vector3s together and returns the result.
+ ///
+ /// Vector3 to add.
+ /// Another Vector3 to add.
+ /// The result of lhs added to rhs
+ static Vector3 operator+(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Subtracts a Vector3 from another Vector3 and returns the result.
+ ///
+ /// Vector3 to subtract from.
+ /// Another Vector3 to subtract.
+ /// The result of rhs subtracted from lhs.
+ static Vector3 operator-(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Calculates the component-wise multiplication of two Vector3s and returns the
+ /// result.
+ ///
+ /// Vector3 to multiply with.
+ /// Another Vector3 to multiply with.
+ /// The result of rhs subtracted from lhs.
+ static Vector3 operator*(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Calculates the multiplication of a Vector3 with a scalar value and returns
+ /// the result.
+ ///
+ /// Vector3 to multiply with.
+ /// Scalar to multiply with.
+ /// The result of the scalar multiplication.
+ static Vector3 operator*(Vector3 lhs, double rhs);
+ ///
+ /// Calculates the division of a Vector3 with a scalar value and returns
+ /// the result.
+ ///
+ /// Scalar to divide with.
+ /// Vector3 to divide with.
+ /// The result of the scalar division.
+ static Vector3 operator/(Vector3 lhs, double rhs);
+ ///
+ /// Checks if two Vector3s are approximately equal. This is equivalent to
+ /// calling Vector3.IsNear() with default tolerance values.
+ ///
+ /// Vector3 to compare.
+ /// Another Vector3 to compare.
+ ///
+ /// True if all components are approximately equal within the default
+ /// tolerance value.
+ ///
+ static bool operator==(Vector3 lhs, Vector3 rhs);
+ ///
+ /// Checks if two Vector3s are not approximately equal. This is equivalent to
+ /// calling !Vector3.IsNear() with default tolerance values.
+ ///
+ /// Vector3 to compare.
+ /// Another Vector3 to compare.
+ ///
+ /// True if all components are not approximately equal within the default
+ /// tolerance value.
+ ///
+ static bool operator!=(Vector3 lhs, Vector3 rhs);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Conversion Operators */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Explicit conversion operator to enable explicit casting from a Vector3 to a
+ /// Vector2.
+ ///
+ /// Vector3 to convert from.
+ static explicit operator Vector2(Vector3 vec);
+ ///
+ /// Explicit conversion operator to enable explicit casting from a Vector2 to a
+ /// Vector3.
+ ///
+ /// Vector2 to convert from.
+ static explicit operator Vector3(Vector2 vec);
+ };
+} // namespace PlushieAPI::Mathematics
diff --git a/SHADE_Managed/src/SHpch.cpp b/SHADE_Managed/src/SHpch.cpp
new file mode 100644
index 00000000..2a36c693
--- /dev/null
+++ b/SHADE_Managed/src/SHpch.cpp
@@ -0,0 +1,10 @@
+/****************************************************************************************
+ * \file SHpch.h
+ * \brief Empty source file for generating SHADE Engine's precompiled header.
+ *
+ * \copyright 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"
\ No newline at end of file
diff --git a/SHADE_Managed/src/SHpch.h b/SHADE_Managed/src/SHpch.h
new file mode 100644
index 00000000..b54a8a5b
--- /dev/null
+++ b/SHADE_Managed/src/SHpch.h
@@ -0,0 +1,31 @@
+/****************************************************************************************
+ * \file SHpch.h
+ * \brief Precompiled header file for SHADE Engine.
+ *
+ * \copyright 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.
+****************************************************************************************/
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+// C RunTime Header Files
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include