Integration of .NET Scripting Backend #23

Merged
Pycorax merged 34 commits from SP3-6-c-scripting into main 2022-09-15 12:31:30 +08:00
53 changed files with 6886 additions and 15 deletions

View File

@ -17,10 +17,11 @@ echo "J - tracy"
echo "K - RTTR" echo "K - RTTR"
echo "L - yamlcpp" echo "L - yamlcpp"
echo "M - SDL" echo "M - SDL"
echo "N - dotnet"
echo --------------------------------------------------- echo ---------------------------------------------------
echo. echo.
choice /C ABCDEFGHIJKLM /T 10 /D A choice /C ABCDEFGHIJKLMN /T 10 /D A
set _e=%ERRORLEVEL% set _e=%ERRORLEVEL%
if %_e%==1 goto VMA if %_e%==1 goto VMA
@ -36,6 +37,7 @@ if %_e%==10 goto tracy
if %_e%==11 goto RTTR if %_e%==11 goto RTTR
if %_e%==12 goto yamlcpp if %_e%==12 goto yamlcpp
if %_e%==13 goto SDL if %_e%==13 goto SDL
if %_e%==14 goto dotnet
:VMA :VMA
echo -----------------------VMA---------------------------- echo -----------------------VMA----------------------------
@ -53,7 +55,7 @@ if %_e%==3 (goto :done) else (goto :assimp)
echo -----------------------assimp---------------------------- echo -----------------------assimp----------------------------
rmdir "Dependencies/assimp" /S /Q rmdir "Dependencies/assimp" /S /Q
git clone https://github.com/SHADE-DP/assimp.git "Dependencies/assimp" 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 :ktx
@REM rmdir "Dependencies/ktx" /S /Q @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 robocopy "Dependencies/SDL/tmp/SDL2-2.24.0/include/" "Dependencies/SDL/include/" /ns /nfl /ndl /nc /njh
rmdir "Dependencies/SDL/tmp/" /s /q rmdir "Dependencies/SDL/tmp/" /s /q
powershell -Command "& {Remove-Item "Dependencies/SDL/SDL.zip"}" 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 :done
echo DONE! echo DONE!

View File

@ -13,3 +13,4 @@ IncludeDir["RTTR"] = "%{wks.location}/Dependencies/RTTR"
IncludeDir["reactphysics3d"] = "%{wks.location}/Dependencies/reactphysics3d" IncludeDir["reactphysics3d"] = "%{wks.location}/Dependencies/reactphysics3d"
IncludeDir["SDL"] = "%{wks.location}/Dependencies/SDL" IncludeDir["SDL"] = "%{wks.location}/Dependencies/SDL"
IncludeDir["VULKAN"] = "$(VULKAN_SDK)" IncludeDir["VULKAN"] = "$(VULKAN_SDK)"
IncludeDir["dotnet"] = "%{wks.location}/Dependencies/dotnet"

View File

@ -26,6 +26,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SHADE_Engine", "SHADE_Engin
{C0FF640D-2C14-8DBE-F595-301E616989EF} = {C0FF640D-2C14-8DBE-F595-301E616989EF} {C0FF640D-2C14-8DBE-F595-301E616989EF} = {C0FF640D-2C14-8DBE-F595-301E616989EF}
EndProjectSection EndProjectSection
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 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}.Debug|x64.Build.0 = Debug|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Release|x64.ActiveCfg = Release|x64 {3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Release|x64.ActiveCfg = Release|x64
{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}.Release|x64.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -61,7 +61,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;..\Dependencies\dotnet\include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
@ -84,7 +84,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PreprocessorDefinitions>_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\Dependencies\spdlog\include;..\SHADE_Engine\src;src;..\Dependencies\dotnet\include;..\Dependencies\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
@ -120,6 +120,9 @@
<ProjectReference Include="..\SHADE_Engine\SHADE_Engine.vcxproj"> <ProjectReference Include="..\SHADE_Engine\SHADE_Engine.vcxproj">
<Project>{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}</Project> <Project>{3F92E998-2BF5-783D-D47A-B1F3C0BC44C0}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\SHADE_Managed\SHADE_Managed.vcxproj">
<Project>{16DB1400-829B-9036-4BD6-D9B3B755D512}</Project>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -37,6 +37,7 @@ project "SHADE_Application"
links links
{ {
"SHADE_Engine", "SHADE_Engine",
"SHADE_Managed",
"SDL2.lib", "SDL2.lib",
"SDL2main.lib" "SDL2main.lib"
} }

View File

@ -14,6 +14,8 @@
#include <ctime> #include <ctime>
#include <SDL.h> #include <SDL.h>
#include "Scripting/SHScriptEngine.h"
namespace Sandbox namespace Sandbox
{ {
bool paused = false; bool paused = false;
@ -36,6 +38,8 @@ namespace Sandbox
#else #else
#endif #endif
// Set up scripting
SHADE::SHScriptEngine::Init();
} }
void SBApplication::Update(void) void SBApplication::Update(void)
@ -52,6 +56,9 @@ namespace Sandbox
void SBApplication::Exit(void) void SBApplication::Exit(void)
{ {
// Shutdown scripting
SHADE::SHScriptEngine::Exit();
SDL_DestroyWindow(sdlWindow); SDL_DestroyWindow(sdlWindow);
#ifdef SHEDITOR #ifdef SHEDITOR
#else #else

View File

@ -61,7 +61,7 @@
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;SH_API_EXPORT;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;SH_API_EXPORT;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<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;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <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)</AdditionalIncludeDirectories>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
@ -78,7 +78,8 @@
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>xcopy /s /r /y /q "$(SolutionDir)/Dependencies/spdlog/bin" "$(OutDir)" <Command>xcopy /s /r /y /q "$(SolutionDir)/Dependencies/spdlog/bin" "$(OutDir)"
xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"</Command> xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
xcopy /s /r /y /q "$(SolutionDir)/Dependencies/dotnet/bin" "$(OutDir)"</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -88,7 +89,7 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"</Comm
<WarningLevel>Level4</WarningLevel> <WarningLevel>Level4</WarningLevel>
<DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4251;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;SH_API_EXPORT;_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_LIB;_GLFW_INCLUDE_NONE;MSDFGEN_USE_CPP11;NOMINMAX;SH_API_EXPORT;_RELEASE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<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;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <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)</AdditionalIncludeDirectories>
<Optimization>Full</Optimization> <Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
@ -108,7 +109,8 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"</Comm
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>xcopy /s /r /y /q "$(SolutionDir)/Dependencies/spdlog/bin" "$(OutDir)" <Command>xcopy /s /r /y /q "$(SolutionDir)/Dependencies/spdlog/bin" "$(OutDir)"
xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"</Command> xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"
xcopy /s /r /y /q "$(SolutionDir)/Dependencies/dotnet/bin" "$(OutDir)"</Command>
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@ -185,6 +187,7 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"</Comm
<ClInclude Include="src\Graphics\Windowing\Surface\SHVkSurface.h" /> <ClInclude Include="src\Graphics\Windowing\Surface\SHVkSurface.h" />
<ClInclude Include="src\Math\SHMath.h" /> <ClInclude Include="src\Math\SHMath.h" />
<ClInclude Include="src\Math\SHMathHelpers.h" /> <ClInclude Include="src\Math\SHMathHelpers.h" />
<ClInclude Include="src\Math\SHMathHelpers.hpp" />
<ClInclude Include="src\Math\SHMatrix.h" /> <ClInclude Include="src\Math\SHMatrix.h" />
<ClInclude Include="src\Math\SHQuaternion.h" /> <ClInclude Include="src\Math\SHQuaternion.h" />
<ClInclude Include="src\Math\Vector\SHVec2.h" /> <ClInclude Include="src\Math\Vector\SHVec2.h" />
@ -192,19 +195,28 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"</Comm
<ClInclude Include="src\Math\Vector\SHVec4.h" /> <ClInclude Include="src\Math\Vector\SHVec4.h" />
<ClInclude Include="src\Meta\SHIsDetected.h" /> <ClInclude Include="src\Meta\SHIsDetected.h" />
<ClInclude Include="src\Resource\Handle.h" /> <ClInclude Include="src\Resource\Handle.h" />
<ClInclude Include="src\Resource\Handle.hpp" />
<ClInclude Include="src\Resource\ResourceLibrary.h" /> <ClInclude Include="src\Resource\ResourceLibrary.h" />
<ClInclude Include="src\Resource\ResourceLibrary.hpp" />
<ClInclude Include="src\Resource\SparseSet.h" /> <ClInclude Include="src\Resource\SparseSet.h" />
<ClInclude Include="src\Resource\SparseSet.hpp" />
<ClInclude Include="src\SHCommonTypes.h" /> <ClInclude Include="src\SHCommonTypes.h" />
<ClInclude Include="src\SH_API.h" /> <ClInclude Include="src\SH_API.h" />
<ClInclude Include="src\SHpch.h" /> <ClInclude Include="src\SHpch.h" />
<ClInclude Include="src\Scene\SHScene.h" /> <ClInclude Include="src\Scene\SHScene.h" />
<ClInclude Include="src\Scene\SHSceneGraph.h" /> <ClInclude Include="src\Scene\SHSceneGraph.h" />
<ClInclude Include="src\Scene\SHSceneManager.h" /> <ClInclude Include="src\Scene\SHSceneManager.h" />
<ClInclude Include="src\Scripting\SHDotNetRuntime.h" />
<ClInclude Include="src\Scripting\SHDotNetRuntime.hpp" />
<ClInclude Include="src\Scripting\SHScriptEngine.h" />
<ClInclude Include="src\Tools\SHException.h" /> <ClInclude Include="src\Tools\SHException.h" />
<ClInclude Include="src\Tools\SHExceptionHandler.h" /> <ClInclude Include="src\Tools\SHExceptionHandler.h" />
<ClInclude Include="src\Tools\SHFileUtilties.h" /> <ClInclude Include="src\Tools\SHFileUtilties.h" />
<ClInclude Include="src\Tools\SHLogger.h" /> <ClInclude Include="src\Tools\SHLogger.h" />
<ClInclude Include="src\Tools\SHStringUtils.h" />
<ClInclude Include="src\Tools\SHStringUtils.hpp" />
<ClInclude Include="src\Tools\SHUtilities.h" /> <ClInclude Include="src\Tools\SHUtilities.h" />
<ClInclude Include="src\Tools\SHUtilities.hpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\ECS_Base\Components\SHComponent.cpp" /> <ClCompile Include="src\ECS_Base\Components\SHComponent.cpp" />
@ -274,10 +286,13 @@ xcopy /r /y /q "$(SolutionDir)/Dependencies/SDL/lib/SDL2.dll" "$(OutDir)"</Comm
</ClCompile> </ClCompile>
<ClCompile Include="src\Scene\SHSceneGraph.cpp" /> <ClCompile Include="src\Scene\SHSceneGraph.cpp" />
<ClCompile Include="src\Scene\SHSceneManager.cpp" /> <ClCompile Include="src\Scene\SHSceneManager.cpp" />
<ClCompile Include="src\Scripting\SHDotNetRuntime.cpp" />
<ClCompile Include="src\Scripting\SHScriptEngine.cpp" />
<ClCompile Include="src\Tools\SHException.cpp" /> <ClCompile Include="src\Tools\SHException.cpp" />
<ClCompile Include="src\Tools\SHExceptionHandler.cpp" /> <ClCompile Include="src\Tools\SHExceptionHandler.cpp" />
<ClCompile Include="src\Tools\SHFileUtilties.cpp" /> <ClCompile Include="src\Tools\SHFileUtilties.cpp" />
<ClCompile Include="src\Tools\SHLogger.cpp" /> <ClCompile Include="src\Tools\SHLogger.cpp" />
<ClCompile Include="src\Tools\SHStringUtils.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj"> <ProjectReference Include="..\Dependencies\yamlcpp\yaml-cpp.vcxproj">

View File

@ -115,6 +115,9 @@
<Filter Include="Scene"> <Filter Include="Scene">
<UniqueIdentifier>{B3F7140E-1F0C-3DBF-E88D-E01E546139F0}</UniqueIdentifier> <UniqueIdentifier>{B3F7140E-1F0C-3DBF-E88D-E01E546139F0}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Scripting">
<UniqueIdentifier>{985A7358-04C5-27CF-4D03-D974B9AC0524}</UniqueIdentifier>
</Filter>
<Filter Include="Tools"> <Filter Include="Tools">
<UniqueIdentifier>{16CF2D0E-82E3-55BF-4B65-F91EB73852F0}</UniqueIdentifier> <UniqueIdentifier>{16CF2D0E-82E3-55BF-4B65-F91EB73852F0}</UniqueIdentifier>
</Filter> </Filter>
@ -339,6 +342,9 @@
<ClInclude Include="src\Math\SHMathHelpers.h"> <ClInclude Include="src\Math\SHMathHelpers.h">
<Filter>Math</Filter> <Filter>Math</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Math\SHMathHelpers.hpp">
<Filter>Math</Filter>
</ClInclude>
<ClInclude Include="src\Math\SHMatrix.h"> <ClInclude Include="src\Math\SHMatrix.h">
<Filter>Math</Filter> <Filter>Math</Filter>
</ClInclude> </ClInclude>
@ -360,12 +366,21 @@
<ClInclude Include="src\Resource\Handle.h"> <ClInclude Include="src\Resource\Handle.h">
<Filter>Resource</Filter> <Filter>Resource</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Resource\Handle.hpp">
<Filter>Resource</Filter>
</ClInclude>
<ClInclude Include="src\Resource\ResourceLibrary.h"> <ClInclude Include="src\Resource\ResourceLibrary.h">
<Filter>Resource</Filter> <Filter>Resource</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Resource\ResourceLibrary.hpp">
<Filter>Resource</Filter>
</ClInclude>
<ClInclude Include="src\Resource\SparseSet.h"> <ClInclude Include="src\Resource\SparseSet.h">
<Filter>Resource</Filter> <Filter>Resource</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Resource\SparseSet.hpp">
<Filter>Resource</Filter>
</ClInclude>
<ClInclude Include="src\SHCommonTypes.h" /> <ClInclude Include="src\SHCommonTypes.h" />
<ClInclude Include="src\SH_API.h" /> <ClInclude Include="src\SH_API.h" />
<ClInclude Include="src\SHpch.h" /> <ClInclude Include="src\SHpch.h" />
@ -378,6 +393,15 @@
<ClInclude Include="src\Scene\SHSceneManager.h"> <ClInclude Include="src\Scene\SHSceneManager.h">
<Filter>Scene</Filter> <Filter>Scene</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Scripting\SHDotNetRuntime.h">
<Filter>Scripting</Filter>
</ClInclude>
<ClInclude Include="src\Scripting\SHDotNetRuntime.hpp">
<Filter>Scripting</Filter>
</ClInclude>
<ClInclude Include="src\Scripting\SHScriptEngine.h">
<Filter>Scripting</Filter>
</ClInclude>
<ClInclude Include="src\Tools\SHException.h"> <ClInclude Include="src\Tools\SHException.h">
<Filter>Tools</Filter> <Filter>Tools</Filter>
</ClInclude> </ClInclude>
@ -390,9 +414,18 @@
<ClInclude Include="src\Tools\SHLogger.h"> <ClInclude Include="src\Tools\SHLogger.h">
<Filter>Tools</Filter> <Filter>Tools</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Tools\SHStringUtils.h">
<Filter>Tools</Filter>
</ClInclude>
<ClInclude Include="src\Tools\SHStringUtils.hpp">
<Filter>Tools</Filter>
</ClInclude>
<ClInclude Include="src\Tools\SHUtilities.h"> <ClInclude Include="src\Tools\SHUtilities.h">
<Filter>Tools</Filter> <Filter>Tools</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Tools\SHUtilities.hpp">
<Filter>Tools</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\ECS_Base\Components\SHComponent.cpp"> <ClCompile Include="src\ECS_Base\Components\SHComponent.cpp">
@ -588,6 +621,12 @@
<ClCompile Include="src\Scene\SHSceneManager.cpp"> <ClCompile Include="src\Scene\SHSceneManager.cpp">
<Filter>Scene</Filter> <Filter>Scene</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Scripting\SHDotNetRuntime.cpp">
<Filter>Scripting</Filter>
</ClCompile>
<ClCompile Include="src\Scripting\SHScriptEngine.cpp">
<Filter>Scripting</Filter>
</ClCompile>
<ClCompile Include="src\Tools\SHException.cpp"> <ClCompile Include="src\Tools\SHException.cpp">
<Filter>Tools</Filter> <Filter>Tools</Filter>
</ClCompile> </ClCompile>
@ -600,5 +639,8 @@
<ClCompile Include="src\Tools\SHLogger.cpp"> <ClCompile Include="src\Tools\SHLogger.cpp">
<Filter>Tools</Filter> <Filter>Tools</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Tools\SHStringUtils.cpp">
<Filter>Tools</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -12,6 +12,7 @@ project "SHADE_Engine"
files files
{ {
"%{prj.location}/src/**.h", "%{prj.location}/src/**.h",
"%{prj.location}/src/**.hpp",
"%{prj.location}/src/**.c", "%{prj.location}/src/**.c",
"%{prj.location}/src/**.cpp", "%{prj.location}/src/**.cpp",
"%{prj.location}/src/**.glsl", "%{prj.location}/src/**.glsl",
@ -35,7 +36,8 @@ project "SHADE_Engine"
"%{IncludeDir.RTTR}/include", "%{IncludeDir.RTTR}/include",
"%{IncludeDir.reactphysics3d}/include", "%{IncludeDir.reactphysics3d}/include",
"%{IncludeDir.VULKAN}/include", "%{IncludeDir.VULKAN}/include",
"%{IncludeDir.VULKAN}/Source/SPIRV-Reflect" "%{IncludeDir.VULKAN}/Source/SPIRV-Reflect",
"%{IncludeDir.dotnet}/include",
} }
libdirs libdirs
@ -60,7 +62,7 @@ project "SHADE_Engine"
"SDL2.lib", "SDL2.lib",
"SDL2main.lib", "SDL2main.lib",
"shaderc_shared.lib", "shaderc_shared.lib",
"shlwapi" "shlwapi.lib"
} }
disablewarnings disablewarnings
@ -94,7 +96,8 @@ project "SHADE_Engine"
postbuildcommands postbuildcommands
{ {
"xcopy /s /r /y /q \"%{IncludeDir.spdlog}/bin\" \"$(OutDir)\"", "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' warnings 'Extra'

View File

@ -28,7 +28,7 @@ namespace SHADE
//SHEntityManager::RemoveEntity(this->entityID); //SHEntityManager::RemoveEntity(this->entityID);
} }
EntityID SHEntity::GetEID() noexcept EntityID SHEntity::GetEID() const noexcept
{ {
return this->entityID; return this->entityID;
} }

View File

@ -78,7 +78,7 @@ namespace SHADE
* \return uint32_t * \return uint32_t
* The entityID of this Entity object. * The entityID of this Entity object.
***************************************************************************/ ***************************************************************************/
EntityID GetEID() noexcept; EntityID GetEID() const noexcept;
/*!************************************************************************* /*!*************************************************************************
* \brief Set the Active object * \brief Set the Active object

View File

@ -0,0 +1,198 @@
/*************************************************************************************//*!
\file SHDotNetRuntime.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 2, 2021
\brief Contains the definition of the SHDotNetRuntime class.
Implementation of code to set up code for SHDotNetRuntime is based on the
following repository:
https://github.com/mjrousos/SampleCoreCLRHost
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//**************************************************************************************/
// Precompiled Header
#include <SHpch.h>
// Primary Header
#include "SHDotNetRuntime.h"
// Standard Library
#include <array>
// External Dependencies
#include <shlwapi.h> // PathRemoveFileSpecA
#include "Tools/SHLogger.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*---------------------------------------------------------------------------------*/
SHDotNetRuntime::SHDotNetRuntime(bool autoInit)
{
if (autoInit)
{
Init();
}
}
SHDotNetRuntime::~SHDotNetRuntime()
{
if (IsLoaded())
{
try
{
Exit();
}
catch (std::runtime_error& e)
{
SHLOG_ERROR(e.what());
}
}
}
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void SHDotNetRuntime::Init()
{
// State checking, in case there was an unload before, we must ensure that the state is valid
if (initialised)
throw std::runtime_error("[DotNetRuntime] Failed to initialise as it was already initialised or was deinitialised into an invalid state.");
// Get the current executable directory
std::string runtimePath(MAX_PATH, '\0');
GetModuleFileNameA(nullptr, runtimePath.data(), MAX_PATH);
PathRemoveFileSpecA(runtimePath.data());
// Since PathRemoveFileSpecA() removes from data(), the size is not updated, so we must manually update it
runtimePath.resize(std::strlen(runtimePath.data()));
// Do not need to load the library if it was previously loaded
if (coreClr == nullptr)
{
// Construct the CoreCLR path
std::string coreClrPath(runtimePath); // Works
coreClrPath += "\\coreclr.dll";
// Load the CoreCLR DLL
coreClr = LoadLibraryExA(coreClrPath.c_str(), nullptr, 0);
if (!coreClr)
{
std::ostringstream oss;
oss << "[DotNetRuntime] Error #" << GetLastError() << " Failed to load CoreCLR from \"" << coreClrPath << "\"\n";
throw std::runtime_error(oss.str());
}
// Step 2: Get CoreCLR hosting functions
initializeCoreClr = getCoreClrFunctionPtr<coreclr_initialize_ptr>("coreclr_initialize");
createManagedDelegate = getCoreClrFunctionPtr<coreclr_create_delegate_ptr>("coreclr_create_delegate");
shutdownCoreClr = getCoreClrFunctionPtr<coreclr_shutdown_ptr>("coreclr_shutdown");
}
// Step 3: Construct AppDomain properties used when starting the runtime
// Construct the trusted platform assemblies (TPA) list
// This is the list of assemblies that .NET Core can load as
// trusted system assemblies (similar to the .NET Framework GAC).
// For this host (as with most), assemblies next to CoreCLR will
// be included in the TPA list
std::string tpaList = buildTpaList(runtimePath);
// Define CoreCLR properties
std::array propertyKeys =
{
"TRUSTED_PLATFORM_ASSEMBLIES", // Trusted assemblies (like the GAC)
"APP_PATHS", // Directories to probe for application assemblies
// "APP_NI_PATHS", // Directories to probe for application native images (not used in this sample)
// "NATIVE_DLL_SEARCH_DIRECTORIES", // Directories to probe for native dlls (not used in this sample)
};
std::array propertyValues =
{
tpaList.c_str(),
runtimePath.c_str()
};
// Step 4: Start the CoreCLR runtime
int result = initializeCoreClr
(
runtimePath.c_str(), // AppDomain base path
"SHADEHost", // AppDomain friendly name
static_cast<int>(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());
}
}
}

View File

@ -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 <iomanip> // std::setfill, std::setw
#include <stdexcept> // std::runtime_error
#include <string> // std::string
#include <sstream> // std::ostringstream
// External Dependencies
#include <Windows.h> // HMODULE
#include <coreclrhost.h> // coreclr_*
namespace SHADE
{
/*************************************************************************************/
/*!
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<typename FunctionType>
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<typename FunctionType>
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"

View File

@ -0,0 +1,61 @@
/*************************************************************************************//*!
\file SHDotNetRuntime.hpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 2, 2021
\brief Contains the implementation of the template functions of the
DotNetRuntime class.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//**************************************************************************************/
#pragma once
// Primary Include
#include "SHDotNetRuntime.h"
namespace SHADE
{
template<typename FunctionType>
FunctionType SHDotNetRuntime::GetFunctionPtr(const std::string_view & assemblyName,
const std::string_view & typeName,
const std::string_view & functionName) const
{
FunctionType managedDelegate = nullptr;
int result = createManagedDelegate
(
hostHandle,
domainId,
assemblyName.data(),
typeName.data(),
functionName.data(),
reinterpret_cast<void**>(&managedDelegate)
);
// Check if it failed
if (result < 0)
{
std::ostringstream oss;
oss << std::hex << std::setfill('0') << std::setw(8)
<< "[DotNetRuntime] Failed to get pointer to function \""
<< typeName << "." << functionName << "\" in assembly (" << assemblyName << "). "
<< "Error 0x" << result << "\n";
throw std::runtime_error(oss.str());
}
return managedDelegate;
}
template<typename FunctionType>
FunctionType SHDotNetRuntime::getCoreClrFunctionPtr(const std::string& functionName)
{
FunctionType fPtr = reinterpret_cast<FunctionType>(GetProcAddress(coreClr, functionName.c_str()));
if (!fPtr)
{
std::ostringstream oss;
oss << "[DotNetRuntime] Unable to get pointer to function: \"" << functionName << "\"";
throw std::runtime_error(oss.str());
}
return fPtr;
}
}

View File

@ -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 <SHpch.h>
// Primary Header
#include "SHScriptEngine.h"
// Standard Library
#include <fstream> // std::fstream
#include <filesystem> // std::filesystem::canonical, std::filesystem::remove
// Project Headers
#include "Tools/SHLogger.h"
#include "Tools/SHStringUtils.h"
namespace SHADE
{
/*--------------------------------------------------------------------------------*/
/* Static Definitions */
/*--------------------------------------------------------------------------------*/
const std::string SHScriptEngine::DEFAULT_CSHARP_NAMESPACE = std::string("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<char> buffer { new char[BUFFER_SIZE] };
std::memset(buffer.get(), 0, BUFFER_SIZE);
// Attempt to serialise the script
std::string result;
if (csScriptsSerialise(entity.GetEID(), buffer.get(), BUFFER_SIZE))
{
result = std::string(buffer.get());
}
else
{
SHLOG_ERROR("[ScriptEngine] Failed to serialise scripts as string buffer is too small!");
}
// Return an empty string since we failed to serialise
return result;
}
/*---------------------------------------------------------------------------------*/
/* Script Serialisation Functions */
/*---------------------------------------------------------------------------------*/
void SHScriptEngine::DeserialiseScript(const SHEntity& entity, const std::string& yaml)
{
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 =
"<Project Sdk=\"Microsoft.NET.Sdk\">\n\
<PropertyGroup>\n\
<TargetFramework>net6.0</TargetFramework>\n\
<Platforms>x64</Platforms>\n\
<Configurations>Release;Debug</Configurations>\n\
</PropertyGroup>\n\
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n\
<OutputPath>.\\bin_Release-x64</OutputPath>\n\
<PlatformTarget>x64</PlatformTarget>\n\
</PropertyGroup>\n\
<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\"> \n\
<OutputPath>.\\bin_Debug-x64</OutputPath>\n\
<PlatformTarget>x64</PlatformTarget>\n\
<DefineConstants>DEBUG;TRACE</DefineConstants>\n\
<Optimize>false</Optimize>\n\
<DebugType>full</DebugType>\n\
<DebugSymbols>true</DebugSymbols>\n\
</PropertyGroup>\n\
<ItemGroup>\n\
<Compile Remove=\"bin\\**\" />\n\
<EmbeddedResource Remove=\"Assets\\**\" />\n\
<EmbeddedResource Remove=\"bin\\**\" />\n\
<None Remove=\"bin\\**\" />\n\
</ItemGroup>\n\
<ItemGroup>\n\
<None Remove=\".gitignore\" />\n\
<None Remove=\".gitmodules\" />\n\
</ItemGroup>\n\
<ItemGroup>\n\
<Reference Include=\"SHADE_Managed\">\n\
<HintPath>.\\bin\\SHADE_Managed.dll</HintPath>\n\
</Reference>\n\
</ItemGroup>\n\
</Project>";
// Attempt to create the file
std::ofstream file(path);
if (!file.is_open())
throw std::runtime_error("Unable to create CsProj file!");
// Fill the file
file << FILE_CONTENTS;
// Close
file.close();
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void SHScriptEngine::loadFunctions()
{
std::ostringstream oss;
oss << "[ScriptEngine] Loading \"" << DEFAULT_CSHARP_LIB_NAME << "\" CLR library.";
SHLOG_INFO(oss.str());
// Load functions
csEngineInit = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"Init"
);
csEngineLoadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"LoadScriptAssembly"
);
csEngineUnloadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"UnloadScriptAssembly"
);
csEngineReloadScripts = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"ReloadScriptAssembly"
);
csEngineExit = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".EngineInterface",
"Exit"
);
csScriptsFrameSetUp = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"FrameSetUp"
);
csScriptsExecuteFixedUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteFixedUpdate"
);
csScriptsExecuteUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteUpdate"
);
csScriptsExecuteLateUpdate = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteLateUpdate"
);
csScriptsFrameCleanUp = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"FrameCleanUp"
);
csScriptsAdd = dotNet.GetFunctionPtr<CsScriptManipFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"AddScriptViaName"
);
csScriptsRemoveAll = dotNet.GetFunctionPtr<CsScriptBasicFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"RemoveAllScripts"
);
csScriptsRemoveAllImmediately = dotNet.GetFunctionPtr<CsScriptOptionalFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"RemoveAllScriptsImmediately"
);
/*csScriptsSerialise = dotNet.GetFunctionPtr<CsScriptSerialiseFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"SerialiseScripts"
);
csScriptsSerialiseYaml = dotNet.GetFunctionPtr<CsScriptSerialiseYamlFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"SerialiseScriptsYaml"
);
csScriptDeserialise = dotNet.GetFunctionPtr<CsScriptDeserialiseFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"DeserialiseScript"
);
csScriptDeserialiseYaml = dotNet.GetFunctionPtr<CsScriptSerialiseYamlFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"SerialiseScriptsYaml"
);
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Editor",
"RenderScriptsInInspector"
);*/
}
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)
{
std::ifstream buildLog(buildLogPath);
// Fail to open
if (!buildLog.is_open())
return;
// Process line by line
std::string line;
while (std::getline(buildLog, line))
{
if (line.find("error") != line.npos)
{
SHLOG_ERROR(line);
}
else
{
SHLOG_WARNING(line);
}
}
}
void SHScriptEngine::deleteFile(const std::string_view& filePath)
{
try
{
std::filesystem::remove(std::filesystem::canonical(filePath));
}
catch (...) {} // Ignore deletion failures
}
void SHScriptEngine::deleteFolder(const std::string_view& filePath)
{
try
{
std::filesystem::remove_all(std::filesystem::canonical(filePath));
}
catch (...) {} // Ignore deletion failures
}
bool SHScriptEngine::fileExists(const std::string_view& filePath)
{
std::error_code error;
if (std::filesystem::exists(filePath, error))
{
return true;
}
return false;
}
DWORD SHScriptEngine::execProcess(const std::wstring& path, const std::wstring& args)
{
STARTUPINFOW startInfo;
PROCESS_INFORMATION procInfo;
ZeroMemory(&startInfo, sizeof(startInfo));
ZeroMemory(&procInfo, sizeof(procInfo));
startInfo.cb = sizeof(startInfo);
std::wstring argsWstr = args;
// Start Process
const auto SUCCESS = CreateProcess
(
path.data(), argsWstr.data(),
nullptr, nullptr, false, NULL, nullptr, nullptr,
&startInfo, &procInfo
);
// Error Check
if (!SUCCESS)
{
auto err = GetLastError();
std::ostringstream oss;
oss << "[ScriptEngine] Failed to launch process. Error code: " << std::hex << err
<< " (" << SHStringUtils::GetWin32ErrorMessage(err) << ")";
throw std::runtime_error(oss.str());
}
// Wait for execution to end
DWORD status;
while (true)
{
const auto SUCCESS = GetExitCodeProcess(procInfo.hProcess, &status);
if (!SUCCESS)
{
auto err = GetLastError();
std::ostringstream oss;
oss << "[ScriptEngine] Failed to query process. Error code: " << std::hex << err
<< " (" << SHStringUtils::GetWin32ErrorMessage(err) << ")";
throw std::runtime_error(oss.str());
}
// Break only if process ends
if (status != STILL_ACTIVE)
{
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
return status;
}
}
}
}

View File

@ -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 <filesystem>
// Project Headers
#include "SHDotNetRuntime.h"
#include "ECS_Base/SHECSMacros.h"
#include "ECS_Base/Entity/SHEntity.h"
#include "SH_API.h"
namespace SHADE
{
/// <summary>
/// Manages initialisation of the DotNetRuntime and interfacing with CLR code written
/// and executed on .NET.
/// </summary>
class SH_API SHScriptEngine
{
public:
/*-----------------------------------------------------------------------------*/
/* Constructor */
/*-----------------------------------------------------------------------------*/
SHScriptEngine() = delete;
/*-----------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Initialises the DotNetRuntime and retrieves function pointers to all
/// functions on the CLR used to interface with the engine.
/// </summary>
static void Init();
/// <summary>
/// Loads the managed script assembly. Ensure this is only called after
/// UnloadScriptAssembly() has been called.
/// </summary>
static void UnloadScriptAssembly();
/// <summary>
/// Unloads the managed script assembly.
/// Take note that this will clear all existing scripts, ensure that the scene
/// is saved before doing so.
/// </summary>
static void LoadScriptAssembly();
/// <summary>
/// Reloads the managed script assembly.
/// Take note that this will clear all existing scripts, ensure that the scene
/// is saved before doing so.
/// </summary>
static void ReloadScriptAssembly();
/// <summary>
/// Executes the FixedUpdate()s of the Scripts that are attached to
/// Entities.
/// </summary>
static void ExecuteFixedUpdates();
/// <summary>
/// Shuts down the DotNetRuntime.
/// </summary>
static void Exit();
/*-----------------------------------------------------------------------------*/
/* Script Manipulation Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Script to a specified Entity. Note that while you can call this
/// multiple times on a specified Entity, it will work for all intents and
/// purposes but GetScript&lt;T&gt;() (C# only) currently only
/// gives you the first Script added of the specified type.
/// </summary>
/// <param name="entity">The entity to add a script to.</param>
/// <param name="scriptName">Type name of the script to add.</param>
/// <returns>
/// True if successfully added. False otherwise with the error logged to the
/// console.
/// </returns>
static bool AddScript(const SHEntity& entity, const std::string_view& scriptName);
/// <summary>
/// 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.
/// </summary>
/// <param name="entity">The entity to remove the scripts from.</param>
static void RemoveAllScripts(const SHEntity& entity);
/// <summary>
/// Removes all Scripts attached to the specified Entity. Unlike
/// RemoveAllScripts(), this removes all the scripts immediately.
/// Does not do anything if the specified Entity is invalid or does not have any
/// Scripts attached.
/// </summary>
/// <param name="entity">The entity to remove the scripts from.</param>
/// <param name="callOnDestroy">
/// Whether or not to call OnDestroy on the scripts. This is ignored if not in
/// play mode.
/// </param>
static void RemoveAllScriptsImmediately(const SHEntity& entity, bool callOnDestroy);
/*-----------------------------------------------------------------------------*/
/* Script Serialisation Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Generates a JSON string that represents the set of Scripts attached to the
/// specified Entity.
/// </summary>
/// <param name="entity"> The Entity to Serialise.</param>
/// <returns>
/// String that represents the set of scripts attached to the specified Entity.
/// </returns>
static std::string SerialiseScripts(const SHEntity& entity);
/// <summary>
/// Loads the specified JSON string and creates a Script for the specified Entity
/// based on the specified JSON string.
/// </summary>
/// <param name="entity">The Entity to deserialise a Script on to.</param>
/// <param name="yaml">
/// The YAML string that represents the Script to load into the Entity.
/// </param>
static void DeserialiseScript(const SHEntity& entity, const std::string& yaml);
/*-----------------------------------------------------------------------------*/
/* Script Editor Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Renders the set of attached Scripts for the specified Entity into the
/// inspector.
/// <br/>
/// This function is meant for consumption from native code in the inspector
/// rendering code.
/// </summary>
/// <param name="entity">The Entity to render the Scripts of.</param>
static void RenderScriptsInInspector(const SHEntity& entity);
/*-----------------------------------------------------------------------------*/
/* Static Utility Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Utilises execution of a external batch file for invoking the dotnet build
/// tool to compile C# scripts in the Assets folder into the SHADE_Scripting
/// C# assembly DLL.
/// </summary>
/// <param name="debug">
/// Whether or not a debug build will be built. Only debug built C# assemblies
/// can be debugged.
/// </param>
/// <returns>Whether or not the build succeeded.</returns>
static bool BuildScriptAssembly(bool debug = false);
/// <summary>
/// Generates a .csproj file for editing and compiling the C# scripts.
/// </summary>
/// <param name="path">File path to the generated file.</param>
static void GenerateScriptsCsProjFile(const std::filesystem::path& path);
private:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using CsFuncPtr = void(*)(void);
using CsScriptManipFuncPtr = bool(*)(EntityID, const char*);
using CsScriptBasicFuncPtr = void(*)(EntityID);
using CsScriptOptionalFuncPtr = void(*)(EntityID, bool);
using CsScriptSerialiseFuncPtr = bool(*)(EntityID, char*, int);
using CsScriptDeserialiseFuncPtr = bool(*)(EntityID, const char*);
using 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 */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Loads all the function pointers to CLR code that we need to execute.
/// </summary>
static void loadFunctions();
/// <summary>
/// Reads the file via the specified path that represents a build log of error
/// and warning messages.
/// </summary>
/// <param name="buildLogPath">
/// File path to the build log of script builds done by BuildScriptAssembly() to
/// dump and process.
/// </param>
static void dumpBuildLog(const std::string_view& buildLogPath);
/// <summary>
/// Deletes the file as specified by the file path.
/// </summary>
/// <param name="filePath">File path to the file to delete.</param>
static void deleteFile(const std::string_view& filePath);
/// <summary>
/// Deletes the folder and all files in it as specified by the file path.
/// </summary>
/// <param name="filePath">File path to the file to delete.</param>
static void deleteFolder(const std::string_view& filePath);
/// <summary>
/// Checks if a specified file exists.
/// </summary>
/// <param name="filePath">File path to the file to check.</param>
/// <returns> True if the file exists </returns>
static bool fileExists(const std::string_view& filePath);
static DWORD execProcess(const std::wstring& path, const std::wstring& args);
};
}

View File

@ -0,0 +1,52 @@
/************************************************************************************//*!
\file StringUtilities.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 29, 2021
\brief Contains the definition of functions for working with strings.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Header
#include <SHpch.h>
// Primary Header
#include "SHStringUtils.h"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Utility Functions */
/*---------------------------------------------------------------------------------*/
std::vector<std::string> SHStringUtils::Split(const std::string& str, const char& delim)
{
return Split<char>(str, delim);
}
std::vector<std::wstring> SHStringUtils::Split(const std::wstring& str, const wchar_t& delim)
{
return Split<wchar_t>(str, delim);
}
std::string SHStringUtils::WstrToStr(const std::wstring& wstr)
{
static std::vector<char> buffer;
const int STR_SIZE = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.size()), nullptr, 0, nullptr, nullptr) + 1 /* Null Terminator */;
buffer.resize(STR_SIZE);
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.size()), buffer.data(), MAX_PATH, nullptr, nullptr);
return std::string(buffer.data());
}
std::wstring SHStringUtils::StrToWstr(const std::string& str)
{
static std::vector<wchar_t> buffer;
const int WSTR_SIZE = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), nullptr, 0) + 1 /* Null Terminator */;
buffer.resize(WSTR_SIZE);
MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), buffer.data(), WSTR_SIZE);
return std::wstring(buffer.data());
}
std::string SHStringUtils::GetWin32ErrorMessage(unsigned long errorCode)
{
return std::system_category().message(errorCode);
}
}

View File

@ -0,0 +1,81 @@
/************************************************************************************//*!
\file StringUtilities.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 29, 2021
\brief Contains the declaration of functions for working with files and folders.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// Standard Libraries
#include <string> // std::basic_string
#include <vector> // std::vector
namespace SHADE
{
/// <summary>
/// Contains useful functions for operating on strings.
/// </summary>
class SHStringUtils
{
public:
/*-----------------------------------------------------------------------------*/
/* Utility Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Splits a string separated by a specified delimiter into a vector of strings.
/// </summary>
/// <typeparam name="T">Internal type of each element in the string.</typeparam>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
template<typename T>
static std::vector<std::basic_string<T>> Split(const std::basic_string<T>& str, const T& delim);
/// <summary>
/// Splits a string separated by a specified delimiter into a vector of strings.
/// Overload of Split<T>() to allow for string literals to be accepted.
/// </summary>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
static std::vector<std::string> Split(const std::string& str, const char& delim);
/// <summary>
/// Splits a string separated by a specified delimiter into a vector of strings.
/// Overload of Split<T>() to allow for wide string literals to be accepted.
/// </summary>
/// <param name="str">Read only reference to the string to split.</param>
/// <param name="delim">Read only reference to the delimiter.</param>
/// <returns>Vector of strings that have been split.</returns>
static std::vector<std::wstring> Split(const std::wstring& str, const wchar_t& delim);
/// <summary>
/// Converts a wstring to a string.
/// </summary>
/// <param name="wstr">wstring to convert.</param>
/// <returns>The converted wstring in string form.</returns>
static std::string WstrToStr(const std::wstring& wstr);
/// <summary>
/// Converts a string to a wstring.
/// </summary>
/// <param name="str">string to convert.</param>
/// <returns>The converted string in wstring form.</returns>
static std::wstring StrToWstr(const std::string& str);
/// <summary>
/// Retrieves the error message associated with a Win32 error code.
/// </summary>
/// <param name="errorCode">Win32 error code to decode.</param>
/// <returns>String that represents the Win32 error.</returns>
static std::string GetWin32ErrorMessage(unsigned long errorCode);
private:
/*-------------------------------------------------------------------------------*/
/* Constructors/Destructors */
/*-------------------------------------------------------------------------------*/
SHStringUtils() = delete;
};
}
#include "SHStringUtils.hpp"

View File

@ -0,0 +1,46 @@
/************************************************************************************//*!
\file StringUtilities.hpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 29, 2021
\brief Contains the implementation of template functions for working with files
and folders.
Copyright (C) 2021 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// Primary Header
#include "SHStringUtils.h"
namespace SHADE
{
/*-------------------------------------------------------------------------------*/
/* Template Function Definitions */
/*-------------------------------------------------------------------------------*/
template<typename T>
inline std::vector<std::basic_string<T>> SHStringUtils::Split(const std::basic_string<T>& str, const T& delim)
{
std::vector<std::basic_string<T>> results;
std::basic_string<T> remaining = str;
// Go through looking for delimiters
while (true)
{
const size_t DELIM_POS = remaining.find_first_of(delim);
results.emplace_back(remaining.substr(0, DELIM_POS));
// Check if we hit the end of the string
if (DELIM_POS == remaining.npos)
{
break;
}
// Otherwise, cut the remainder
remaining = remaining.substr(DELIM_POS + 1);
}
return results;
}
}

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Components">
<UniqueIdentifier>{6B7DD516-5735-1764-C03C-F0BFAC13B254}</UniqueIdentifier>
</Filter>
<Filter Include="Engine">
<UniqueIdentifier>{DBC7D3B0-C769-FE86-B024-12DB9C6585D7}</UniqueIdentifier>
</Filter>
<Filter Include="Math">
<UniqueIdentifier>{AFF4887C-9B2B-8A0D-4418-7010302E060F}</UniqueIdentifier>
</Filter>
<Filter Include="Scripts">
<UniqueIdentifier>{4D6F1AE8-B94E-9983-C266-245A2EC5FFE4}</UniqueIdentifier>
</Filter>
<Filter Include="Utility">
<UniqueIdentifier>{594615A9-C525-9444-CE3D-1F1B3A9CFAA5}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Components\Component.hxx">
<Filter>Components</Filter>
</ClInclude>
<ClInclude Include="src\Engine\ECS.hxx">
<Filter>Engine</Filter>
</ClInclude>
<ClInclude Include="src\Engine\EngineInterface.hxx">
<Filter>Engine</Filter>
</ClInclude>
<ClInclude Include="src\Engine\Entity.hxx">
<Filter>Engine</Filter>
</ClInclude>
<ClInclude Include="src\Engine\GameObject.hxx">
<Filter>Engine</Filter>
</ClInclude>
<ClInclude Include="src\Math\Math.hxx">
<Filter>Math</Filter>
</ClInclude>
<ClInclude Include="src\Math\Vector2.hxx">
<Filter>Math</Filter>
</ClInclude>
<ClInclude Include="src\Math\Vector3.hxx">
<Filter>Math</Filter>
</ClInclude>
<ClInclude Include="src\SHpch.h" />
<ClInclude Include="src\Scripts\Script.hxx">
<Filter>Scripts</Filter>
</ClInclude>
<ClInclude Include="src\Scripts\ScriptStore.hxx">
<Filter>Scripts</Filter>
</ClInclude>
<ClInclude Include="src\Utility\Convert.hxx">
<Filter>Utility</Filter>
</ClInclude>
<ClInclude Include="src\Utility\Debug.hxx">
<Filter>Utility</Filter>
</ClInclude>
<ClInclude Include="src\Utility\DisposableAssemblyLoadContext.hxx">
<Filter>Utility</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\AssemblyInfo.cxx" />
<ClCompile Include="src\Components\Component.cxx">
<Filter>Components</Filter>
</ClCompile>
<ClCompile Include="src\Engine\ECS.cxx">
<Filter>Engine</Filter>
</ClCompile>
<ClCompile Include="src\Engine\EngineInterface.cxx">
<Filter>Engine</Filter>
</ClCompile>
<ClCompile Include="src\Engine\Entity.cxx">
<Filter>Engine</Filter>
</ClCompile>
<ClCompile Include="src\Engine\GameObject.cxx">
<Filter>Engine</Filter>
</ClCompile>
<ClCompile Include="src\Math\Math.cxx">
<Filter>Math</Filter>
</ClCompile>
<ClCompile Include="src\Math\Vector2.cxx">
<Filter>Math</Filter>
</ClCompile>
<ClCompile Include="src\Math\Vector3.cxx">
<Filter>Math</Filter>
</ClCompile>
<ClCompile Include="src\SHpch.cpp" />
<ClCompile Include="src\Scripts\Script.cxx">
<Filter>Scripts</Filter>
</ClCompile>
<ClCompile Include="src\Scripts\ScriptStore.cxx">
<Filter>Scripts</Filter>
</ClCompile>
<ClCompile Include="src\Utility\Convert.cxx">
<Filter>Utility</Filter>
</ClCompile>
<ClCompile Include="src\Utility\Debug.cxx">
<Filter>Utility</Filter>
</ClCompile>
<ClCompile Include="src\Utility\DisposableAssemblyLoadContext.cxx">
<Filter>Utility</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="src\Components\Component.h++">
<Filter>Components</Filter>
</None>
<None Include="src\Engine\ECS.h++">
<Filter>Engine</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -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"}

View File

@ -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)];

View File

@ -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 <typename T>
T BaseComponent::AddComponent()
{
return ECS::AddComponent<T>(owner.GetEntity());
}
generic <typename T>
T BaseComponent::GetComponent()
{
return ECS::GetComponent<T>(owner.GetEntity());
}
generic <typename T>
void BaseComponent::RemoveComponent()
{
ECS::RemoveComponent<T>(owner.GetEntity());
}
/*---------------------------------------------------------------------------------*/
/* Script Access Functions */
/*---------------------------------------------------------------------------------*/
generic <typename T>
T BaseComponent::AddScript()
{
return ScriptStore::AddScript<T>(owner.GetEntity());
}
generic <typename T>
T BaseComponent::GetScript()
{
return ScriptStore::GetScript<T>(owner.GetEntity());
}
generic <typename T>
System::Collections::Generic::IEnumerable<T>^ BaseComponent::GetScripts()
{
return ScriptStore::GetScripts<T>(owner.GetEntity());
}
generic <typename T>
void BaseComponent::RemoveScript()
{
ScriptStore::RemoveScript<T>(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<BaseComponent^>(o);
return Equals(cmp);
}
catch (System::InvalidCastException^)
{
return false;
}
}
int BaseComponent::GetHashCode()
{
return owner.GetHashCode();
}
}

View File

@ -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 <typename NativeType>
Component<NativeType>::Component(Entity entity)
: BaseComponent { entity }
{}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
template <typename NativeType>
typename Component<NativeType>::NativeComponent* Component<NativeType>::GetNativeComponent()
{
return ECS::GetNativeComponent<NativeType>(owner.GetEntity());
}
}

View File

@ -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
{
/// <summary>
/// Class that serves as the base for a wrapper class to Components in native code.
/// </summary>
public ref class BaseComponent : public System::IEquatable<BaseComponent^>
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves the GameObject that this Component belongs to.
/// </summary>
property GameObject Owner
{
GameObject get() { return owner; }
}
/*-----------------------------------------------------------------------------*/
/* Component Access Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Component to this GameObject.
/// </summary>
/// <typeparam name="T">Type of the Component to add. </typeparam>
/// <returns>Reference to the Component that was added.</returns>
generic<typename T> where T : BaseComponent
T AddComponent();
/// <summary>
/// Gets a Component from this GameObject.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns>
/// Reference to the Component or null if this GameObject does not have the
/// specified Component.
/// </returns>
generic<typename T> where T : BaseComponent
T GetComponent();
/// <summary>
/// Removes a Component from this GameObject. If no Component exists to begin
/// with, nothing happens.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
generic<typename T> where T : BaseComponent
void RemoveComponent();
/*-----------------------------------------------------------------------------*/
/* Script Access Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Script of the specified type to this GameObject.
/// </summary>
/// <typeparam name="T">Type of Script to add.</typeparam>
/// <returns>Reference to the created Script.</returns>
generic<typename T> where T : ref class, Script
T AddScript();
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">Type of Script to add.</typeparam>
/// <returns>Reference to the Script to retrieve.</returns>
generic<typename T> where T : ref class, Script
T GetScript();
/// <summary>
/// Retrieves a immutable list of Scripts of the specified type from this
/// GameObject.
/// </summary>
/// <typeparam name="T">Type of Scripts to Get.</typeparam>
/// <returns>Immutable list of Scripts of the specified type.</returns>
generic<typename T> where T : ref class, Script
System::Collections::Generic::IEnumerable<T>^ GetScripts();
/// <summary>
/// Removes all Scripts of the specified type from this GameObject.
/// </summary>
/// <typeparam name="T">Type of PLushieScripts to remove.</typeparam>
generic<typename T> where T : ref class, Script
void RemoveScript();
protected:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for BaseComponent to tie it to a specific Entity.
/// Constructors of derived Components should call this Constructor.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
BaseComponent(Entity entity);
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Entity that this Component belongs to.
/// </summary>
GameObject owner;
public:
/*-----------------------------------------------------------------------------*/
/* IEquatable */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with an object of the same type.
/// </summary>
/// <param name="other">The object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
virtual bool Equals(BaseComponent^ other);
/*-----------------------------------------------------------------------------*/
/* Object */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with another unboxed object.
/// </summary>
/// <param name="o">The unboxed object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
bool Equals(Object^ o) override;
/// <summary>
/// Gets a unique hash for this object.
/// </summary>
/// <returns>Unique hash for this object.</returns>
int GetHashCode() override;
};
/// <summary>
/// C++ template for the BaseComponent class used to generate common template-able
/// functions and types.
/// </summary>
/// <typeparam name="NativeType">
/// Type of the native component that this Component wraps.
/// </typeparam>
template<typename NativeType>
public ref class Component : public BaseComponent
{
internal:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Type of the native component that this Component wraps.
/// </summary>
using NativeComponent = NativeType;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves a pointer to the native unmanaged component that is tied to the
/// Entity described by the owner value.
/// </summary>
/// <returns>
/// Pointer to the native component. Will be nullptr if it does not exist.
/// </returns>
/// <exception cref="System.InvalidOperationException">
/// Thrown if the internal ID stored by this native component is invalid.
/// </exception>
/// <exception cref="System.NullReferenceException">
/// Thrown if an attempt to retrieve the native component fails.
/// </exception>
NativeComponent* GetNativeComponent();
protected:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for Component to tie it to a specific Entity.
/// Constructors of derived Components should call this Constructor.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
Component(Entity entity);
};
}
#include "Component.h++"

View File

@ -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 <sstream>
#include <msclr\marshal_cppstd.h>
// External Dependencies
#include "ECS_Base/System/SHEntityManager.h"
// Project Headers
#include "Utility/Convert.hxx"
#include "Utility/Debug.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Component Manipulation Functions */
/*---------------------------------------------------------------------------------*/
generic <typename T>
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<std::string>(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<T>(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 <typename T>
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<T>(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 <typename T>
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<Pls::Transform>(entity);
//if (tf == nullptr)
// return T();
//// Search direct children first
//for (const auto& child : tf->GetChildren())
//{
// T component = GetComponent<T>(child);
// if (component != nullptr)
// return component;
//}
//// Search their children
//for (const auto& child : tf->GetChildren())
//{
// T script = GetComponentInChildren<T>(child);
// if (script != nullptr)
// return script;
//}
// None here
return T();
}
generic <typename T>
T ECS::EnsureComponent(EntityID entity)
{
if (HasComponent<T>(entity))
{
AddComponent<T>(entity);
}
return GetComponent<T>(entity);
}
generic <typename T>
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<std::string>(componentType->Name)
<< "\" from Entity #"
<< entity;
Debug::LogError(oss.str());
return false;
}
generic <typename T>
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<std::string>(componentType->Name)
<< "\" from Entity #"
<< entity;
Debug::LogError(oss.str());
}
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
static ECS::ECS()
{
// TODO
// componentMap.Add(createComponentSet<Transform, Transform>());
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
generic <typename T>
T ECS::createManagedComponent(EntityID entity)
{
using namespace System::Reflection;
array<System::Object^>^ params = gcnew array<System::Object^>{ static_cast<Entity>(entity) };
return safe_cast<T>(System::Activator::CreateInstance
(
T::typeid,
BindingFlags::Instance | BindingFlags::NonPublic | BindingFlags::CreateInstance,
nullptr, params, nullptr)
);
}
}

View File

@ -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 <typename NativeComponent>
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<NativeComponent>(nativeEntity);
if (component == nullptr)
throw gcnew System::NullReferenceException("Attempted to get a native Component that does not exist.");
return component;
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
template<typename NativeType, typename ManagedType>
ECS::ComponentSet ECS::createComponentSet()
{
return ComponentSet
{
ManagedType::typeid,
SHComponentManager::AddComponent<NativeType>,
SHComponentManager::EnsureComponent<NativeType>,
SHComponentManager::HasComponent<NativeType>,
SHComponentManager::RemoveComponent<NativeType>
};
}
}

View File

@ -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
{
/// <summary>
/// Static class which contains functions that map Pls::ECS's Component manipulation
/// functions to managed generic functions.
/// </summary>
private ref class ECS abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Component Manipulation Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Component to the specified Entity.
/// </summary>
/// <typeparam name="T">Type of the Component to add.</typeparam>
/// <param name="entity">
/// Entity object that should have the specified Component added to.
/// </param>
/// <returns>Reference to the Component that was added.</returns>
generic<typename T> where T : BaseComponent
static T AddComponent(EntityID entity);
/// <summary>
/// Gets a Component from the specified Entity.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <param name="entity"> Entity object to get the Component from. </param>
/// <returns>
/// Reference to the Component or null if the Entity does not have the
/// specified Component.
/// </returns>
generic<typename T> where T : BaseComponent
static T GetComponent(EntityID entity);
/// <summary>
/// Retrieves the first Component from the specified GameObjectt's children that
/// matches the specified type.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <param name="entity"> Entity object to get the Component from. </param>
/// <returns>
/// Reference to the Component or null if the Entity does not have the
/// specified Component.
/// </returns>
generic<typename T> where T : BaseComponent
static T GetComponentInChildren(EntityID entity);
/// <summary>
/// Ensures a Component on the specified Entity.
/// </summary>
/// <typeparam name="T">Type of the Component to ensure.</typeparam>
/// <param name="entity"> Entity object to ensure the Component on. </param>
/// <returns>Reference to the Component.</returns>
generic<typename T> where T : BaseComponent
static T EnsureComponent(EntityID entity);
/// <summary>
/// Checks if the specified Entity has the specified Component.
/// </summary>
/// <typeparam name="T">Type of the Component to check for.</typeparam>
/// <param name="entity">Entity object to check for the Component.</param>
/// <returns>
/// True if the specified Entity has the specified Component. False otherwise.
/// </returns>
generic<typename T> where T : BaseComponent
static bool HasComponent(EntityID entity);
/// <summary>
/// Removes a Component from the specified Entity.
/// </summary>
/// <typeparam name="T">Type of the Component to remove.</typeparam>
/// <param name="entity">
/// Entity object that should have the specified Component removed from/
/// </param>
generic<typename T> where T : BaseComponent
static void RemoveComponent(EntityID entity);
internal:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Pointer to a function for Component manipulation operations.
/// </summary>
using ComponentFunc = void(*)(const EntityID&);
using ComponentHasFunc = bool(*)(const EntityID&);
/// <summary>
/// Contains a set of Component related data used for resolving operations for
/// each Component.
/// </summary>
value struct ComponentSet
{
public:
System::Type^ Type;
ComponentFunc AddFunction;
ComponentHasFunc HasFunction;
ComponentFunc RemoveFunction;
};
/*-----------------------------------------------------------------------------*/
/* Static Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves a pointer to the native unmanaged component of the specified
/// Entity.
/// </summary>
/// <returns>
/// Pointer to the native component. Will be nullptr if it does not exist.
/// </returns>
/// <exception cref="System.InvalidOperationException">
/// Thrown if the Entity specified is invalid.
/// </exception>
/// <exception cref="System.NullReferenceException">
/// Thrown if an attempt to retrieve the native component fails.
/// </exception>
template<typename NativeComponent>
static NativeComponent* GetNativeComponent(Entity entity);
private:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Static constructor to initialize static data
/// </summary>
static ECS();
/*-----------------------------------------------------------------------------*/
/* Static Data Members */
/*-----------------------------------------------------------------------------*/
static System::Collections::Generic::List<ComponentSet> componentMap;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Creates a ComponentSet for a pair of Native and Managed Components.
/// </summary>
/// <typeparam name="NativeType">Type of the Native Component.</typeparam>
/// <typeparam name="ManagedType">Type of the Managed Component.</typeparam>
/// <returns>ComponentSet for the parameters specified.</returns>
template<typename NativeType, typename ManagedType>
static ComponentSet createComponentSet();
/// <summary>
/// Creates an instance of the Managed representation of a Component with a
/// native Entity.
/// </summary>
/// <typeparam name="T">Type of Component to create.</typeparam>
/// <param name="entity">Native Entity that this Component is tied to.</param>
/// <returns>The created Managed representation of the Component.</returns>
generic<typename T> where T : BaseComponent
static T createManagedComponent(EntityID entity);
};
}
#include "ECS.h++"

View File

@ -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 <sstream>
// 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());
}
}

View File

@ -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
{
/// <summary>
/// Static class that contains the functions for interfacing with the core
/// PlushieEngine written in C++ for managing the lifecycle of managed code.
/// </summary>
private ref class EngineInterface abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Name of the Managed Library that contains the C# scripts written externally.
/// </summary>
literal System::String^ ManagedLibraryName = "SHADE_Scripting";
/*-----------------------------------------------------------------------------*/
/* Interop Static Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Initialises all required components for managed code.
/// </summary>
static void Init();
/// <summary>
/// Unloads the managed script assembly.
/// Take note that this will clear all existing scripts, ensure that the scene
/// is saved before doing so.
/// </summary>
static void UnloadScriptAssembly();
/// <summary>
/// Loads the managed script assembly. Ensure this is only called after
/// UnloadScriptAssembly() has been called.
/// </summary>
static void LoadScriptAssembly();
/// <summary>
/// Reloads the managed script assembly.
/// Take note that this will clear all existing scripts, ensure that the scene
/// is saved before doing so.
/// Equivalent to calling UnloadScriptAssembly() and then LoadScriptAssembly().
/// </summary>
static void ReloadScriptAssembly();
/// <summary>
/// Cleans up all required components for managed code.
/// </summary>
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);
};
}

View File

@ -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<EntityID>(entity));
}
}

View File

@ -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
{
/// <summary>
/// Managed representation of a native ECS Entity.
/// </summary>
using Entity = System::UInt32;
/// <summary>
/// Static class that contains useful utility functions for working with Entity.
/// </summary>
private ref class EntityUtils abstract sealed
{
public:
/// <summary>
/// Checks if the specified entity is valid. This is done by checking if it
/// matches Pls::Entity::INVALID.
/// </summary>
/// <param name="entity">The Entity to check.</param>
/// <returns>True if the specified Entity is valid.</returns>
static bool IsValid(Entity^ entity);
};
}

View File

@ -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<EntityID>(obj.GetEntity()));
}
System::Nullable<GameObject> 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 <typename T>
T GameObject::AddComponent()
{
return ECS::AddComponent<T>(entity);
}
generic <typename T>
T GameObject::GetComponent()
{
return ECS::GetComponent<T>(entity);
}
generic <typename T>
T GameObject::GetComponentInChildren()
{
return ECS::GetComponentInChildren<T>(entity);
}
generic <typename T>
T GameObject::EnsureComponent()
{
return ECS::EnsureComponent<T>(entity);
}
generic <typename T>
void GameObject::RemoveComponent()
{
ECS::RemoveComponent<T>(entity);
}
/*---------------------------------------------------------------------------------*/
/* Script Access Functions */
/*---------------------------------------------------------------------------------*/
generic <typename T>
T GameObject::AddScript()
{
return ScriptStore::AddScript<T>(entity);
}
generic <typename T>
T GameObject::GetScript()
{
return ScriptStore::GetScript<T>(entity);
}
generic <typename T>
T GameObject::GetScriptInChildren()
{
return ScriptStore::GetScriptInChildren<T>(entity);
}
generic <typename T>
System::Collections::Generic::IEnumerable<T>^ GameObject::GetScripts()
{
return ScriptStore::GetScripts<T>(entity);
}
generic <typename T>
void GameObject::RemoveScript()
{
ScriptStore::RemoveScript<T>(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<GameObject^>(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);
}
}

View File

@ -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 */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Lightweight object for an PlushieEngine Entity that allows for easy access
/// to Component and Script operations.
/// </summary>
public value class GameObject : public System::IEquatable<GameObject>
{
public:
/*-----------------------------------------------------------------------------*/
/* Static Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// 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().
/// </summary>
/// <returns>GameObject that represents the newly created GameObject.</returns>
static GameObject Create();
/// <summary>
/// Destroys the specified GameObject. Note that the specified GameObject will no
/// longer be a valid GameObject after this function is called.
/// </summary>
/// <param name="obj">The GameObject to be destroyed.</param>
static void Destroy(GameObject obj);
/// <summary>
/// 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".
/// </summary>
/// <param name="name">Name of the GameObject to find.</param>
/// <returns>GameObject that has the specified name. Null if not found.</returns>
static System::Nullable<GameObject> Find(System::String^ name);
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Name of the object that this Entity represents.
/// </summary>
property System::String^ Name
{
System::String^ get();
}
/// <summary>
/// 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.
/// </summary>
property bool IsActiveSelf
{
bool get();
}
/// <summary>
/// Whether or not this Entity is active in the Scene hierarchy.
/// </summary>
property bool IsActiveInHierarchy
{
bool get();
}
/*-----------------------------------------------------------------------------*/
/* GameObject Property Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Sets the name of this GameObject.
/// </summary>
/// <param name="name">The name to set.</param>
void SetName(System::String^ name);
/// <summary>
/// Sets the active state of this GameObject.
/// <br/>
/// The actual "activeness" of this GameObject is still dependent on the parents'
/// active states.
/// </summary>
/// <param name="active">
/// Whether to activate or deactivate this GameObject.
/// </param>
void SetActive(bool active);
/*-----------------------------------------------------------------------------*/
/* Component Access Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Component to this GameObject.
/// </summary>
/// <typeparam name="T">Type of the Component to add. </typeparam>
/// <returns>Reference to the Component that was added.</returns>
generic<typename T> where T : BaseComponent
T AddComponent();
/// <summary>
/// Gets a Component from this GameObject.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns>
/// Reference to the Component or null if this GameObject does not have the
/// specified Component.
/// </returns>
generic<typename T> where T : BaseComponent
T GetComponent();
/// <summary>
/// Retrieves the first Component from this GameObject's children that matches
/// the specified type.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns>
/// Reference to the Component or null if neither of this GameObject's children
/// does not have the specified Component.
/// </returns>
generic<typename T> where T : BaseComponent
T GetComponentInChildren();
/// <summary>
/// Ensures a Component on this GameObject.
/// </summary>
/// <typeparam name="T">Type of the Component to ensure.</typeparam>
/// <returns>
/// Reference to the Component.
/// </returns>
generic<typename T> where T : BaseComponent
T EnsureComponent();
/// <summary>
/// Removes a Component from this GameObject. If no Component exists to begin
/// with, nothing happens.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
generic<typename T> where T : BaseComponent
void RemoveComponent();
/*-----------------------------------------------------------------------------*/
/* Script Access Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Script of the specified type to this GameObject.
/// </summary>
/// <typeparam name="T">Type of Script to add.</typeparam>
/// <returns>Reference to the created Script.</returns>
generic<typename T> where T : ref class, Script
T AddScript();
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">Type of Script to retrieve.</typeparam>
/// <returns>Reference to the Script to retrieve.</returns>
generic<typename T> where T : ref class, Script
T GetScript();
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">Type of Script to retrieve.</typeparam>
/// <returns>Reference to the Script to retrieve.</returns>
generic<typename T> where T : ref class, Script
T GetScriptInChildren();
/// <summary>
/// Retrieves a immutable list of Scripts of the specified type from this
/// GameObject.
/// </summary>
/// <typeparam name="T">Type of Scripts to retrieve.</typeparam>
/// <returns>Immutable list of Scripts of the specified type.</returns>
generic<typename T> where T : ref class, Script
System::Collections::Generic::IEnumerable<T>^ GetScripts();
/// <summary>
/// Removes all Scripts of the specified type from this GameObject.
/// </summary>
/// <typeparam name="T">Type of PLushieScripts to remove.</typeparam>
generic<typename T> where T : ref class, Script
void RemoveScript();
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for the GameObject.
/// </summary>
/// <param name="entity">
/// The ECS Entity that this GameObject should represent.
/// </param>
GameObject(const SHEntity& entity);
/// <summary>
/// Constructor for the GameObject.
/// </summary>
/// <param name="entity">
/// Managed numerical representation of the ECS Entity that this GameObject
/// should represent.
/// </param>
GameObject(Entity entity);
/*-----------------------------------------------------------------------------*/
/* Getters */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves the CLR Entity object that this GameObject represents.
/// </summary>
/// <returns>Entity object that this GameObject represents.</returns>
inline Entity GetEntity() { return entity; }
/// <summary>
/// Retrieves the native Entity object that this GameObject represents.
/// </summary>
/// <returns>Native Entity object that this GameObject represents.</returns>
SHEntity& GetNativeEntity();
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
Entity entity;
public:
/*-----------------------------------------------------------------------------*/
/* IEquatable */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with an object of the same type.
/// </summary>
/// <param name="other">The object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
virtual bool Equals(GameObject other);
/*-----------------------------------------------------------------------------*/
/* Object */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with another unboxed object.
/// </summary>
/// <param name="o">The unboxed object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
bool Equals(Object^ o) override;
/// <summary>
/// Gets a unique hash for this object.
/// </summary>
/// <returns>Unique hash for this object.</returns>
int GetHashCode() override;
/// <summary>
/// Checks if two GameObject references are the same.
/// </summary>
/// <param name="lhs">GameObject to check.</param>
/// <param name="rhs">Another GameObject to check with.</param>
/// <returns>True if both Components are the same.</returns>
static bool operator==(GameObject lhs, GameObject rhs);
/// <summary>
/// Checks if two GameObject references are different.
/// </summary>
/// <param name="lhs">GameObject to check.</param>
/// <param name="rhs">Another GameObject to check with.</param>
/// <returns>True if both Components are different.</returns>
static bool operator!=(GameObject lhs, GameObject rhs);
};
}

View File

@ -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);
}
}

View File

@ -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
{
/// <summary>
/// Contains utility Math functions.
/// </summary>
public ref class Math abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Static Constants */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Degrees-to-radians conversion constant
/// </summary>
static constexpr double Deg2Rad = System::Math::PI / 180.0;
/// <summary>
/// Radians-to-degrees conversion constant
/// </summary>
static constexpr double Rad2Deg = 180.0 / System::Math::PI;
/// <summary>
/// Small value used for single precision floating point comparisons.
/// </summary>
static constexpr float Epsilon = 0.001f;
/*-----------------------------------------------------------------------------*/
/* Utility Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Wraps a value if they get to low or too high.
/// </summary>
/// <param name="value">Value to wrap.</param>
/// <param name="min">Minimum value to wrap at.</param>
/// <param name="max">Maximum value to wrap at.</param>
/// <returns>Wrapped value.</returns>
static double Wrap(double value, double min, double max);
/// <summary>
/// Converts an angle from degree representation to radian representation.
/// </summary>
/// <param name="degrees">Degree-based angle to convert.</param>
/// <returns>The specified angle in radians.</returns>
static double DegreesToRadians(double degrees);
/// <summary>
/// Converts an angle from radian representation to degree representation.
/// </summary>
/// <param name="radians">Radian-based angle to convert.</param>
/// <returns>The specified angle in degrees.</returns>
static double RadiansToDegrees(double radians);
/// <summary>
/// Linearly interpolates between a and b by t.
/// The parameter t is clamped to the range [0, 1].
/// </summary>
/// <param name="a">The start value.</param>
/// <param name="b">The end value.</param>
/// <param name="t">The interpolation value between the two double.</param>
/// <returns>The interpolated double result between the two double values.</returns>
static double Lerp(double a, double b, double t);
/// <summary>
/// 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.
/// </summary>
/// <param name="a">The start value.</param>
/// <param name="b">The end value.</param>
/// <param name="t">The interpolation value between the two double.</param>
/// <returns>The interpolated double result between the two double values.</returns>
static double LerpUnclamped(double a, double b, double t);
/// <summary>
/// Calculates the linear parameter t that produces the interpolant value within the range [a, b].
/// </summary>
/// <param name="a">Start value.</param>
/// <param name="b">End value.</param>
/// <param name="value">Value between start and end.</param>
/// <returns>Percentage of value between start and end.</returns>
static double InverseLerp(double a, double b, double value);
};
}

View File

@ -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 <cmath>
#include <algorithm>
// 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<Vector2>(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

View File

@ -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 <limits>
namespace SHADE
{
///<summary>
/// CLR version of the the PlushieEngine's Vector2 class that represents a
/// 2-Dimensional Vector. Designed to closely match Unity's Vector2 struct.
/// </summary>
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
public value struct Vector2 : public System::IEquatable<Vector2>
{
public:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
#pragma region Constants
///<summary>
/// Shorthand for writing Vector2(0, -1).
///</summary>
static initonly Vector2 Down = Vector2(0.0, -1.0);
///<summary>
/// Shorthand for writing Vector2(-1, 0).
///</summary>
static initonly Vector2 Left = Vector2(-1.0, 0.0);
///<summary>
/// Shorthand for writing Vector2(double.NegativeInfinity,
/// double.NegativeInfinity).
///</summary>
static initonly Vector2 NegativeInfinity = Vector2(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
///<summary>
/// Shorthand for writing Vector2(1, 1).
///</summary>
static initonly Vector2 One = Vector2(1.0, 1.0);
///<summary>
/// Shorthand for writing Vector2(double.PositiveInfinity,
/// double.PositiveInfinity).
///</summary>
static initonly Vector2 PositiveInfinity = Vector2(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
///<summary>
/// Shorthand for writing Vector2(1, 0).
///</summary>
static initonly Vector2 Right = Vector2(1.0, 0.0);
///<summary>
/// Shorthand for writing Vector2(0, 1).
///</summary>
static initonly Vector2 Up = Vector2(0.0, 1.0);
///<summary>
/// Shorthand for writing Vector2(0, 0).
///</summary>
static initonly Vector2 Zero = Vector2(0.0, 0.0);
#pragma endregion
/*-----------------------------------------------------------------------------*/
/* Public Members */
/*-----------------------------------------------------------------------------*/
///<summary>
/// X-component of the Vector2.
///</summary>
double x;
///<summary>
/// Y-component of the Vector2.
///</summary>
double y;
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor to construct a Vector2 with the specified components with the
/// Y-component set to 0.0.
/// </summary>
/// <param name="_x">X-coordinate to set.</param>
Vector2(double _x);
/// <summary>
/// Constructor to construct a Vector2 with the specified components..
/// </summary>
/// <param name="_x">X-coordinate to set.</param>
/// <param name="_y">Y-coordinate to set.</param>
Vector2(double _x, double _y);
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// 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.
/// </summary>
void Normalise();
/// <summary>
/// Creates a copy of this Vector2 and returns a normalized version.
/// </summary>
/// <returns>
/// Returns a normalised copy of this Vector2.
/// If this Vector2 is a zero vector, a zero vector will be returned.
/// </returns>
Vector2 GetNormalised();
/// <summary>
/// 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.
/// </summary>
/// <returns>Returns the length of this Vector2.</returns>
double GetMagnitude();
/// <summary>
/// Calculates and returns the squared magnitude of this Vector2.
/// </summary>
/// <returns>Returns the squared length of this Vector2.</returns>
double GetSqrMagnitude();
/// <summary>
/// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -Math.PI and Math.PI.
/// </summary>
/// <returns>Returns the angle of this vector from the right vector in radians.</returns>
double AngleFromRightRadians();
/// <summary>
/// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -180.0 and 180.0.
/// </summary>
/// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
double AngleFromRightDegrees();
/// <summary>
/// Checks if a specified point is near this Vector2 that represents a point with
/// a tolerance value of PLS_EPSILON.
/// </summary>
/// <param name="point">The other point to check if we are near.</param>
/// <returns>
/// True if this Vector2 representing a point and the specified point are within
/// the range of the specified tolerance. False otherwise.
/// </returns>
bool IsNearPoint(Vector2 point);
/// <summary>
/// Checks if a specified point is near this Vector2 that represents a point.
/// </summary>
/// <param name="point">The other point to check if we are near.</param>
/// <param name="tolerance">
/// The amount of tolerance before we consider these points as "near".
/// </param>
/// <returns>
/// True if this Vector2 representing a point and the specified point are within
/// the range of the specified tolerance. False otherwise.
/// </returns>
bool IsNearPoint(Vector2 point, double tolerance);
/*-----------------------------------------------------------------------------*/
/* IEquatable */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with an object of the same type.
/// </summary>
/// <param name="other">The object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
virtual bool Equals(Vector2 other);
/*-----------------------------------------------------------------------------*/
/* Object */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with another unboxed object.
/// </summary>
/// <param name="o">The unboxed object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
bool Equals(Object^ o) override;
/// <summary>
/// Gets a unique hash for this object.
/// </summary>
/// <returns>Unique hash for this object.</returns>
int GetHashCode() override;
/*-----------------------------------------------------------------------------*/
/* Static Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Checks if two specified Vector2s are near in value.
/// </summary>
/// <param name="lhs">Vector2 to check if is near in value.</param>
/// <param name="rhs">Another Vector2 to check if is near in value.</param>
/// <returns>
/// True if the two Vector2s are within the tolerance value specified
/// </returns>
static bool IsNear(Vector2 lhs, Vector2 rhs);
/// <summary>
/// Checks if two specified Vector2s are near in value.
/// </summary>
/// <param name="lhs">Vector2 to check if is near in value.</param>
/// <param name="rhs">Another Vector2 to check if is near in value.</param>
/// <param name="tolerance">
/// Amount of tolerance to do the comparison with.
/// </param>
/// <returns>
/// True if the two Vector2s are within the tolerance value specified
/// </returns>
static bool IsNear(Vector2 lhs, Vector2 rhs, double tolerance);
/// <summary>
/// Computes and returns the dot product of 2 specified Vector2s.
/// </summary>
/// <param name="lhs">Vector2 to calculate dot product with.</param>
/// <param name="rhs">Another Vector2 to calculate dot product with.</param>
/// <returns>
/// Scalar value representing the dot product of the two Vector2s.
/// </returns>
static double Dot(Vector2 lhs, Vector2 rhs);
/// <summary>
/// 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.
/// </summary>
/// <param name="lhs">Vector2 to find a perpendicular of.</param>
/// <returns>
/// The perpendicular Vector2 relative to the specified Vector2.
/// </returns>
static Vector2 Perpendicular(Vector2 lhs);
/// <summary>
/// Computes a perpendicular Vector2 to the specified Vector2.
/// </summary>
/// <param name="lhs">Vector2 to find a perpendicular of.</param>
/// <param name="inward">
/// Whether the inward perpendicular Vector is retrieved. If true, the
/// resultant vector is rotated 90-degrees in a counter-clockwise.
/// </param>
/// <returns>The perpendicular Vector2 relative to the specified Vector2.
/// </returns>
static Vector2 Perpendicular(Vector2 lhs, bool inward);
/// <summary>
/// Computes and returns a Vector2 projection.
/// </summary>
/// <param name="vec">Vector2 to project.</param>
/// <param name="direction">Vector2 to project onto.</param>
/// <returns>The Vector2 that represents the projected vec onto direction.</returns>
static Vector2 Project(Vector2 vec, Vector2 direction);
/// <summary>
/// Reflects a Vector2 across another Vector2.
/// </summary>
/// <param name="vec">A Vector2 to reflect.</param>
/// <param name="normal">A normal to reflect the Vector2 across.</param>
/// <returns>The Vector2 that represents vec reflected across normal.</returns>
static Vector2 Reflect(Vector2 vec, Vector2 normal);
/// <summary>
/// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise
/// direction.
/// </summary>
/// <param name="vec">A Vector2 to rotate.</param>
/// <param name="radians">
/// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param>
/// <returns>The Vector2 that represents the rotated vector.</returns>
static Vector2 RotateRadians(Vector2 vec, double radians);
/// <summary>
/// Rotates a Vector2 on the Z-axis by a specified angle in an anti-clockwise
/// direction.
/// </summary>
/// <param name="vec">A Vector2 to rotate.</param>
/// <param name="degrees">
/// Angle to rotate the vector by in an anti-clockwise direction in degrees.
/// </param>
/// <returns>The Vector2 that represents the rotated vector.</returns>
static Vector2 RotateDegrees(Vector2 vec, double degrees);
/// <summary>
/// Computes and returns a Vector2 that is made from the smallest components of
/// the two specified Vector2s.
/// </summary>
/// <param name="lhs">Vector2 to calculate minimum Vector2 with.</param>
/// <param name="rhs">Another Vector2 to calculate minimum Vector2 with.</param>
/// <returns>
/// The Vector2 that contains the smallest components of the two specified
/// Vector2s.
/// </returns>
static Vector2 Min(Vector2 lhs, Vector2 rhs);
/// <summary>
/// Computes and returns a Vector2 that is made from the largest components of
/// the two specified Vector2s.
/// </summary>
/// <param name="lhs">Vector2 to calculate maximum Vector2 with.</param>
/// <param name="rhs">Another Vector2 to calculate maximum Vector2 with.</param>
/// <returns>
/// The Vector2 that contains the largest components of the two specified
/// Vector2s.
/// </returns>
static Vector2 Max(Vector2 lhs, Vector2 rhs);
/// <summary>
/// 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.
/// </summary>
/// <param name="a">The start Vector2, returned when t = 0.0.</param>
/// <param name="b">The end Vector2, returned when t = 1.0.</param>
/// <param name="t">
/// Value used to interpolate between a and b which is clamped to
/// the range[0, 1].
/// </param>
/// <returns>The interpolated Vector2.</returns>
static Vector2 Lerp(Vector2 a, Vector2 b, double t);
/// <summary>
/// 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.
/// </summary>
/// <param name="a">The start Vector2, returned when t = 0.0.</param>
/// <param name="b">The end Vector2, returned when t = 1.0.</param>
/// <param name="t">Value used to interpolate between a and b.</param>
/// <returns>The interpolated Vector2.</returns>
static Vector2 LerpUnclamped(Vector2 a, Vector2 b, double t);
/// <summary>
/// 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
/// </summary>
/// <param name="current">The current position of the point.</param>
/// <param name="target">The target position to move to.</param>
/// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
/// <returns>Vector representing the moved point.</returns>
static Vector2 MoveTowards(Vector2 current, Vector2 target, double maxDistanceDelta);
/*-----------------------------------------------------------------------------*/
/* Overloaded Operators */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds two Vector2s together and returns the result.
/// </summary>
/// <param name="lhs">Vector2 to add.</param>
/// <param name="rhs">Another Vector2 to add.</param>
/// <returns>The result of lhs added to rhs</returns>
static Vector2 operator+(Vector2 lhs, Vector2 rhs);
/// <summary>
/// Subtracts a Vector2 from another Vector2 and returns the result.
/// </summary>
/// <param name="lhs">Vector2 to subtract from.</param>
/// <param name="rhs">Another Vector2 to subtract.</param>
/// <returns>The result of rhs subtracted from lhs.</returns>
static Vector2 operator-(Vector2 lhs, Vector2 rhs);
/// <summary>
/// Calculates the component-wise multiplication of two Vector2s and returns the
/// result.
/// </summary>
/// <param name="lhs">Vector2 to multiply with.</param>
/// <param name="rhs">Another Vector2 to multiply with.</param>
/// <returns>The result of rhs subtracted from lhs.</returns>
static Vector2 operator*(Vector2 lhs, Vector2 rhs);
/// <summary>
/// Calculates the multiplication of a Vector2 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Vector2 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns>
static Vector2 operator*(Vector2 lhs, double rhs);
/// <summary>
/// Calculates the division of a Vector2 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Scalar to divide with.</param>
/// <param name="rhs">Vector2 to divide with.</param>
/// <returns>The result of the scalar division.</returns>
static Vector2 operator/(Vector2 lhs, double rhs);
/// <summary>
/// Checks if two Vector2s are approximately equal. This is equivalent to
/// calling Vector2.IsNear() with default tolerance values.
/// </summary>
/// <param name="lhs">Vector2 to compare.</param>
/// <param name="rhs">Another Vector2 to compare.</param>
/// <returns>
/// True if all components are approximately equal within the default
/// tolerance value.
/// </returns>
static bool operator==(Vector2 lhs, Vector2 rhs);
/// <summary>
/// Checks if two Vector2s are not approximately equal. This is equivalent to
/// calling !Vector2.IsNear() with default tolerance values.
/// </summary>
/// <param name="lhs">Vector2 to compare.</param>
/// <param name="rhs">Another Vector2 to compare.</param>
/// <returns>
/// True if all components are not approximately equal within the default
/// tolerance value.
/// </returns>
static bool operator!=(Vector2 lhs, Vector2 rhs);
};
}

View File

@ -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 <cmath>
#include <algorithm>
// 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<Vector3>(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

View File

@ -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 <limits>
// Project Includes
#include "Vector2.hxx"
namespace SHADE
{
///<summary>
/// CLR version of the the PlushieEngine's Vector3 class that represents a
/// 3-Dimensional Vector. Designed to closely match Unity's Vector3 struct.
/// </summary>
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential)]
public value struct Vector3 : public System::IEquatable<Vector3>
{
public:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
#pragma region Constants
///<summary>
/// Shorthand for writing Vector3(0, 0, -1).
///</summary>
static initonly Vector3 Back = Vector3(0.0, 0.0, -1.0);
///<summary>
/// Shorthand for writing Vector3(0, -1, 0).
///</summary>
static initonly Vector3 Down = Vector3(0.0, -1.0, 0.0);
///<summary>
/// Shorthand for writing Vector3(0, 0, 1).
///</summary>
static initonly Vector3 Forward = Vector3(0.0, 0.0, 1.0);
///<summary>
/// Shorthand for writing Vector3(-1, 0, 0).
///</summary>
static initonly Vector3 Left = Vector3(-1.0, 0.0, 0.0);
///<summary>
/// Shorthand for writing Vector3(double.NegativeInfinity,
/// double.NegativeInfinity, double.NegativeInfinity).
///</summary>
static initonly Vector3 NegativeInfinity = Vector3(std::numeric_limits<double>::lowest(),
std::numeric_limits<double>::lowest(),
std::numeric_limits<double>::lowest());
///<summary>
/// Shorthand for writing Vector3(1, 1, 1).
///</summary>
static initonly Vector3 One = Vector3(1.0, 1.0, 1.0);
///<summary>
/// Shorthand for writing Vector3(double.PositiveInfinity,
/// double.PositiveInfinity, double.PositiveInfinity).
///</summary>
static initonly Vector3 PositiveInfinity = Vector3(std::numeric_limits<double>::max(),
std::numeric_limits<double>::max(),
std::numeric_limits<double>::max());
///<summary>
/// Shorthand for writing Vector3(1, 0, 0).
///</summary>
static initonly Vector3 Right = Vector3(1.0, 0.0, 0.0);
///<summary>
/// Shorthand for writing Vector3(0, 1, 0).
///</summary>
static initonly Vector3 Up = Vector3(0.0, 1.0, 0.0);
///<summary>
/// Shorthand for writing Vector3(0, 0, 0).
///</summary>
static initonly Vector3 Zero = Vector3(0.0, 0.0, 0.0);
#pragma endregion
/*-----------------------------------------------------------------------------*/
/* Public Members */
/*-----------------------------------------------------------------------------*/
///<summary>
/// X-component of the Vector3.
///</summary>
double x;
///<summary>
/// Y-component of the Vector3.
///</summary>
double y;
///<summary>
/// Z-component of the Vector3.
///</summary>
double z;
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor to construct a Vector3 with the specified components with the
/// Y and Z-component set to 0.0.
/// </summary>
/// <param name="_x">X-coordinate to set.</param>
Vector3(double _x);
/// <summary>
/// Constructor to construct a Vector3 with the specified components with the
/// Z-component set to 0.0.
/// </summary>
/// <param name="_x">X-coordinate to set.</param>
/// <param name="_y">Y-coordinate to set.</param>
Vector3(double _x, double _y);
/// <summary>
/// Constructor to construct a Vector3 with the specified components.
/// </summary>
/// <param name="_x">X-coordinate to set.</param>
/// <param name="_y">Y-coordinate to set.</param>
/// <param name="_z">Z-coordinate to set.</param>
Vector3(double _x, double _y, double _z);
/// <summary>
/// Conversion constructor to construct a Vector3 using a Vector2.
/// </summary>
/// <param name="vec"></param>
Vector3(Vector2 vec);
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// 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.
/// </summary>
void Normalise();
/// <summary>
/// Creates a copy of this Vector3 and returns a normalized version.
/// </summary>
/// <returns>
/// Returns a normalised copy of this Vector3.
/// If this Vector3 is a zero vector, a zero vector will be returned.
/// </returns>
Vector3 GetNormalised();
/// <summary>
/// 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.
/// </summary>
/// <returns>Returns the length of this Vector3.</returns>
double GetMagnitude();
/// <summary>
/// Calculates and returns the squared magnitude of this Vector3.
/// </summary>
/// <returns>Returns the squared length of this Vector3.</returns>
double GetSqrMagnitude();
/// <summary>
/// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -Math.PI and Math.PI.
/// </summary>
/// <returns>Returns the angle of this vector from the right vector in radians.</returns>
double Angle2DFromRightRadians();
/// <summary>
/// Calculates and returns the angle of this vector from the right vector. This
/// function returns values between -180.0 and 180.0.
/// </summary>
/// <returns>Returns the angle of this vector from the right vector in degrees.</returns>
double Angle2DFromRightDegrees();
/// <summary>
/// Checks if a specified point is near this Vector3 that represents a point with
/// a tolerance value of PLS_EPSILON.
/// </summary>
/// <param name="point">The other point to check if we are near.</param>
/// <returns>
/// True if this Vector3 representing a point and the specified point are within
/// the range of the specified tolerance. False otherwise.
/// </returns>
bool IsNearPoint(Vector3 point);
/// <summary>
/// Checks if a specified point is near this Vector3 that represents a point.
/// </summary>
/// <param name="point">The other point to check if we are near.</param>
/// <param name="tolerance">
/// The amount of tolerance before we consider these points as "near".
/// </param>
/// <returns>
/// True if this Vector3 representing a point and the specified point are within
/// the range of the specified tolerance. False otherwise.
/// </returns>
bool IsNearPoint(Vector3 point, double tolerance);
/*-----------------------------------------------------------------------------*/
/* IEquatable */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with an object of the same type.
/// </summary>
/// <param name="other">The object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
virtual bool Equals(Vector3 other);
/*-----------------------------------------------------------------------------*/
/* Object */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Compares equality with another unboxed object.
/// </summary>
/// <param name="o">The unboxed object to compare with.</param>
/// <returns>True if both objects are the same.</returns>
bool Equals(Object^ o) override;
/// <summary>
/// Gets a unique hash for this object.
/// </summary>
/// <returns>Unique hash for this object.</returns>
int GetHashCode() override;
/*-----------------------------------------------------------------------------*/
/* Static Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Checks if two specified Vector3s are near in value.
/// </summary>
/// <param name="lhs">Vector3 to check if is near in value.</param>
/// <param name="rhs">Another Vector3 to check if is near in value.</param>
/// <returns>
/// True if the two Vector3s are within the tolerance value specified
/// </returns>
static bool IsNear(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Checks if two specified Vector3s are near in value.
/// </summary>
/// <param name="lhs">Vector3 to check if is near in value.</param>
/// <param name="rhs">Another Vector3 to check if is near in value.</param>
/// <param name="tolerance">Amount of tolerance to do the comparison with.</param>
/// <returns>
/// True if the two Vector3s are within the tolerance value specified
/// </returns>
static bool IsNear(Vector3 lhs, Vector3 rhs, double tolerance);
/// <summary>
/// Computes and returns the dot product of 2 specified Vector3s.
/// </summary>
/// <param name="lhs">Vector3 to calculate dot product with.</param>
/// <param name="rhs">Another Vector3 to calculate dot product with.</param>
/// <returns>Scalar value representing the dot product of the two Vector3s.</returns>
static double Dot(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Computes and returns the cross product of 2 specified Vector3s.
/// </summary>
/// <param name="lhs">Vector3 to calculate cross product with.</param>
/// <param name="rhs">Another Vector3 to calculate cross product with.</param>
/// <returns>The cross product of the two Vector3s.</returns>
static Vector3 Cross(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Computes and returns a Vector3 projection.
/// </summary>
/// <param name="vec">Vector3 to project.</param>
/// <param name="direction">Vector3 to project onto.</param>
/// <returns>The Vector3 that represents the projected vec onto direction.</returns>
static Vector3 Project(Vector3 vec, Vector3 direction);
/// <summary>
/// Reflects a Vector3 across another Vector3.
/// </summary>
/// <param name="vec">A Vector3 to reflect.</param>
/// <param name="normal">A normal to reflect the Vector3 across.</param>
/// <returns>The Vector3 that represents vec reflected across normal.</returns>
static Vector3 Reflect(Vector3 vec, Vector3 normal);
/// <summary>
/// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise
/// direction.
/// </summary>
/// <param name="vec">A Vector3 to rotate.</param>
/// <param name="radians">
/// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 RotateRadians(Vector3 vec, double radians);
/// <summary>
/// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise
/// direction.
/// </summary>
/// <param name="vec">A Vector3 to rotate.</param>
/// <param name="degrees">
/// Angle to rotate the vector by in an anti-clockwise direction in degrees.
/// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 RotateDegrees(Vector3 vec, double degrees);
/// <summary>
/// Computes and returns a Vector3 that is made from the smallest components of
/// the two specified Vector3s.
/// </summary>
/// <param name="lhs">Vector3 to calculate minimum Vector3 with.</param>
/// <param name="rhs">Another Vector3 to calculate minimum Vector3 with.</param>
/// <returns>
/// The Vector3 that contains the smallest components of the two specified
/// Vector3s.
/// </returns>
static Vector3 Min(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Computes and returns a Vector3 that is made from the largest components of
/// the two specified Vector3s.
/// </summary>
/// <param name="lhs">Vector3 to calculate maximum Vector3 with.</param>
/// <param name="rhs">Another Vector3 to calculate maximum Vector3 with.</param>
/// <returns>
/// The Vector3 that contains the largest components of the two specified
/// Vector3s.
/// </returns>
static Vector3 Max(Vector3 lhs, Vector3 rhs);
/// <summary>
/// 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.
/// </summary>
/// <param name="a">The start Vector3, returned when t = 0.0.</param>
/// <param name="b">The end Vector3, returned when t = 1.0.</param>
/// <param name="t">
/// Value used to interpolate between a and b which is clamped to
/// the range[0, 1].
/// </param>
/// <returns>The interpolated Vector3.</returns>
static Vector3 Lerp(Vector3 a, Vector3 b, double t);
/// <summary>
/// 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.
/// </summary>
/// <param name="a">The start Vector3, returned when t = 0.0.</param>
/// <param name="b">The end Vector3, returned when t = 1.0.</param>
/// <param name="t">Value used to interpolate between a and b.</param>
/// <returns>The interpolated Vector3.</returns>
static Vector3 LerpUnclamped(Vector3 a, Vector3 b, double t);
/// <summary>
/// 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
/// </summary>
/// <param name="current">The current position of the point.</param>
/// <param name="target">The target position to move to.</param>
/// <param name="maxDistanceDelta">Maximum distance moved per call.</param>
/// <returns>Vector representing the moved point.</returns>
static Vector3 MoveTowards(Vector3 current, Vector3 target, double maxDistanceDelta);
/*-----------------------------------------------------------------------------*/
/* Overloaded Operators */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds two Vector3s together and returns the result.
/// </summary>
/// <param name="lhs">Vector3 to add.</param>
/// <param name="rhs">Another Vector3 to add.</param>
/// <returns>The result of lhs added to rhs</returns>
static Vector3 operator+(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Subtracts a Vector3 from another Vector3 and returns the result.
/// </summary>
/// <param name="lhs">Vector3 to subtract from.</param>
/// <param name="rhs">Another Vector3 to subtract.</param>
/// <returns>The result of rhs subtracted from lhs.</returns>
static Vector3 operator-(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Calculates the component-wise multiplication of two Vector3s and returns the
/// result.
/// </summary>
/// <param name="lhs">Vector3 to multiply with.</param>
/// <param name="rhs">Another Vector3 to multiply with.</param>
/// <returns>The result of rhs subtracted from lhs.</returns>
static Vector3 operator*(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Calculates the multiplication of a Vector3 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Vector3 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns>
static Vector3 operator*(Vector3 lhs, double rhs);
/// <summary>
/// Calculates the division of a Vector3 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Scalar to divide with.</param>
/// <param name="rhs">Vector3 to divide with.</param>
/// <returns>The result of the scalar division.</returns>
static Vector3 operator/(Vector3 lhs, double rhs);
/// <summary>
/// Checks if two Vector3s are approximately equal. This is equivalent to
/// calling Vector3.IsNear() with default tolerance values.
/// </summary>
/// <param name="lhs">Vector3 to compare.</param>
/// <param name="rhs">Another Vector3 to compare.</param>
/// <returns>
/// True if all components are approximately equal within the default
/// tolerance value.
/// </returns>
static bool operator==(Vector3 lhs, Vector3 rhs);
/// <summary>
/// Checks if two Vector3s are not approximately equal. This is equivalent to
/// calling !Vector3.IsNear() with default tolerance values.
/// </summary>
/// <param name="lhs">Vector3 to compare.</param>
/// <param name="rhs">Another Vector3 to compare.</param>
/// <returns>
/// True if all components are not approximately equal within the default
/// tolerance value.
/// </returns>
static bool operator!=(Vector3 lhs, Vector3 rhs);
/*-----------------------------------------------------------------------------*/
/* Conversion Operators */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Explicit conversion operator to enable explicit casting from a Vector3 to a
/// Vector2.
/// </summary>
/// <param name="vec">Vector3 to convert from.</param>
static explicit operator Vector2(Vector3 vec);
/// <summary>
/// Explicit conversion operator to enable explicit casting from a Vector2 to a
/// Vector3.
/// </summary>
/// <param name="vec">Vector2 to convert from.</param>
static explicit operator Vector3(Vector2 vec);
};
} // namespace PlushieAPI::Mathematics

View File

@ -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"

31
SHADE_Managed/src/SHpch.h Normal file
View File

@ -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 <Windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <array>
#include <utility>
#include <unordered_map>
#include <map>
#include <tuple>
#include <functional>
#include <sstream>
#include <iomanip>

View File

@ -0,0 +1,171 @@
/************************************************************************************//*!
\file Script.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 PlushieScript 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 "Script.hxx"
// Project Headers
#include "Utility/Debug.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Component Access Functions */
/*---------------------------------------------------------------------------------*/
generic <typename T>
T Script::AddComponent()
{
return owner.AddComponent<T>();
}
generic <typename T>
T Script::GetComponent()
{
return owner.GetComponent<T>();
}
generic <typename T>
T Script::GetComponentInChildren()
{
return owner.GetComponentInChildren<T>();
}
generic <typename T>
T Script::EnsureComponent()
{
return owner.EnsureComponent<T>();
}
generic <typename T>
void Script::RemoveComponent()
{
throw gcnew System::NotImplementedException;
//ECS::RemoveComponent<T>(owner.GetNativeEntity());
}
/*---------------------------------------------------------------------------------*/
/* Script Access Functions */
/*---------------------------------------------------------------------------------*/
generic <typename T>
T Script::AddScript()
{
throw gcnew System::NotImplementedException;
//return ScriptStore::AddScript<T>(owner.GetEntity());
}
generic <typename T>
T Script::GetScript()
{
throw gcnew System::NotImplementedException;
//return ScriptStore::GetScript<T>(owner.GetEntity());
}
generic <typename T>
T Script::GetScriptInChildren()
{
throw gcnew System::NotImplementedException;
//return ScriptStore::GetScriptInChildren<T>(owner.GetEntity());
}
generic <typename T>
System::Collections::Generic::IEnumerable<T>^ Script::GetScripts()
{
throw gcnew System::NotImplementedException;
//return ScriptStore::GetScripts<T>(owner.GetEntity());
}
generic <typename T>
void Script::RemoveScript()
{
throw gcnew System::NotImplementedException;
//ScriptStore::RemoveScript<T>(owner.GetEntity());
}
/*---------------------------------------------------------------------------------*/
/* "All-time" Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void Script::OnAttached()
{
SAFE_NATIVE_CALL_BEGIN
onAttached();
SAFE_NATIVE_CALL_END(this)
}
void Script::OnDetached()
{
SAFE_NATIVE_CALL_BEGIN
onDetatched();
SAFE_NATIVE_CALL_END(this)
}
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void Script::Awake()
{
SAFE_NATIVE_CALL_BEGIN
awake();
SAFE_NATIVE_CALL_END(this)
}
void Script::Start()
{
SAFE_NATIVE_CALL_BEGIN
start();
SAFE_NATIVE_CALL_END(this)
}
void Script::FixedUpdate()
{
SAFE_NATIVE_CALL_BEGIN
fixedUpdate();
SAFE_NATIVE_CALL_END(this)
}
void Script::Update()
{
SAFE_NATIVE_CALL_BEGIN
update();
SAFE_NATIVE_CALL_END(this)
}
void Script::LateUpdate()
{
SAFE_NATIVE_CALL_BEGIN
lateUpdate();
SAFE_NATIVE_CALL_END(this)
}
void Script::OnDestroy()
{
SAFE_NATIVE_CALL_BEGIN
onDestroy();
SAFE_NATIVE_CALL_END(this)
}
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
Script::Script(GameObject gameObj)
: owner { gameObj }
{}
/*---------------------------------------------------------------------------------*/
/* Virtual "All-Time" Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void Script::onAttached() {}
void Script::onDetatched() {}
/*---------------------------------------------------------------------------------*/
/* Virtual Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void Script::awake() {}
void Script::start() {}
void Script::fixedUpdate() {}
void Script::update() {}
void Script::lateUpdate() {}
void Script::onDestroy() {}
}// namespace PlushieAPI

View File

@ -0,0 +1,274 @@
/************************************************************************************//*!
\file Script.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 28, 2021
\brief Contains the definition of the Script 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 "Engine/GameObject.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
ref class BaseComponent;
/*---------------------------------------------------------------------------------*/
/* Class Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Class that forms the basis of all "script"-objects that can be attached to
/// Entities to update each Entity's Components via C# code.
/// </summary>
public ref class Script
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// GameObject that this Script belongs to.
/// </summary>
property GameObject Owner
{
GameObject get() { return owner; }
}
/*-----------------------------------------------------------------------------*/
/* Component Access Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Component to the GameObject that this Script belongs to.
/// </summary>
/// <typeparam name="T">
/// Type of the Component to add. Must be derived from BaseComponent.
/// </typeparam>
/// <returns>Reference to the Component that was added.</returns>
generic<typename T> where T : BaseComponent
T AddComponent();
/// <summary>
/// Gets a Component from the GameObject that this Script belongs to.
/// </summary>
/// <typeparam name="T">
/// Type of the Component to get. Must be derived from BaseComponent.
/// </typeparam>
/// <returns>Reference to the Component that was retrieved.</returns>
generic<typename T> where T : BaseComponent
T GetComponent();
/// <summary>
/// Retrieves the first Component from this GameObject's children that matches
/// the specified type.
/// </summary>
/// <typeparam name="T">
/// Type of the Component to get. Must be derived from BaseComponent.
/// </typeparam>
/// <returns>Reference to the Component that was retrieved.</returns>
generic<typename T> where T : BaseComponent
T GetComponentInChildren();
/// <summary>
/// Ensures a Component on the GameObject that this Script belongs to.
/// </summary>
/// <typeparam name="T">
/// Type of the Component to ensure. Must be derived from BaseComponent.
/// </typeparam>
/// <returns>Reference to the Component.</returns>
generic<typename T> where T : BaseComponent
T EnsureComponent();
/// <summary>
/// Removes a Component from the GameObject that this Script belongs to.
/// </summary>
/// <typeparam name="T">
/// Type of the Component to remove. Must be derived from BaseComponent.
/// </typeparam>
generic<typename T> where T : BaseComponent
void RemoveComponent();
/*-----------------------------------------------------------------------------*/
/* Script Access Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Script to this GameObject.
/// </summary>
/// <typeparam name="T">
/// Type of script to add.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <returns>Reference to the script added</returns>
generic<typename T> where T : ref class, Script
T AddScript();
/// <summary>
/// Retrieves the first Script from this GameObject that matches the specified
/// type.
/// </summary>
/// <typeparam name="T">
/// Type of script to get.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <returns>Reference to the script added</returns>
generic<typename T> where T : ref class, Script
T GetScript();
/// <summary>
/// Retrieves the first Script from this GameObject's children that matches the
/// specified type.
/// </summary>
/// <typeparam name="T">
/// Type of script to get.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <returns>Reference to the script added</returns>
generic<typename T> where T : ref class, Script
T GetScriptInChildren();
/// <summary>
/// Retrieves a immutable list of scripts from the specified Entity that
/// matches the specified type.
/// <br/>
/// Note that this function allocates. It should be used sparingly.
/// </summary>
/// <typeparam name="T">
/// Type of scripts to get.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <returns>
/// Immutable list of references to scripts of the specified type.
/// </returns>
generic<typename T> where T : ref class, Script
System::Collections::Generic::IEnumerable<T>^ GetScripts();
/// <summary>
/// Removes all Scripts of the specified type from this GameObject.
/// </summary>
/// <typeparam name="T">
/// Type of script to remove.
/// This needs to be a default constructable Script.
/// </typeparam>
generic<typename T> where T : ref class, Script
void RemoveScript();
internal:
/*-----------------------------------------------------------------------------*/
/* "All-Time" Lifecycle Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Used to call onAttached(). This is called immediately when this script is
/// attached to a GameObject.
/// </summary>
void OnAttached();
/// <summary>
/// Used to call onDetached(). This is called immediately when this script is
/// detached from a GameObject.
/// </summary>
void OnDetached();
/*-----------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Used to call awake(). This should be called on the first frame that the
/// attached GameObject is active if they are a part of the scene.
/// </summary>
void Awake();
/// <summary>
/// Used to call start(). This should be called on the first frame that the
/// attached GameObject is active but always after Awake().
/// </summary>
void Start();
/// <summary>
/// Used to call fixedUpdate(). This should be called in sync with Physics
/// update steps and thus in most cases will execute more than Update() will.
/// This will be called immediately before a Physics update step.
/// </summary>
void FixedUpdate();
/// <summary>
/// Used to call update(). This should be called every frame before physics and
/// collision resolution.
/// </summary>
void Update();
/// <summary>
/// Used to call lateUpdate(). This should be called every frame after physics
/// and collision resolution but before rendering.
/// </summary>
void LateUpdate();
/// <summary>
/// Used to call onDestroy(). This should be called at the end of the frame
/// where the attached GameObject or this script is destroyed directly or
/// indirectly due to destruction of the owner.
/// </summary>
void OnDestroy();
protected:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for Script to tie it to a specific GameObject.
/// Constructors of derived Scripts should call this Constructor.
/// </summary>
/// <param name="gameObj">
/// GameObject that this Script will be tied to.
/// </param>
Script(GameObject gameObj);
/*-----------------------------------------------------------------------------*/
/* Virtual "All-Time" Lifecycle Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Called immediately once this script is attached to a GameObject.
/// </summary>
virtual void onAttached();
/// <summary>
/// Called immediately once this script is detached from a GameObject.
/// </summary>
virtual void onDetatched();
/*-----------------------------------------------------------------------------*/
/* Virtual Lifecycle Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Called on the first frame that the attached GameObject is active if they are
/// a part of the scene.
/// </summary>
virtual void awake();
/// <summary>
/// Called on the first frame that the attached GameObject is active but always
/// after Awake().
/// </summary>
virtual void start();
/// <summary>
/// Called every frame in sync with Physics update steps and thus in most cases
/// will execute more than update() will. This will be called immediately before
/// a Physics update step.
/// </summary>
virtual void fixedUpdate();
/// <summary>
/// Called every frame before physics and collision resolution.
/// </summary>
virtual void update();
/// <summary>
/// Called every frame after physics and collision resolution but before
/// rendering.
/// </summary>
virtual void lateUpdate();
/// <summary>
/// Called just before the end of the frame where the attached GameObject or
/// this script is destroyed directly or indirectly due to destruction of the
/// owner.
/// </summary>
virtual void onDestroy();
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
GameObject owner;
};
} // namespace PlushieAPI

View File

@ -0,0 +1,673 @@
/************************************************************************************//*!
\file ScriptStore.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 ScriptStore 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 "ScriptStore.hxx"
// Standard Libraries
#include <sstream>
// External Dependencies
#include "ECS_Base/System/SHEntityManager.h"
// Project Headers
#include "Utility/Debug.hxx"
#include "Utility/Convert.hxx"
#include "Script.hxx"
#include "Engine/Entity.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Scripts Manipulation Functions */
/*---------------------------------------------------------------------------------*/
generic<typename T>
T ScriptStore::AddScript(Entity entity)
{
// Check if entity exists
if (!EntityUtils::IsValid(entity))
throw gcnew System::ArgumentException("Invalid Entity provided to add a Script to.");
System::Collections::Generic::List<Script^> ^ entityScriptList;
// Check if storage for scripts of this entity exists
if (!scripts.ContainsKey(entity))
{
// Create a new list for this set of scripts
entityScriptList = gcnew System::Collections::Generic::List<Script^>();
scripts.Add(entity, entityScriptList);
}
else
{
entityScriptList = scripts[entity];
}
// Create the script and add it in
array<Object^>^ params = gcnew array<Object^>{GameObject(entity)};
Script^ script = safe_cast<Script^>(System::Activator::CreateInstance(T::typeid, params));
entityScriptList->Add(script);
awakeList.Add(script);
startList.Add(script);
script->OnAttached();
return safe_cast<T>(script);
}
bool ScriptStore::AddScriptViaName(Entity entity, System::String^ scriptName)
{
SAFE_NATIVE_CALL_BEGIN
Script^ script;
return AddScriptViaNameWithRef(entity, scriptName, script);
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
return false;
}
bool ScriptStore::AddScriptViaNameWithRef(Entity entity, System::String^ scriptName, Script^% createdScript)
{
// Check if we are set up to get scripts
if (addScriptMethod == nullptr)
{
Debug::LogError("[ScriptStore] Native AddScript<T>() was not loaded. Unable to add scripts.");
return false;
}
// Get the script if it exists
System::Type^ scriptType = getScriptType(scriptName);
if (scriptType == nullptr)
{
std::ostringstream oss;
oss << "[ScriptStore] No Script named "
<< Convert::ToNative(scriptName)
<< " found!";
Debug::LogError(oss.str());
return false;
}
// Otherwise, add the script
System::Reflection::MethodInfo^ method = addScriptMethod->MakeGenericMethod(scriptType);
try
{
array<Object^>^ params = gcnew array<Object^>{entity};
createdScript = safe_cast<Script^>(method->Invoke(nullptr, params));
}
catch (System::Exception^ e)
{
std::ostringstream oss;
oss << "[ScriptStore] Failed to add Script named \"" << Convert::ToNative(scriptName)
<< "\" to Entity #" << entity << "! (" << Convert::ToNative(e->GetType()->Name) << ")";
Debug::LogError(oss.str());
return false;
}
return true;
}
generic<typename T>
T ScriptStore::GetScript(Entity entity)
{
// Check if entity exists
if (!EntityUtils::IsValid(entity))
throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from.");
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
{
return T();
}
// Search for and obtain
for each (Script^ script in scripts[entity])
{
try
{
T actualScript = safe_cast<T>(script);
return actualScript;
}
catch (System::InvalidCastException^)
{
continue;
}
}
return T();
}
generic <typename T>
T ScriptStore::GetScriptInChildren(Entity entity)
{
// Check if entity exists and is a valid GameObject
if (!EntityUtils::IsValid(entity))
throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from.");
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
{
return T();
}
// Get Transform component and get the children list
throw gcnew System::NotImplementedException;
//Pls::Transform* tf = Pls::ECS::GetComponent<Pls::Transform>(Convert::ToNative(entity));
//if (tf == nullptr)
// return T();
//// Search direct children first
//for (const auto& child : tf->GetChildren())
//{
// T script = GetScript<T>(Convert::ToCLI(child));
// if (script != nullptr)
// return script;
//}
//// Search their children
//for (const auto& child : tf->GetChildren())
//{
// T script = GetScriptInChildren<T>(Convert::ToCLI(child));
// if (script != nullptr)
// return script;
//}
// None here
return T();
}
generic <typename T>
System::Collections::Generic::IEnumerable<T>^ ScriptStore::GetScripts(Entity entity)
{
// Check if entity exists and is a valid GameObject
if (!EntityUtils::IsValid(entity))
throw gcnew System::ArgumentException("Invalid Entity provided to get a Script from.");
// Create a list to store entries
System::Collections::Generic::List<T>^ foundScripts = gcnew System::Collections::Generic::List<T>();
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
{
return foundScripts;
}
// Search for and obtain
for each (Script^ script in scripts[entity])
{
try
{
T actualScript = safe_cast<T>(script);
foundScripts->Add(actualScript);
}
catch (System::InvalidCastException^)
{
continue;
}
}
return foundScripts;
}
System::Collections::Generic::IEnumerable<Script^>^ ScriptStore::GetAllScripts(Entity entity)
{
// Check if entity exists
if (!EntityUtils::IsValid(entity))
return nullptr;
// Check if entity exists in the script storage
if (scripts.ContainsKey(entity))
{
return scripts[entity];
}
return nullptr;
}
generic<typename T>
void ScriptStore::RemoveScript(Entity entity)
{
// Check if entity exists
if (!EntityUtils::IsValid(entity))
throw gcnew System::ArgumentException("Invalid Entity provided to remove a Script from.");
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
{
Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!");
return;
}
// Search for and obtain
for each (Script^ script in scripts[entity])
{
try
{
safe_cast<T>(script);
removeScript(script);
}
catch (System::InvalidCastException^)
{
continue;
}
}
}
bool ScriptStore::RemoveScript(Entity entity, Script^ script)
{
// Check if entity exists
if (!EntityUtils::IsValid(entity))
{
Debug::LogError("[ScriptStore] Attempted to remove a Script from an invalid Entity!");
return false;
}
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
{
Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!");
return false;
}
// Check if the script exists to begin with
if (!scripts[entity]->Contains(script))
{
Debug::LogError("[ScriptStore] Attempted to remove a Script that does not belong to the specified Entity!");
return false;
}
// Script found, queue it for deletion
removeScript(script);
return true;
}
void ScriptStore::RemoveAllScripts(Entity entity)
{
SAFE_NATIVE_CALL_BEGIN
// Check if entity exists
if (!EntityUtils::IsValid(entity))
{
Debug::LogError("[ScriptStore] Attempted to remove Scripts from an invalid Entity!");
return;
}
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
return;
// Search for and clear
System::Collections::Generic::List<Script^>^ scriptList = scripts[entity];
for each (Script^ script in scriptList)
{
removeScript(script);
}
scriptList->Clear();
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
void ScriptStore::RemoveAllScriptsImmediately(Entity entity, bool callOnDestroy)
{
SAFE_NATIVE_CALL_BEGIN
// Check if entity exists
if (!EntityUtils::IsValid(entity))
{
Debug::LogError("[ScriptStore] Attempted to remove Scripts from an invalid Entity!");
return;
}
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
return;
// Clear all
System::Collections::Generic::List<Script^>^ scriptList = scripts[entity];
for each (Script ^ script in scriptList)
{
// Call OnDestroy only if indicated and also in play mode
if (callOnDestroy)
{
script->OnDestroy();
}
script->OnDetached();
// Remove scripts from awakening if they were not woken up to begin with
awakeList.Remove(script);
startList.Remove(script);
}
scriptList->Clear();
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void ScriptStore::Init()
{
// Create an enumerable list of script types
refreshScriptTypeList();
// Get stored methods for interop variants of functions
getGenericMethods();
}
void ScriptStore::FrameSetUp()
{
SAFE_NATIVE_CALL_BEGIN
// Clear the awake queue
for each (Script^ script in awakeList)
{
script->Awake();
}
awakeList.Clear();
// Clear the start queue
for each (Script^ script in startList)
{
if (script->Owner.IsActiveInHierarchy)
{
script->Start();
}
else
{
inactiveStartList.Add(script);
}
}
startList.Clear();
startList.AddRange(%inactiveStartList);
inactiveStartList.Clear();
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
void ScriptStore::FrameCleanUp()
{
SAFE_NATIVE_CALL_BEGIN
// Clear the queue
while (disposalQueue.Count > 0)
{
Script^ script = disposalQueue.Dequeue();
/*if (Application::IsPlaying)
{
script->OnDestroy();
}*/
auto entity = script->Owner.GetEntity();
auto scriptList = scripts[script->Owner.GetEntity()];
scriptList->Remove(script);
if (scriptList->Count <= 0)
{
scripts.Remove(entity);
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
void ScriptStore::Exit()
{
SAFE_NATIVE_CALL_BEGIN
// Run the deinit all scripts if needed
//if (Application::IsPlaying)
{
Debug::Log("Running OnDestroy() for scripts.");
for each (System::Collections::Generic::KeyValuePair<Entity, ScriptList^> entity in scripts)
{
for each (Script^ script in entity.Value)
{
script->OnDestroy();
}
}
}
// Clear Script Storage
scripts.Clear();
awakeList.Clear();
startList.Clear();
disposalQueue.Clear();
scriptTypeList = nullptr;
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
/*---------------------------------------------------------------------------------*/
/* Script Information Functions */
/*---------------------------------------------------------------------------------*/
System::Collections::Generic::IEnumerable<System::Type^>^ ScriptStore::GetAvailableScriptList()
{
return scriptTypeList;
}
/*---------------------------------------------------------------------------------*/
/* Script Execution Functions */
/*---------------------------------------------------------------------------------*/
void ScriptStore::ExecuteFixedUpdate()
{
SAFE_NATIVE_CALL_BEGIN
for each (System::Collections::Generic::KeyValuePair<Entity, ScriptList^> entity in scripts)
{
// Check active state
if (!isEntityActive(entity.Key))
continue;
// Update each script
for each (Script^ script in entity.Value)
{
script->FixedUpdate();
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
void ScriptStore::ExecuteUpdate()
{
SAFE_NATIVE_CALL_BEGIN
for each (System::Collections::Generic::KeyValuePair<Entity, ScriptList^> entity in scripts)
{
// Check active state
if (!isEntityActive(entity.Key))
continue;
// Update each script
for each (Script^ script in entity.Value)
{
script->Update();
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
void ScriptStore::ExecuteLateUpdate()
{
SAFE_NATIVE_CALL_BEGIN
for each (System::Collections::Generic::KeyValuePair<Entity, ScriptList^> entity in scripts)
{
// Check active state
if (!isEntityActive(entity.Key))
continue;
// Update each script
for each (Script^ script in entity.Value)
{
script->LateUpdate();
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
}
bool ScriptStore::SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize)
{
SAFE_NATIVE_CALL_BEGIN
// Create a buffer that we can work with temporarily
System::Text::StringBuilder^ jsonString = gcnew System::Text::StringBuilder();
// Check if entity exists, otherwise nothing
if (!EntityUtils::IsValid(entity))
return true;
// Check if entity exists in the script storage
if (!scripts.ContainsKey(entity))
return true;
// Serialise each script
System::Collections::Generic::List<Script^>^ scriptList = scripts[entity];
for (int i = 0; i < scriptList->Count; ++i)
{
throw gcnew System::NotImplementedException;
//jsonString->Append(ReflectionUtilities::Serialise(scriptList[i]));
// Only add separator if is not last script
if (i != scriptList->Count - 1)
{
jsonString->Append(",\r\n");
}
}
// Check if the size is too big
if (jsonString->Length > bufferSize)
return false;
// Otherwise we copy it over
buffer->Clear();
buffer->Append(jsonString->ToString());
return true;
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
return false;
}
bool ScriptStore::DeserialiseScript(Entity entity, System::String^ yaml)
{
SAFE_NATIVE_CALL_BEGIN
// Check if entity exists, otherwise nothing
if (!EntityUtils::IsValid(entity))
return false;
// Get the name of the script
const int FIRST_QUOTE = yaml->IndexOf('\"');
const int FIRST_COLON = yaml->IndexOf(':');
if (FIRST_QUOTE < 0 || FIRST_COLON < 0) // No script name, it's invalid
return false;
const int SCRIPT_NAME_START = FIRST_QUOTE + 1;
const int SCRIPT_NAME_END = FIRST_COLON - 1;
System::String^ typeName = yaml->Substring(SCRIPT_NAME_START, SCRIPT_NAME_END - SCRIPT_NAME_START);
// Create the script
Script^ script;
if (AddScriptViaNameWithRef(entity, typeName, script))
{
// Copy the data in
throw gcnew System::NotImplementedException;
//ReflectionUtilities::Deserialise(json, script);
return true;
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
return false;
}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void ScriptStore::removeScript(Script^ script)
{
// Prepare for disposal
disposalQueue.Enqueue(script);
// Also remove it fromm awake and start queues if they were created but not initialised
awakeList.Remove(script);
startList.Remove(script);
script->OnDetached();
}
namespace
{
/* Select Many */
ref struct Pair
{
System::Reflection::Assembly^ assembly;
System::Type^ type;
};
System::Collections::Generic::IEnumerable<System::Type^>^ selectorFunc(System::Reflection::Assembly^ assembly)
{
return assembly->GetExportedTypes();
}
Pair^ resultSelectorFunc(System::Reflection::Assembly^ assembly, System::Type^ type)
{
Pair^ p = gcnew Pair();
p->assembly = assembly;
p->type = type;
return p;
}
/* Where */
bool predicateFunc(Pair^ pair)
{
return pair->type->IsSubclassOf(Script::typeid) && !pair->type->IsAbstract;
}
/* Select */
System::Type^ selectorFunc(Pair^ pair)
{
return pair->type;
}
}
void ScriptStore::refreshScriptTypeList()
{
using namespace System;
using namespace System::Reflection;
using namespace System::Linq;
using namespace System::Collections::Generic;
/* Select Many: Types in Loaded Assemblies */
IEnumerable<Assembly^>^ assemblies = AppDomain::CurrentDomain->GetAssemblies();
Func<Assembly^, IEnumerable<Type^>^>^ collectionSelector = gcnew Func<Assembly^, IEnumerable<Type^>^>(selectorFunc);
Func<Assembly^, Type^, Pair^>^ resultSelector = gcnew Func<Assembly^, Type^, Pair^>(resultSelectorFunc);
IEnumerable<Pair^>^ selectManyResult = Enumerable::SelectMany(assemblies, collectionSelector, resultSelector);
/* Where: Are concrete Scripts */
Func<Pair^, bool>^ predicate = gcnew Func<Pair^, bool>(predicateFunc);
IEnumerable<Pair^>^ whereResult = Enumerable::Where(selectManyResult, predicate);
/* Select: Select them all */
Func<Pair^, Type^>^ selector = gcnew Func<Pair^, Type^>(selectorFunc);
scriptTypeList = Enumerable::Select(whereResult, selector);
// Log
std::ostringstream oss;
oss << "[ScriptStore] Successfully retrieved references to " << Enumerable::Count(scriptTypeList)
<< " Script(s) from currently loaded assemblies.";
Debug::Log(oss.str());
}
void ScriptStore::getGenericMethods()
{
addScriptMethod = ScriptStore::typeid->GetMethod("AddScript");
if (addScriptMethod == nullptr)
{
Debug::LogError("[ScriptStore] Failed to get MethodInfo of \"AddScript<T>()\". Adding of scripts from native code will fail.");
}
}
System::Type^ ScriptStore::getScriptType(System::String^ scriptName)
{
// Remove any whitespaces just in case
scriptName = scriptName->Trim();
// Look for the correct script
for each (System::Type^ type in scriptTypeList)
{
if (type->FullName == scriptName || type->Name == scriptName)
{
return type;
}
}
return nullptr;
}
bool ScriptStore::isEntityActive(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.");
// Check active state
return nativeEntity->isActive;
}
}

View File

@ -0,0 +1,301 @@
/************************************************************************************//*!
\file ScriptStore.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 "Engine/Entity.hxx"
#include "Script.hxx"
namespace SHADE
{
/// <summary>
/// Responsible for managing all scripts attached to Entities as well as executing
/// all lifecycle functions of scripts.
/// </summary>
public ref class ScriptStore abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Scripts Manipulation Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Adds a Script to a specified Entity.
/// </summary>
/// <typeparam name="T">
/// Type of script to add.
/// This needs to be a default constructable PlushieScript.
/// </typeparam>
/// <param name="entity">The entity to add a script to.</param>
/// <returns>Reference to the script added.</returns>
/// <exception cref="ArgumentException">
/// If the specified Entity is invalid.
/// </exception>
generic<typename T> where T : ref class, Script
static T AddScript(Entity entity);
/// <summary>
/// Adds a Script to a specified Entity.
/// <br/>
/// This function is meant for consumption from native code. If you are writing
/// in C# or C++/CLI, use AddScript&lt;T&gt;() instead as it is faster.
/// </summary>
/// <param name="entity">The entity to add a script to.</param>
/// <param name="scriptName">The entity to add a script to.</param>
/// <returns>
/// True if successfully added. False otherwise with the error logged to the
/// console.
/// </returns>
static bool AddScriptViaName(Entity entity, System::String^ scriptName);
/// <summary>
/// Adds a Script to a specified Entity.
/// <br/>
/// This function is meant for consumption from native code or for serialisation
/// purposes. If you are writing in C# or C++/CLI and not doing serialisation,
/// use AddScript&lt;T&gt;() instead as it is faster.
/// </summary>
/// <param name="entity">The entity to add a script to.</param>
/// <param name="scriptName">The entity to add a script to.</param>
/// <param name="createdScript">
/// Out parameter handle to the Script that was created.
/// </param>
/// <returns>
/// True if successfully added. False otherwise with the error logged to the
/// console.
/// </returns>
static bool AddScriptViaNameWithRef(Entity entity, System::String^ scriptName, [System::Runtime::InteropServices::Out] Script^% createdScript);
/// <summary>
/// Retrieves the first Script from the specified Entity that matches the
/// specified type.
/// </summary>
/// <typeparam name="T">
/// Type of script to get.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <param name="entity">
/// The entity which the script to retrieve is attached.
/// </param>
/// <returns>
/// Reference to the script. This can be null if no script of the specified
/// type is attached.
/// </returns>
/// <exception cref="ArgumentException">
/// If the specified Entity is invalid.
/// </exception>
generic<typename T> where T : ref class, Script
static T GetScript(Entity entity);
/// <summary>
/// Retrieves the first Script from the specified Entity's children that matches
/// the specified type.
/// </summary>
/// <typeparam name="T">
/// Type of script to get.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <param name="entity">
/// The entity which the script to retrieve is attached.
/// </param>
/// <returns>
/// Reference to the script. This can be null if no script of the specified
/// type is attached.
/// </returns>
/// <exception cref="ArgumentException">
/// If the specified Entity is invalid.
/// </exception>
generic<typename T> where T : ref class, Script
static T GetScriptInChildren(Entity entity);
/// <summary>
/// Retrieves a immutable list of scripts from the specified Entity that
/// matches the specified type.
/// <br/>
/// Note that this function allocates. It should be used sparingly.
/// </summary>
/// <typeparam name="T">
/// Type of scripts to get.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <param name="entity">
/// The entity which the scripts to retrieve are attached.
/// </param>
/// <returns>
/// Immutable list of references to scripts of the specified type.
/// </returns>
generic<typename T> where T : ref class, Script
static System::Collections::Generic::IEnumerable<T> ^ GetScripts(Entity entity);
/// <summary>
/// Retrieves an immutable list of all scripts attached to a specified Entity.
/// </summary>
/// <param name="entity">
/// The entity which the scripts to retrieve are attached.
/// </param>
/// <returns>
/// Immutable list of references to scripts attached to the specified Entity.
/// This can also be null if there are no scripts at all or an invalid Entity
/// was specified.
/// </returns>
static System::Collections::Generic::IEnumerable<Script^>^ GetAllScripts(Entity entity);
/// <summary>
/// Removes all Scripts of the specified type from the specified Entity.
/// </summary>
/// <typeparam name="T">
/// Type of script to remove.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <param name="entity">The entity to remove the script from.</param>
/// <exception cref="ArgumentException">
/// If the specified Entity is invalid.
/// </exception>
generic<typename T> where T : ref class, Script
static void RemoveScript(Entity entity);
/// <summary>
/// Removes a specific script from the
/// </summary>
/// <param name="entity">The entity to remove the script from.</param>
/// <param name="script">The script to remove.</param>
/// <returns>True if successfully removed. False otherwise.</returns>
static bool RemoveScript(Entity entity, Script^ script);
/// <summary>
/// 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.
/// </summary>
/// <param name="entity">The entity to remove the scripts from.</param>
static void RemoveAllScripts(Entity entity);
/// <summary>
/// Removes all Scripts attached to the specified Entity. Unlike
/// RemoveAllScripts(), this removes all the scripts immediately.
/// Does not do anything if the specified Entity is invalid or does not have any
/// Scripts attached.
/// </summary>
/// <param name="entity">The entity to remove the scripts from.</param>
/// <param name="callOnDestroy">
/// Whether or not to call OnDestroy on the scripts.This is ignored if not in
/// play mode.
/// </param>
static void RemoveAllScriptsImmediately(Entity entity, bool callOnDestroy);
internal:
/*-----------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Initializes the ScriptStore to allocate and pre-populate reflection data.
/// </summary>
static void Init();
/// <summary>
/// Sets up scripts that were marked for initialization. This calls the Awake()
/// and Start() for Scripts that have yet to have done so.
/// </summary>
static void FrameSetUp();
/// <summary>
/// Cleans up scripts that were marked for deletion. This calls the OnDestroy()
/// for these Scripts.
/// </summary>
static void FrameCleanUp();
/// <summary>
/// Cleans up data stored in the ScriptStore to free up memory for garbage
/// collection.
/// </summary>
static void Exit();
/*-----------------------------------------------------------------------------*/
/* Script Information Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves a immutable list of available scripts that can be added.
/// </summary>
/// <returns>Immutable list of available scripts that can be added.</returns>
static System::Collections::Generic::IEnumerable<System::Type^>^ GetAvailableScriptList();
/*-----------------------------------------------------------------------------*/
/* Script Execution Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Executes FixedUpdate() for all scripts.
/// </summary>
static void ExecuteFixedUpdate();
/// <summary>
/// Executes Update() for all scripts.
/// </summary>
static void ExecuteUpdate();
/// <summary>
/// Executes LateUpdate() for all scripts.
/// </summary>
static void ExecuteLateUpdate();
/*-----------------------------------------------------------------------------*/
/* Serialisation Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Generates a JSON string that represents the set of Scripts attached
/// to the specified Entity.
/// <br/> <br/>
/// This function should only be called from native unmanaged code.
/// </summary>
/// <param name="entity">The Entity to Serialise.</param>
/// <param name="buffer">
/// StringBuilder handle that maps to a native char array that will contain the
/// serialised string.
/// </param>
/// <param name="bufferSize">
/// The size of the char array.
/// </param>
/// <returns>
/// True if serialisation is successful. False if the buffer is too small for
/// the serialised output.
/// </returns>
static bool SerialiseScripts(Entity entity, System::Text::StringBuilder^ buffer, int bufferSize);
/// <summary>
/// Processes a JSON string that represents a single Script and attaches
/// it onto the specified Entity.
/// <br/> <br/>
/// This function should only be called from native unmanaged code.
/// </summary>
/// <param name="entity">
/// The Entity to attach the deserialised Scripts to.
/// </param>
/// <param name="yaml">
/// JSON string that describes the Script to serialise.
/// </param>
/// <returns></returns>
static bool DeserialiseScript(Entity entity, System::String^ yaml);
private:
/*-----------------------------------------------------------------------------*/
/* Type Definition */
/*-----------------------------------------------------------------------------*/
using ScriptList = System::Collections::Generic::List<Script^>;
using ScriptDictionary = System::Collections::Generic::Dictionary<Entity, ScriptList^>;
using ScriptQueue = System::Collections::Generic::Queue<Script^>;
/*-----------------------------------------------------------------------------*/
/* Static Data Members */
/*-----------------------------------------------------------------------------*/
static ScriptDictionary scripts;
static ScriptList awakeList;
static ScriptList startList;
static ScriptList inactiveStartList;
static ScriptQueue disposalQueue;
static System::Collections::Generic::IEnumerable<System::Type^>^ scriptTypeList;
static System::Reflection::MethodInfo^ addScriptMethod;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
static void removeScript(Script^ script);
static void refreshScriptTypeList();
static void getGenericMethods();
static System::Type^ getScriptType(System::String^ scriptName);
static bool isEntityActive(Entity entity);
};
} // namespace PlushieAPI

View File

@ -0,0 +1,45 @@
/************************************************************************************//*!
\file Convert.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 Convert 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 "Convert.hxx"
// External Dependencies
#include "ECS_Base/System//SHEntityManager.h"
#include <msclr/marshal_cppstd.h>
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* ECS Conversions */
/*---------------------------------------------------------------------------------*/
Entity Convert::ToCLI(SHEntity entity)
{
return static_cast<Entity>(entity.GetEID());
}
/*---------------------------------------------------------------------------------*/
/* String Conversions */
/*---------------------------------------------------------------------------------*/
std::string Convert::ToNative(System::String^ str)
{
return msclr::interop::marshal_as<std::string>(str);
}
System::String^ Convert::ToCLI(const std::string& str)
{
return msclr::interop::marshal_as<System::String^>(str);
}
} // namespace PlushieAPI

View File

@ -0,0 +1,62 @@
/************************************************************************************//*!
\file Convert.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 28, 2021
\brief Contains the definition of the Convert static class and the
declaration of its functions.
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"
// Project Includes
#include "Engine/Entity.hxx"
namespace SHADE
{
/// <summary>
/// Provides functions easy and consistent syntax for converting between custom
/// managed and native types that are aligned.
/// </summary>
class Convert
{
public:
/*-----------------------------------------------------------------------------*/
/* Deleted Destructors (Static Class) */
/*-----------------------------------------------------------------------------*/
Convert() = delete;
/*-----------------------------------------------------------------------------*/
/* ECS Conversions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Converts from a native Entity to a managed Entity (UInt32).
/// </summary>
/// <param name="entity">Native Entity to convert from.</param>
/// <returns>Managed representation of the specified Entity.</returns>
static Entity ToCLI(SHEntity entity);
/*-----------------------------------------------------------------------------*/
/* String Conversions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Converts from a managed String to a native std::string.
/// </summary>
/// <param name="str">The managed String to convert from.</param>
/// <returns>Native copy of a managed String.</returns>
static std::string ToNative(System::String^ str);
/// <summary>
/// Converts from a native std::Stringto a managed String.
/// </summary>
/// <param name="str">The native std::string to convert from.</param>
/// <returns>Managed copy of a native std::string.</returns>
static System::String^ ToCLI(const std::string& str);
};
}

View File

@ -0,0 +1,122 @@
/************************************************************************************//*!
\file Debug.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 Debug 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 "Debug.hxx"
// Standard Libraries
#include <sstream>
// Project Headers
#include "Convert.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Logging Functions */
/*---------------------------------------------------------------------------------*/
void Debug::Log(const std::string& str)
{
std::cout << str << std::endl;
}
void Debug::Log(System::String^ str)
{
System::Console::WriteLine(str);
}
void Debug::Log(System::String^ str, Object^ owner)
{
Log(str, owner->GetType()->Name);
}
void Debug::Log(System::String^ str, System::String^ throwerName)
{
Log("[" + throwerName + "] " + str);
}
void Debug::Log(System::String^ str, const std::string& throwerName)
{
std::ostringstream oss;
oss << "[" << throwerName << "] " << Convert::ToNative(str);
std::cout << oss.str() << std::endl;
}
void Debug::LogWarning(const std::string& str)
{
std::cout << str << std::endl;
}
void Debug::LogWarning(System::String^ str)
{
System::Console::WriteLine(str);
}
void Debug::LogWarning(System::String^ str, Object^ thrower)
{
LogWarning(str, thrower->GetType()->Name);
}
void Debug::LogWarning(System::String^ str, System::String^ throwerName)
{
LogWarning("[" + throwerName + "] " + str);
}
void Debug::LogWarning(System::String^ str, const std::string& throwerName)
{
std::ostringstream oss;
oss << "[" << throwerName << "] " << Convert::ToNative(str);
std::cout << oss.str() << std::endl;
}
void Debug::LogError(const std::string& str)
{
std::cout << str << std::endl;
}
void Debug::LogError(System::String^ str)
{
System::Console::WriteLine(str);
}
void Debug::LogError(System::String^ str, Object^ thrower)
{
LogError(str, thrower->GetType()->Name);
}
void Debug::LogErrorNative(System::String^ str, const std::string& throwerName)
{
std::ostringstream oss;
oss << "[" << throwerName << "] -> " << Convert::ToNative(str);
std::cout << oss.str() << std::endl;
}
void Debug::LogError(System::String^ str, System::String^ throwerName)
{
LogError("[" + throwerName + "] " + str);
}
void Debug::LogException(System::Exception^ exception)
{
LogError("Unhandled exception: " + exception->ToString(), exception->Source);
}
void Debug::LogException(System::Exception^ exception, Object^ thrower)
{
LogError("Unhandled exception: " + exception->ToString(), thrower->GetType()->Name);
}
void Debug::LogException(const std::exception& exception, Object^ thrower)
{
LogExceptionNative(exception, Convert::ToNative(thrower->GetType()->Name));
}
void Debug::LogExceptionNative(System::Exception^ exception, const std::string& throwerName)
{
std::ostringstream oss;
oss << "[" << throwerName << "] Unhandled exception: " << Convert::ToNative(exception->ToString());
std::cout << oss.str() << std::endl;
}
void Debug::LogExceptionNative(const std::exception& exception, const std::string& throwerName)
{
std::ostringstream oss;
oss << "[" << throwerName << "] Unhandled exception: " << exception.what();
std::cout << oss.str() << std::endl;
}
}

View File

@ -0,0 +1,255 @@
/************************************************************************************//*!
\file Debug.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 30, 2021
\brief Contains the definition of the Debug static class and the declaration of
its functions.
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 Library
#include <stdexcept>
#include <string>
/*-------------------------------------------------------------------------------------*/
/* Macro Functions */
/*-------------------------------------------------------------------------------------*/
/// <summary>
/// Macro expansion that is used together with SAFE_NATIVE_CALL_END or
/// SAFE_NATIVE_CALL_END_N to wrap the body of a function with a try and catch that
/// catches native and managed exceptions. This is needed to prevent crashes when calling
/// managed code from native code.
/// </summary>
#define SAFE_NATIVE_CALL_BEGIN try {
/// <summary>
/// Macro expansion that is used together with SAFE_NATIVE_CALL_BEGIN or to wrap the body
/// of a function with a try and catch that catches native and managed exceptions. This
/// is needed to prevent crashes when calling managed code from native code.
/// <br/>
/// Use this instead of SAFE_NATIVE_CALL_END_N if passing in managed types as the owner.
/// </summary>
/// <param name="OWNER">
/// The managed object that owns the function that this macro encapsulates.
/// </param>
#define SAFE_NATIVE_CALL_END(OWNER) \
} \
catch (System::Exception^ e) \
{ \
Debug::LogException(e); \
} \
catch (const std::exception& e) \
{ \
Debug::LogException(e, OWNER); \
} \
catch (...) \
{ \
Debug::LogError("Unsupported native exception.", OWNER); \
} \
/// <summary>
/// Macro expansion that is used together with SAFE_NATIVE_CALL_BEGIN or to wrap the body
/// of a function with a try and catch that catches native and managed exceptions. This
/// is needed to prevent crashes when calling managed code from native code.
/// <br/>
/// Use this instead of SAFE_NATIVE_CALL_END if passing in a native string that specifies
/// the owner.
/// </summary>
/// <param name="OWNER">
/// The managed object that owns the function that this macro encapsulates.
/// </param>
#define SAFE_NATIVE_CALL_END_N(OWNER) \
} \
catch (System::Exception^ e) \
{ \
Debug::LogExceptionNative(e, OWNER); \
} \
catch (const std::exception& e) \
{ \
Debug::LogExceptionNative(e, OWNER); \
} \
catch (...) \
{ \
Debug::LogErrorNative("Unsupported native exception.", OWNER); \
} \
/*-------------------------------------------------------------------------------------*/
/* Type Definitions */
/*-------------------------------------------------------------------------------------*/
namespace SHADE
{
/// <summary>
/// Static class that contains the functions for working with time.
/// </summary>
public ref class Debug abstract sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Logging Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Logs a message to the output.
/// </summary>
/// <param name="str">The string to output.</param>
static void Log(const std::string& str);
/// <summary>
/// Logs a message to the output.
/// </summary>
/// <param name="str">The string to output.</param>
static void Log(System::String^ str);
/// <summary>
/// Logs a message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="owner">
/// Object that sent the message to label the message.
/// The name of the object will be used.
/// </param>
static void Log(System::String^ str, Object^ owner);
/// <summary>
/// Logs a message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="throwerName">
/// Name of the object that sent the message to label the message.
/// The name of the object will be used.
/// </param>
static void Log(System::String^ str, System::String^ throwerName);
/// <summary>
/// Logs a message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="throwerName">
/// Name of the object that sent the message to label the message.
/// The name of the object will be used.
/// </param>
static void Log(System::String^ str, const std::string& throwerName);
/// <summary>
/// Logs a warning message to the output.
/// </summary>
/// <param name="str">The string to output.</param>
static void LogWarning(const std::string& str);
/// <summary>
/// Logs a warning message to the output.
/// </summary>
/// <param name="str">The string to output.</param>
static void LogWarning(System::String^ str);
/// <summary>
/// Logs a warning message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="thrower">
/// Object that threw the warning to label the warning message.
/// The name of the object will be used.
/// </param>
static void LogWarning(System::String^ str, Object^ thrower);
/// <summary>
/// Logs a warning message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="throwerName">
/// Name of the object that threw the warning to label the warning message.
/// The name of the object will be used.
/// </param>
static void LogWarning(System::String^ str, System::String^ throwerName);
/// <summary>
/// Logs a warning message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="throwerName">
/// Name of the object that threw the warning to label the warning message.
/// The name of the object will be used.
/// </param>
static void LogWarning(System::String^ str, const std::string& throwerName);
/// <summary>
/// Logs a error message to the output.
/// </summary>
/// <param name="str">The string to output.</param>
static void LogError(const std::string& str);
/// <summary>
/// Logs a error message to the output.
/// </summary>
/// <param name="str">The string to output.</param>
static void LogError(System::String^ str);
/// <summary>
/// Logs a error message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="thrower">
/// Object that threw the error to label the error message.
/// The name of the object will be used.
/// </param>
static void LogError(System::String^ str, Object^ thrower);
/// <summary>
/// Logs a error message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="throwerName">
/// Name of the object that threw the error to label the error message.
/// The name of the object will be used.
/// </param>
static void LogErrorNative(System::String^ str, const std::string& throwerName);
/// <summary>
/// Logs a error message to the output with a label such that it looks like this:
/// "[Label] Message"
/// </summary>
/// <param name="str">The string to output.</param>
/// <param name="throwerName">
/// Name of the object that threw the error to label the error message.
/// The name of the object will be used.
/// </param>
static void LogError(System::String^ str, System::String^ throwerName);
/// <summary>
/// Logs an exception that is formatted nicely to the output.
/// </summary>
/// <param name="exception">Exception to log.</param>
static void LogException(System::Exception^ exception);
/// <summary>
/// Logs an exception that is formatted nicely to the output.
/// </summary>
/// <param name="exception">Exception to log.</param>
/// <param name="thrower">
/// Object that threw the exception to label the exception message.
/// The name of the object will be used.
/// </param>
static void LogException(System::Exception^ exception, Object^ thrower);
/// <summary>
/// Logs a native exception that is formatted nicely to the output.
/// Equivalent to calling
/// LogException(exception, Convert::ToNative(thrower->GetType()->Name));
/// </summary>
/// <param name="exception">Native exception to log.</param>
/// <param name="thrower">
/// Object that threw the exception to label the exception message.
/// The name of the object will be used.
/// </param>
static void LogException(const std::exception& exception, Object^ thrower);
/// <summary>
/// Logs an exception that is formatted nicely to the output.
/// </summary>
/// <param name="throwerName">Name of the one responsible for the exception.</param>
/// <param name="exception">Exception to log.</param>
static void LogExceptionNative(System::Exception^ exception, const std::string& throwerName);
/// <summary>
/// Logs a native exception that is formatted nicely to the output.
/// </summary>
/// <param name="exception">Native exception to log.</param>
/// <param name="throwerName">Name of the one responsible for the exception.</param>
static void LogExceptionNative(const std::exception& exception, const std::string& throwerName);
};
}

View File

@ -0,0 +1,36 @@
/************************************************************************************//*!
\file DisposableAssemblyLoadContext.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Jan 20, 2022
\brief Contains the implementation of the managed DisposableAssemblyLoadContext
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 "DisposableAssemblyLoadContext.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructor */
/*---------------------------------------------------------------------------------*/
DisposableAssemblyLoadContext::DisposableAssemblyLoadContext()
: AssemblyLoadContext { true }
{}
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
System::Reflection::Assembly^ DisposableAssemblyLoadContext::Load(System::Reflection::AssemblyName^)
{
return nullptr;
}
} // namespace PlushieAPI

View File

@ -0,0 +1,39 @@
/************************************************************************************//*!
\file DisposableAssemblyLoadContext.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Jan 20, 2022
\brief Contains the definitions of the managed DisposableAssemblyLoadContext
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
{
/// <summary>
/// Custom AssemblyLoadContext marked as collectible so that it can be unloaded.
/// </summary>
private ref class DisposableAssemblyLoadContext : public System::Runtime::Loader::AssemblyLoadContext
{
public:
/*-----------------------------------------------------------------------------*/
/* Constructor */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Default Constructor
/// </summary>
DisposableAssemblyLoadContext();
protected:
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
System::Reflection::Assembly^ Load(System::Reflection::AssemblyName^ assemblyName) override;
};
} // namespace PlushieAPI

View File

@ -20,6 +20,7 @@ workspace "SHADE"
include "SHADE_Engine" include "SHADE_Engine"
include "SHADE_Application" include "SHADE_Application"
include "SHADE_Managed"
group "Dependencies" group "Dependencies"
include "Dependencies/msdf" include "Dependencies/msdf"