diff --git a/SHADE_CSharp/premake5.lua b/SHADE_CSharp/premake5.lua
new file mode 100644
index 00000000..2d6c1edb
--- /dev/null
+++ b/SHADE_CSharp/premake5.lua
@@ -0,0 +1,52 @@
+project "SHADE_CSharp"
+ architecture "x64"
+ kind "SharedLib"
+ language "C#"
+ clr "NetCore"
+ dotnetframework "net5.0"
+ namespace ("SHADE")
+ targetdir (outputdir)
+ objdir (interdir)
+ systemversion "latest"
+
+ files
+ {
+ "%{prj.location}/src/**.cs",
+ "%{prj.location}/src/**.tt"
+ }
+
+ flags
+ {
+ "MultiProcessorCompile"
+ }
+
+ dependson
+ {
+ "SHADE_Engine"
+ }
+
+ warnings 'Extra'
+
+ filter "configurations:Debug"
+ symbols "On"
+ defines {"_DEBUG"}
+
+ filter "configurations:Release"
+ optimize "On"
+ defines{"_RELEASE"}
+
+ filter "configurations:Publish"
+ optimize "On"
+ defines{"_RELEASE"}
+
+ require "vstudio"
+
+ function platformsElement(cfg)
+ _p(2,'x64')
+ end
+
+ premake.override(premake.vstudio.cs2005.elements, "projectProperties", function (oldfn, cfg)
+ return table.join(oldfn(cfg), {
+ platformsElement,
+ })
+ end)
\ No newline at end of file
diff --git a/SHADE_CSharp/src/Events/CallbackAction.cs b/SHADE_CSharp/src/Events/CallbackAction.cs
new file mode 100644
index 00000000..968302ed
--- /dev/null
+++ b/SHADE_CSharp/src/Events/CallbackAction.cs
@@ -0,0 +1,852 @@
+/************************************************************************************//*!
+\file CallbackAction.cs
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 23, 2022
+\brief Contains the definition of CallbackAction and related classes.
+
+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.
+*//*************************************************************************************/
+using System;
+using System.Reflection;
+
+namespace SHADE
+{
+ ///
+ /// Interface for a CallbackAction that all variants inherit from.
+ ///
+ public interface ICallbackAction
+ {
+ ///
+ /// Whether or not this CallbackAction is runtime assigned. If it is, then the
+ /// TargetMethodName and TargetObject properties are invalid.
+ ///
+ bool IsRuntimeAction { get; }
+ ///
+ /// Name of the method that this CallbackAction is using.
+ ///
+ string TargetMethodName { get; }
+ ///
+ /// Object which the specified target method is called on.
+ ///
+ Object TargetObject { get; }
+ }
+
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 1 parameter.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 2 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 3 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 4 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3, t4);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ parameters[3] = t4;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 5 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3, t4, t5);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ parameters[3] = t4;
+ parameters[4] = t5;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 6 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3, t4, t5, t6);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ parameters[3] = t4;
+ parameters[4] = t5;
+ parameters[5] = t6;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 7 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ parameters[3] = t4;
+ parameters[4] = t5;
+ parameters[5] = t6;
+ parameters[6] = t7;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 8 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ parameters[3] = t4;
+ parameters[4] = t5;
+ parameters[5] = t6;
+ parameters[6] = t7;
+ parameters[7] = t8;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 9 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ parameters[3] = t4;
+ parameters[4] = t5;
+ parameters[5] = t6;
+ parameters[6] = t7;
+ parameters[7] = t8;
+ parameters[8] = t9;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with 10 parameters.
+ ///
+ public class CallbackAction : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ parameters[0] = t1;
+ parameters[1] = t2;
+ parameters[2] = t3;
+ parameters[3] = t4;
+ parameters[4] = t5;
+ parameters[5] = t6;
+ parameters[6] = t7;
+ parameters[7] = t8;
+ parameters[8] = t9;
+ parameters[9] = t10;
+ _ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/SHADE_CSharp/src/Events/CallbackAction.tt b/SHADE_CSharp/src/Events/CallbackAction.tt
new file mode 100644
index 00000000..fffd4251
--- /dev/null
+++ b/SHADE_CSharp/src/Events/CallbackAction.tt
@@ -0,0 +1,132 @@
+<#
+/************************************************************************************//*!
+\file CallbackAction.tt
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 23, 2022
+\brief Contains the T4 template for the definition of CallbackAction and
+ related classes.
+
+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.
+*//*************************************************************************************/#>
+<#@ template hostspecific="false" language="C#" #>
+<#@ output extension=".cs" #>
+<# var max = 10; #>
+/************************************************************************************//*!
+\file CallbackAction.cs
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 23, 2022
+\brief Contains the definition of CallbackAction and related classes.
+
+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.
+*//*************************************************************************************/
+using System;
+using System.Reflection;
+
+namespace SHADE
+{
+ ///
+ /// Interface for a CallbackAction that all variants inherit from.
+ ///
+ public interface ICallbackAction
+ {
+ ///
+ /// Whether or not this CallbackAction is runtime assigned. If it is, then the
+ /// TargetMethodName and TargetObject properties are invalid.
+ ///
+ bool IsRuntimeAction { get; }
+ ///
+ /// Name of the method that this CallbackAction is using.
+ ///
+ string TargetMethodName { get; }
+ ///
+ /// Object which the specified target method is called on.
+ ///
+ Object TargetObject { get; }
+ }
+
+<# for (int i = 1; i <= max; ++i) { #>
+ ///
+ /// Represents a function call that can be serialised and put togetheer with scripts.
+ /// This variant accepts functions with <#=i#> parameter<# if (i > 1) {#>s<#} #>.
+ ///
+ public class CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackAction
+ {
+ #region Properties ------------------------------------------------------------
+ ///
+ public Object TargetObject { get; private set; }
+ ///
+ public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
+ ///
+ public bool IsRuntimeAction => targetAction != null;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private MethodInfo targetMethod;
+ private Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> targetAction;
+ private Object[] parameters;
+ #endregion
+
+ #region Constructors ------------------------------------------------------------
+ ///
+ /// Constructs an empty Callback action.
+ ///
+ public CallbackAction() {}
+ ///
+ /// Constructs a CallbackAction that represents a call to the specified method on the
+ /// specified target.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ ///
+ /// Thrown if a method that is not compatible with the target is specified. The method's
+ /// source type must match the target's type.
+ ///
+ public CallbackAction(Object target, MethodInfo method)
+ {
+ // Error Checks
+ if (method.DeclaringType != target.GetType())
+ throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
+
+ // No errors, assign
+ TargetObject = target;
+ targetMethod = method;
+
+ // Create storage for parameters for calling
+ parameters = new Object[1];
+ }
+ ///
+ /// Constructs a Callback action based on an action.
+ ///
+ ///
+ public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
+ {
+ targetAction = action;
+ }
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ /// Invokes the CallbackAction's stored method/action with the specified parameters.
+ ///
+ public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>)
+ {
+ if (targetAction != null)
+ {
+ targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
+ }
+ else if (TargetObject != null && targetMethod != null)
+ {
+ <# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>;
+ <# } #>_ = targetMethod.Invoke(TargetObject, parameters);
+ }
+ }
+ #endregion
+ }
+<# } #>
+}
diff --git a/SHADE_CSharp/src/Events/CallbackEvent.cs b/SHADE_CSharp/src/Events/CallbackEvent.cs
new file mode 100644
index 00000000..ec464ba9
--- /dev/null
+++ b/SHADE_CSharp/src/Events/CallbackEvent.cs
@@ -0,0 +1,908 @@
+/************************************************************************************//*!
+\file CallbackEvent.cs
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 23, 2022
+\brief Contains the definition of CallbackEvent and related classes.
+
+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.
+*//*************************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Reflection.Metadata.Ecma335;
+
+namespace SHADE
+{
+ ///
+ /// Interface for a CallbackEvent that all variants inherit from.
+ ///
+ public interface ICallbackEvent
+ {
+ ///
+ /// Registers an empty ICallbackAction.
+ ///
+ void RegisterAction();
+ ///
+ /// Registers an ICallbackAction with the event such that it will be called in
+ /// future
+ ///
+ /// ICallbackAction to register with.
+ void RegisterAction(ICallbackAction action);
+ ///
+ /// Deregisters an ICallbackAction that was previously added. This should
+ /// only emit a warning if an action that was not previous added was
+ /// provided.
+ ///
+ /// ICallbackAction to remove.
+ void DeregisterAction(ICallbackAction action);
+ ///
+ /// Iterable set of ICallbackActions that were registered to this event.
+ ///
+ IEnumerable Actions { get; }
+ }
+
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3, t4);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3, t4, t5);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3, t4, t5, t6);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3, t4, t5, t6, t7);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action action)
+ {
+ actions.Add(new CallbackAction(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10)
+ {
+ foreach (CallbackAction action in actions)
+ {
+ try
+ {
+ action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+}
diff --git a/SHADE_CSharp/src/Events/CallbackEvent.tt b/SHADE_CSharp/src/Events/CallbackEvent.tt
new file mode 100644
index 00000000..6a545601
--- /dev/null
+++ b/SHADE_CSharp/src/Events/CallbackEvent.tt
@@ -0,0 +1,152 @@
+<#
+/************************************************************************************//*!
+\file CallbackEvent.tt
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 23, 2022
+\brief Contains the T4 template for the definition of CallbackEvent and
+ related classes.
+
+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.
+*//*************************************************************************************/#>
+<#@ template hostspecific="false" language="C#" #>
+<#@ output extension=".cs" #>
+<# var max = 10; #>
+/************************************************************************************//*!
+\file CallbackEvent.cs
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 23, 2022
+\brief Contains the definition of CallbackEvent and related classes.
+
+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.
+*//*************************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Reflection.Metadata.Ecma335;
+
+namespace SHADE
+{
+ ///
+ /// Interface for a CallbackEvent that all variants inherit from.
+ ///
+ public interface ICallbackEvent
+ {
+ ///
+ /// Registers an empty ICallbackAction.
+ ///
+ void RegisterAction();
+ ///
+ /// Registers an ICallbackAction with the event such that it will be called in
+ /// future
+ ///
+ /// ICallbackAction to register with.
+ void RegisterAction(ICallbackAction action);
+ ///
+ /// Deregisters an ICallbackAction that was previously added. This should
+ /// only emit a warning if an action that was not previous added was
+ /// provided.
+ ///
+ /// ICallbackAction to remove.
+ void DeregisterAction(ICallbackAction action);
+ ///
+ /// Iterable set of ICallbackActions that were registered to this event.
+ ///
+ IEnumerable Actions { get; }
+ }
+
+<# for (int i = 1; i <= max; ++i) { #>
+ ///
+ /// A container of CallbackActions that is correlated to a specific scenario as
+ /// specified by the user of this class.
+ /// This variant accepts CallbackEvents with 1 generic parameter.
+ ///
+ public class CallbackEvent<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackEvent
+ {
+ #region Properties --------------------------------------------------------------
+ ///
+ public IEnumerable Actions => actions;
+ #endregion
+
+ #region Fields ------------------------------------------------------------------
+ private List actions = new List();
+ #endregion
+
+ #region Usage Functions ---------------------------------------------------------
+ ///
+ public void RegisterAction()
+ {
+ actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>());
+ }
+ ///
+ public void RegisterAction(ICallbackAction action)
+ {
+ // Check if valid action
+ if (action.GetType() != typeof(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>))
+ {
+ Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
+ return;
+ }
+
+ actions.Add(action);
+ }
+ ///
+ /// Adds a CallbackAction into the event.
+ ///
+ /// CallbackAction to add.
+ public void RegisterAction(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
+ {
+ actions.Add(action);
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// System.Action to add as a CallbackAction.
+ public void RegisterAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
+ {
+ actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(action));
+ }
+ ///
+ /// Constructs and adds a CallbackACtion into the event.
+ ///
+ /// Object to call the method on.
+ /// Method to call.
+ public void RegisterAction(Object target, MethodInfo method)
+ {
+ actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(target, method));
+ }
+ ///
+ public void DeregisterAction(ICallbackAction action)
+ {
+ if (!actions.Remove(action))
+ {
+ Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
+ }
+ }
+ ///
+ /// Invokes all stored CallbackActions with the specified parameters.
+ ///
+ public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>)
+ {
+ foreach (CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action in actions)
+ {
+ try
+ {
+ action.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
+ }
+ catch (Exception e)
+ {
+ Debug.LogException(e, this);
+ }
+ }
+ }
+ #endregion
+ }
+<# } #>
+}
diff --git a/SHADE_CSharp/src/Utility/Debug.cs b/SHADE_CSharp/src/Utility/Debug.cs
new file mode 100644
index 00000000..eb9d9b24
--- /dev/null
+++ b/SHADE_CSharp/src/Utility/Debug.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace SHADE
+{
+ internal static class Debug
+ {
+ [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Info")]
+ public static extern void LogInfo([MarshalAs(UnmanagedType.LPStr)] string str);
+ [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Warning")]
+ public static extern void LogWarning([MarshalAs(UnmanagedType.LPStr)] string str);
+ [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Error")]
+ public static extern void LogError([MarshalAs(UnmanagedType.LPStr)] string str);
+ [DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Critical")]
+ public static extern void LogCritical([MarshalAs(UnmanagedType.LPStr)] string str);
+ public static void LogInfo(string msg, Object thrower)
+ {
+ LogInfo($"[{thrower.GetType().Name}] {msg}");
+ }
+ public static void LogWarning(string msg, Object thrower)
+ {
+ LogWarning($"[{thrower.GetType().Name}] {msg}");
+ }
+ public static void LogError(string msg, Object thrower)
+ {
+ LogError($"[{thrower.GetType().Name}] {msg}");
+ }
+ public static void LogCritical(string msg, Object thrower)
+ {
+ LogCritical($"[{thrower.GetType().Name}] {msg}");
+ }
+ public static void LogException(Exception exception, Object thrower)
+ {
+ LogError($"[{ thrower.GetType().Name }] Unhandled exception: { exception.ToString() }");
+ }
+ }
+}
\ No newline at end of file
diff --git a/SHADE_Engine/src/Editor/SHEditorUI.cpp b/SHADE_Engine/src/Editor/SHEditorUI.cpp
index 7107778d..0137b951 100644
--- a/SHADE_Engine/src/Editor/SHEditorUI.cpp
+++ b/SHADE_Engine/src/Editor/SHEditorUI.cpp
@@ -54,7 +54,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
bool SHEditorUI::CollapsingHeader(const std::string& title)
{
- return ImGui::CollapsingHeader(title.c_str());
+ return ImGui::CollapsingHeader(title.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
}
void SHEditorUI::SameLine()
diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp
index b0172f64..c1969557 100644
--- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp
+++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.cpp
@@ -10,6 +10,9 @@
#include
+// External Dependencies
+#include
+
// Primary Header
#include "SHRigidBodyComponent.h"
diff --git a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h
index 78de84e7..3c5dd4f9 100644
--- a/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h
+++ b/SHADE_Engine/src/Physics/Components/SHRigidBodyComponent.h
@@ -10,7 +10,6 @@
#pragma once
-#include
#include
// Project Headers
@@ -23,6 +22,11 @@
// class SHPhysicsSystem;
//}
+namespace reactphysics3d
+{
+ class RigidBody;
+}
+
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
@@ -153,7 +157,7 @@ namespace SHADE
uint16_t dirtyFlags;
bool interpolate;
- rp3d::RigidBody* rp3dBody;
+ reactphysics3d::RigidBody* rp3dBody;
float mass;
float drag;
diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp
index fea59353..f0f8912b 100644
--- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp
+++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp
@@ -24,6 +24,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Events/SHEvent.h"
#include "Events/SHEventReceiver.h"
#include "Events/SHEventManager.hpp"
+#include "Physics/SHPhysicsSystem.h"
namespace SHADE
{
@@ -60,7 +61,7 @@ namespace SHADE
// Initialise the CSharp Engine
csEngineInit();
- // Register entity creation events
+ // Register all events
registerEvents();
}
void SHScriptEngine::UnloadScriptAssembly()
@@ -191,6 +192,12 @@ namespace SHADE
// 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);
+ // If debug, we want to copy the PDB so that we can do script debugging
+ if (debug)
+ {
+ std::filesystem::copy_file("./tmp/SHADE_Scripting.pdb", "SHADE_Scripting.pdb", std::filesystem::copy_options::overwrite_existing);
+ }
+
oss << "[ScriptEngine] Successfully built Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
SHLOG_INFO(oss.str());
}
@@ -255,6 +262,10 @@ namespace SHADE
..\\bin\\Debug\\SHADE_Managed.dll\n\
..\\bin\\Release\\SHADE_Managed.dll\n\
\n\
+ \n\
+ ..\\bin\\Debug\\SHADE_CSharp.dll\n\
+ ..\\bin\\Release\\SHADE_CSharp.dll\n\
+ \n\
\n\
";
@@ -280,6 +291,28 @@ namespace SHADE
return eventData->handle;
}
+ SHEventHandle SHScriptEngine::onColliderAdded(SHEventPtr eventPtr)
+ {
+ auto eventData = reinterpret_cast*>(eventPtr.get());
+ csColliderOnListChanged(eventData->data->entityID);
+ return eventData->handle;
+ }
+
+ SHEventHandle SHScriptEngine::onColliderRemoved(SHEventPtr eventPtr)
+ {
+ auto eventData = reinterpret_cast*>(eventPtr.get());
+ csColliderOnListChanged(eventData->data->entityID);
+ return eventData->handle;
+ }
+
+ SHEventHandle SHScriptEngine::onColliderComponentRemoved(SHEventPtr eventPtr)
+ {
+ auto eventData = reinterpret_cast*>(eventPtr.get());
+ if (eventData->data->removedComponentType == ComponentFamily::GetID())
+ csColliderOnRemoved(eventData->data->eid);
+ return eventData->handle;
+ }
+
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
@@ -380,6 +413,18 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"DeserialiseScripts"
);
+ csColliderOnListChanged = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".Collider",
+ "OnColliderBoundChanged"
+ );
+ csColliderOnRemoved = dotNet.GetFunctionPtr
+ (
+ DEFAULT_CSHARP_LIB_NAME,
+ DEFAULT_CSHARP_NAMESPACE + ".Collider",
+ "OnColliderRemoved"
+ );
csEditorRenderScripts = dotNet.GetFunctionPtr
(
DEFAULT_CSHARP_LIB_NAME,
@@ -407,8 +452,28 @@ namespace SHADE
{
std::make_shared>(this, &SHScriptEngine::onEntityDestroyed)
};
- ReceiverPtr receiver = std::dynamic_pointer_cast(destroyedEventReceiver);
- SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, receiver);
+ SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, std::dynamic_pointer_cast(destroyedEventReceiver));
+
+ // Register for collider added event
+ std::shared_ptr> addedColliderEventReceiver
+ {
+ std::make_shared>(this, &SHScriptEngine::onColliderAdded)
+ };
+ SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_ADDED_EVENT, std::dynamic_pointer_cast(addedColliderEventReceiver));
+
+ // Register for collider removed event
+ std::shared_ptr> removedColliderEventReceiver
+ {
+ std::make_shared>(this, &SHScriptEngine::onColliderRemoved)
+ };
+ SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_REMOVED_EVENT, std::dynamic_pointer_cast(removedColliderEventReceiver));
+
+ // Register for collider component removed event
+ std::shared_ptr> removedColliderComponentEventReceiver
+ {
+ std::make_shared>(this, &SHScriptEngine::onColliderComponentRemoved)
+ };
+ SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast(removedColliderComponentEventReceiver));
}
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)
diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.h b/SHADE_Engine/src/Scripting/SHScriptEngine.h
index 137d978f..c38e3618 100644
--- a/SHADE_Engine/src/Scripting/SHScriptEngine.h
+++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h
@@ -218,6 +218,7 @@ namespace SHADE
using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*);
using CsScriptDeserialiseYamlFuncPtr = bool(*)(EntityID, const void*);
using CsScriptEditorFuncPtr = void(*)(EntityID);
+ using CsEventRelayFuncPtr = void(*)(EntityID);
/*-----------------------------------------------------------------------------*/
/* Constants */
@@ -250,6 +251,9 @@ namespace SHADE
CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr;
CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr;
CsScriptDeserialiseYamlFuncPtr csScriptsDeserialiseYaml = nullptr;
+ // - Events
+ CsEventRelayFuncPtr csColliderOnListChanged = nullptr;
+ CsEventRelayFuncPtr csColliderOnRemoved = nullptr;
// - Editor
CsScriptEditorFuncPtr csEditorRenderScripts = nullptr;
CsFuncPtr csEditorUndo = nullptr;
@@ -259,6 +263,9 @@ namespace SHADE
/* Event Handler Functions */
/*-----------------------------------------------------------------------------*/
SHEventHandle onEntityDestroyed(SHEventPtr eventPtr);
+ SHEventHandle onColliderAdded(SHEventPtr eventPtr);
+ SHEventHandle onColliderRemoved(SHEventPtr eventPtr);
+ SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr);
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
diff --git a/SHADE_Engine/src/Tools/SHLog.cpp b/SHADE_Engine/src/Tools/SHLog.cpp
index 2d0b7b58..30a79338 100644
--- a/SHADE_Engine/src/Tools/SHLog.cpp
+++ b/SHADE_Engine/src/Tools/SHLog.cpp
@@ -51,4 +51,24 @@ namespace SHADE
}
#endif
+ void SHLog_Info(const char* msg) noexcept
+ {
+ SHLOG_INFO(msg)
+ }
+
+ void SHLog_Warning(const char* msg) noexcept
+ {
+ SHLOG_WARNING(msg)
+ }
+
+ void SHLog_Error(const char* msg) noexcept
+ {
+ SHLOG_ERROR(msg)
+ }
+
+ void SHLog_Critical(const char* msg) noexcept
+ {
+ SHLOG_CRITICAL(msg)
+ }
+
}
diff --git a/SHADE_Engine/src/Tools/SHLog.h b/SHADE_Engine/src/Tools/SHLog.h
index b77042db..89dd9206 100644
--- a/SHADE_Engine/src/Tools/SHLog.h
+++ b/SHADE_Engine/src/Tools/SHLog.h
@@ -45,4 +45,12 @@ namespace SHADE
static void Trace(const std::string& msg) noexcept;
#endif
};
+
+ extern "C"
+ {
+ static void SHLog_Info(const char* msg) noexcept;
+ static void SHLog_Warning(const char* msg) noexcept;
+ static void SHLog_Error(const char* msg) noexcept;
+ static void SHLog_Critical(const char* msg) noexcept;
+ }
}
diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua
index 6d37122c..906511c1 100644
--- a/SHADE_Managed/premake5.lua
+++ b/SHADE_Managed/premake5.lua
@@ -45,7 +45,8 @@ project "SHADE_Managed"
{
"yaml-cpp",
"imgui",
- "SHADE_Engine"
+ "SHADE_Engine",
+ "SHADE_CSharp"
}
disablewarnings
diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx
new file mode 100644
index 00000000..6d2c2f01
--- /dev/null
+++ b/SHADE_Managed/src/Components/Collider.cxx
@@ -0,0 +1,257 @@
+/************************************************************************************//*!
+\file Collider.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 20, 2022
+\brief Contains the definition of the functions of the managed Collider class.
+
+ 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.
+*//*************************************************************************************/
+// Precompiled Headers
+#include "SHpch.h"
+// Primary Header
+#include "Collider.hxx"
+#include "Utility/Debug.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* ColliderBound - Constructors */
+ /*---------------------------------------------------------------------------------*/
+ ColliderBound::ColliderBound(int arrayIdx, Entity attachedEntity)
+ : arrayIndex { arrayIdx }
+ , entity { attachedEntity }
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* ColliderBound - Setter Functions */
+ /*---------------------------------------------------------------------------------*/
+ void ColliderBound::updateArrayIndex(int index)
+ {
+ arrayIndex = index;
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* BoxColliderBound - Constructors */
+ /*---------------------------------------------------------------------------------*/
+ BoxColliderBound::BoxColliderBound(int arrayIdx, Entity attachedEntity)
+ : ColliderBound { arrayIndex, attachedEntity }
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* BoxColliderBound - Properties */
+ /*---------------------------------------------------------------------------------*/
+ Vector3 BoxColliderBound::Center::get()
+ {
+ return Convert::ToCLI(getNativeBoundObject().GetCenter());
+ }
+ void BoxColliderBound::Center::set(Vector3 value)
+ {
+ getNativeBoundObject().SetCenter(Convert::ToNative(value));
+ }
+ Vector3 BoxColliderBound::HalfExtents::get()
+ {
+ return Convert::ToCLI(getNativeBoundObject().GetHalfExtents());
+ }
+ void BoxColliderBound::HalfExtents::set(Vector3 value)
+ {
+ getNativeBoundObject().SetHalfExtents(Convert::ToNative(value));
+ }
+ Vector3 BoxColliderBound::Min::get()
+ {
+ return Convert::ToCLI(getNativeBoundObject().GetMin());
+ }
+ void BoxColliderBound::Min::set(Vector3 value)
+ {
+ getNativeBoundObject().SetMin(Convert::ToNative(value));
+ }
+ Vector3 BoxColliderBound::Max::get()
+ {
+ return Convert::ToCLI(getNativeBoundObject().GetMax());
+ }
+ void BoxColliderBound::Max::set(Vector3 value)
+ {
+ getNativeBoundObject().SetMax(Convert::ToNative(value));
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* BoxColliderBound - Usage Functions */
+ /*---------------------------------------------------------------------------------*/
+ bool BoxColliderBound::TestPoint(Vector3 point)
+ {
+ return getNativeBoundObject().TestPoint(Convert::ToNative(point));
+ }
+ bool BoxColliderBound::Raycast(Ray ray, float maxDistance)
+ {
+ return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* BoxColliderBound - Properties */
+ /*---------------------------------------------------------------------------------*/
+ Vector3 SphereColliderBound::Center::get()
+ {
+ return Convert::ToCLI(getNativeBoundObject().GetCenter());
+ }
+ void SphereColliderBound::Center::set(Vector3 value)
+ {
+ getNativeBoundObject().SetCenter(Convert::ToNative(value));
+ }
+ float SphereColliderBound::Radius::get()
+ {
+ return getNativeBoundObject().GetRadius();
+ }
+ void SphereColliderBound::Radius::set(float value)
+ {
+ getNativeBoundObject().SetRadius(value);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* SphereColliderBound - Usage Functions */
+ /*---------------------------------------------------------------------------------*/
+ bool SphereColliderBound::TestPoint(Vector3 point)
+ {
+ return getNativeBoundObject().TestPoint(Convert::ToNative(point));
+ }
+ bool SphereColliderBound::Raycast(Ray ray, float maxDistance)
+ {
+ return getNativeBoundObject().Raycast(Convert::ToNative(ray), maxDistance);
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* SphereColliderBound - Constructors */
+ /*---------------------------------------------------------------------------------*/
+ SphereColliderBound::SphereColliderBound(int arrayIndex, Entity attachedEntity)
+ : ColliderBound{ arrayIndex, attachedEntity }
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* Collider - Constructors */
+ /*---------------------------------------------------------------------------------*/
+ Collider::Collider(Entity entity)
+ : Component(entity)
+ {
+ // Create lists if they don't exist
+ if (colliders == nullptr)
+ colliders = gcnew CollidersMap;
+ if (!colliders->ContainsKey(entity))
+ colliders->Add(entity, gcnew WeakReferenceList());
+
+ // Store a weak reference
+ colliders[entity]->Add(gcnew System::WeakReference(this));
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Collider - Properties */
+ /*---------------------------------------------------------------------------------*/
+ int Collider::ColliderBoundsCount::get()
+ {
+ return static_cast(GetNativeComponent()->GetColliders().size());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Collider - ColliderBound Functions */
+ /*---------------------------------------------------------------------------------*/
+ ColliderBound^ Collider::GetColliderBound(int index)
+ {
+ // Populate the list if it hasn't been
+ if (subColliderList == nullptr)
+ {
+ updateSubColliderList();
+ }
+
+ // Check if valid
+ if (index < 0 || index >= subColliderList->Count)
+ throw gcnew System::ArgumentException("[Collider] Invalid index for Collider Bound retrieval.");
+
+ // Return the bound
+ return subColliderList[index];
+ }
+ generic
+ T Collider::GetColliderBound(int index)
+ {
+ return safe_cast(GetColliderBound(index));
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Event Handling Functions */
+ /*---------------------------------------------------------------------------------*/
+ void Collider::OnColliderRemoved(EntityID entity)
+ {
+ SAFE_NATIVE_CALL_BEGIN
+ // Check if there are any colliders to update
+ if (colliders == nullptr || !colliders->ContainsKey(entity))
+ return;
+
+ // Remove the key
+ colliders->Remove(entity);
+ SAFE_NATIVE_CALL_END("Collider.OnColliderRemoved")
+ }
+
+ void Collider::OnColliderBoundChanged(EntityID entity)
+ {
+ SAFE_NATIVE_CALL_BEGIN
+ // Check if there are any colliders to update
+ if (colliders == nullptr || !colliders->ContainsKey(entity))
+ return;
+
+ // Update any colliders
+ System::Collections::Generic::List^ toRemove = gcnew System::Collections::Generic::List();
+ WeakReferenceList^ collidersList = colliders[entity];
+ for each (System::WeakReference^ wr in collidersList)
+ {
+ Collider^ collider = safe_cast(wr->Target);
+ // Update collider bounds
+ if (collider && collider->subColliderList != nullptr)
+ collider->updateSubColliderList();
+ else
+ toRemove->Add(wr);
+ }
+
+ // Sweep through and clear any invalid references while we're at it
+ for each (System::WeakReference ^ wr in toRemove)
+ {
+ collidersList->Remove(wr);
+ }
+ SAFE_NATIVE_CALL_END("Collider.OnColliderBoundChanged")
+ }
+
+ void Collider::updateSubColliderList()
+ {
+ // Prepare the list
+ if (subColliderList)
+ subColliderList->Clear();
+ else
+ subColliderList = gcnew System::Collections::Generic::List();
+
+ // Populate the list
+ int i = 0;
+ for (const auto& collider : GetNativeComponent()->GetColliders())
+ {
+ ColliderBound^ bound = nullptr;
+ switch (collider.first.GetType())
+ {
+ case SHCollider::Type::BOX:
+ bound = gcnew BoxColliderBound(i, Owner.GetEntity());
+ break;
+ case SHCollider::Type::SPHERE:
+ bound = gcnew SphereColliderBound(i, Owner.GetEntity());
+ break;
+ case SHCollider::Type::CAPSULE:
+ // TODO
+ break;
+ default:
+ Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping.");
+ break;
+ }
+ ++i;
+
+ // Add into list
+ subColliderList->Add(bound);
+ }
+ }
+}
diff --git a/SHADE_Managed/src/Components/Collider.h++ b/SHADE_Managed/src/Components/Collider.h++
new file mode 100644
index 00000000..66f77e18
--- /dev/null
+++ b/SHADE_Managed/src/Components/Collider.h++
@@ -0,0 +1,41 @@
+/************************************************************************************//*!
+\file Collider.h++
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 20, 2022
+\brief Contains the definition of templated functions for the managed Collider
+ and related classes.
+
+ 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.
+*//*************************************************************************************/
+#pragma once
+
+// Primary Include
+#include "Component.hxx"
+namespace SHADE
+{
+ template
+ ColliderBoundType& SHADE::ColliderBound::getNativeBoundObject()
+ {
+ SHColliderComponent* collider = SHComponentManager::GetComponent_s(entity);
+ if (!collider)
+ throw gcnew System::InvalidOperationException("Unable to retrieve Collider component!");
+
+ try
+ {
+ auto& bounds = collider->GetCollider(arrayIndex);
+ if (bounds.GetType() != SHCollider::Type::BOX)
+ throw gcnew System::InvalidOperationException("Attempted to retrieve invalid ColliderBound.");
+
+ return reinterpret_cast(bounds);
+ }
+ catch (std::invalid_argument&)
+ {
+ throw gcnew System::IndexOutOfRangeException("Attempted to retrieve out of range ColliderBound!");
+ }
+ }
+}
diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx
new file mode 100644
index 00000000..f827ab71
--- /dev/null
+++ b/SHADE_Managed/src/Components/Collider.hxx
@@ -0,0 +1,264 @@
+/************************************************************************************//*!
+\file Collider.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 20, 2022
+\brief Contains the definition of the managed Collider class with the
+ declaration of functions for working with it.
+
+ 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.
+*//*************************************************************************************/
+#pragma once
+
+// External Dependencies
+#include "Physics/Components/SHColliderComponent.h"
+// Project Includes
+#include "Components/Component.hxx"
+#include "Math/Vector3.hxx"
+#include "Utility/Convert.hxx"
+#include "Math/Ray.hxx"
+
+namespace SHADE
+{
+ ///
+ /// Base interface for all Collider Shapes.
+ ///
+ public ref class ColliderBound
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Usage Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Checks if the specified point is within this shape's bounds.
+ ///
+ /// Point to test with.
+ /// True if the point is in the shape's bounds.
+ virtual bool TestPoint(Vector3 point) = 0;
+ ///
+ /// Computes a Raycast and checks if there is a collision with any object.
+ ///
+ /// The ray to cast.
+ /// Maximum distance for the raycast check.
+ /// True if the ray intersects with an object in the scene.
+ virtual bool Raycast(Ray ray, float maxDistance) = 0;
+
+ protected:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ColliderBound(int arrayIdx, Entity attachedEntity);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Data Members */
+ /*-----------------------------------------------------------------------------*/
+ int arrayIndex; // Index into the colliders vector on the native object
+ Entity entity; // Entity holding the collider component that this collider bounds is on
+
+ /*-----------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*-----------------------------------------------------------------------------*/
+ template
+ ColliderBoundType& getNativeBoundObject();
+
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Setter Functions */
+ /*-----------------------------------------------------------------------------*/
+ void updateArrayIndex(int index);
+ };
+
+ ///
+ /// Box-shaped Collider Bound.
+ ///
+ public ref class BoxColliderBound : public ColliderBound
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Properties */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Center of the Bounding Box formed by this bound.
+ ///
+ property Vector3 Center
+ {
+ Vector3 get();
+ void set(Vector3 value);
+ }
+ ///
+ /// Half of the scale of the Bounding Box formed by this bound.
+ ///
+ property Vector3 HalfExtents
+ {
+ Vector3 get();
+ void set(Vector3 value);
+ }
+ ///
+ /// Position of the bottom left back corner of the Bounding Box formed by this
+ /// bound.
+ ///
+ property Vector3 Min
+ {
+ Vector3 get();
+ void set(Vector3 value);
+ }
+ ///
+ /// Position of the top right front corner of the Bounding Box formed by this
+ /// bound.
+ ///
+ property Vector3 Max
+ {
+ Vector3 get();
+ void set(Vector3 value);
+ }
+
+ /*-----------------------------------------------------------------------------*/
+ /* ColliderBound Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ bool TestPoint(Vector3 point) override;
+ ///
+ bool Raycast(Ray ray, float maxDistance) override;
+
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ BoxColliderBound(int arrayIndex, Entity attachedEntity);
+ };
+
+ ///
+ /// Sphere-shaped Collider Bound.
+ ///
+ public ref class SphereColliderBound : public ColliderBound
+ {
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Properties */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Center of the Bounding Sphere formed by this bound.
+ ///
+ property Vector3 Center
+ {
+ Vector3 get();
+ void set(Vector3 value);
+ }
+ ///
+ /// Radius of the Bounding Sphere formed by this bound.
+ ///
+ property float Radius
+ {
+ float get();
+ void set(float value);
+ }
+
+ /*-----------------------------------------------------------------------------*/
+ /* ColliderBound Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ bool TestPoint(Vector3 point) override;
+ ///
+ bool Raycast(Ray ray, float maxDistance) override;
+
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ SphereColliderBound(int arrayIndex, Entity attachedEntity);
+ };
+
+ ///
+ /// CLR version of the the SHADE Engine's SHColliderComponent.
+ /// A single Collider component can contain one or multiple Collider Bounds.
+ ///
+ public ref class Collider : public Component
+ {
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Constructs a Collider Component that represents a native SHColliderComponent
+ /// component tied to the specified Entity.
+ ///
+ /// Entity that this Component will be tied to.
+ Collider(Entity entity);
+
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Properties */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Total number of ColliderBounds in the Collider component.
+ ///
+ property int ColliderBoundsCount
+ {
+ int get();
+ }
+
+ /*-----------------------------------------------------------------------------*/
+ /* Usage Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Retrieves a ColliderBound at the specified index in the ColliderBound list.
+ ///
+ /// Index to retrieve a ColliderBound from.
+ /// ColliderBound for the specified index.
+ ColliderBound^ GetColliderBound(int index);
+ ///
+ /// Retrieves a ColliderBound at the specified index in the ColliderBound list
+ /// and casts it to the appropriate type.
+ ///
+ /// Type of the ColliderBound to cast to.
+ /// Index to retrieve a ColliderBound from.
+ /// ColliderBound for the specified index.
+ generic where T:ColliderBound
+ T GetColliderBound(int index);
+
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Event Handling Functions */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// To be called from native code when a collider has been removed.
+ ///
+ /// The entity which has it's collider removed.
+ static void OnColliderRemoved(EntityID entity);
+ ///
+ /// To be called from native code when a Collider bound has been removed.
+ ///
+ ///
+ /// The entity which has it's collider bounds changed.
+ ///
+ static void OnColliderBoundChanged(EntityID entity);
+
+ private:
+ /*-----------------------------------------------------------------------------*/
+ /* Type Definitions */
+ /*-----------------------------------------------------------------------------*/
+ using WeakReferenceList = System::Collections::Generic::List;
+ using CollidersMap = System::Collections::Generic::Dictionary;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Static Data Members */
+ /*-----------------------------------------------------------------------------*/
+ static CollidersMap^ colliders;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Data Members */
+ /*-----------------------------------------------------------------------------*/
+ System::Collections::Generic::List^ subColliderList;
+
+ /*-----------------------------------------------------------------------------*/
+ /* Helper Functions */
+ /*-----------------------------------------------------------------------------*/
+ void updateSubColliderList();
+ };
+}
+
+#include "Collider.h++"
\ No newline at end of file
diff --git a/SHADE_Managed/src/Components/RigidBody.cxx b/SHADE_Managed/src/Components/RigidBody.cxx
new file mode 100644
index 00000000..172b928b
--- /dev/null
+++ b/SHADE_Managed/src/Components/RigidBody.cxx
@@ -0,0 +1,197 @@
+/************************************************************************************//*!
+\file RigidBody.cxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 22, 2022
+\brief Contains the definition of the functions of the managed RigidBody class.
+
+ 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.
+*//*************************************************************************************/
+// Precompiled Headers
+#include "SHpch.h"
+// Primary Header
+#include "RigidBody.hxx"
+
+namespace SHADE
+{
+ /*---------------------------------------------------------------------------------*/
+ /* Constructors */
+ /*---------------------------------------------------------------------------------*/
+ RigidBody::RigidBody(Entity entity)
+ : Component(entity)
+ {}
+
+ /*---------------------------------------------------------------------------------*/
+ /* Properties */
+ /*---------------------------------------------------------------------------------*/
+ bool RigidBody::IsGravityEnabled::get()
+ {
+ return GetNativeComponent()->IsGravityEnabled();
+ }
+ void RigidBody::IsGravityEnabled::set(bool value)
+ {
+ return GetNativeComponent()->SetGravityEnabled(value);
+ }
+ bool RigidBody::IsAllowedToSleep::get()
+ {
+ return GetNativeComponent()->IsAllowedToSleep();
+ }
+ void RigidBody::IsAllowedToSleep::set(bool value)
+ {
+ return GetNativeComponent()->SetIsAllowedToSleep(value);
+ }
+ RigidBody::Type RigidBody::BodyType::get()
+ {
+ return static_cast(GetNativeComponent()->GetType());
+ }
+ void RigidBody::BodyType::set(Type value)
+ {
+ return GetNativeComponent()->SetType(static_cast(value));
+ }
+ float RigidBody::Mass::get()
+ {
+ return GetNativeComponent()->GetMass();
+ }
+ void RigidBody::Mass::set(float value)
+ {
+ return GetNativeComponent()->SetMass(value);
+ }
+ float RigidBody::Drag::get()
+ {
+ return GetNativeComponent()->GetDrag();
+ }
+ void RigidBody::Drag::set(float value)
+ {
+ return GetNativeComponent()->SetDrag(value);
+ }
+ float RigidBody::AngularDrag::get()
+ {
+ return GetNativeComponent()->GetAngularDrag();
+ }
+ void RigidBody::AngularDrag::set(float value)
+ {
+ return GetNativeComponent()->SetAngularDrag(value);
+ }
+ bool RigidBody::FreezePositionX::get()
+ {
+ return GetNativeComponent()->GetFreezePositionX();
+ }
+ void RigidBody::FreezePositionX::set(bool value)
+ {
+ return GetNativeComponent()->SetFreezePositionX(value);
+ }
+ bool RigidBody::FreezePositionY::get()
+ {
+ return GetNativeComponent()->GetFreezePositionY();
+ }
+ void RigidBody::FreezePositionY::set(bool value)
+ {
+ return GetNativeComponent()->SetFreezePositionY(value);
+ }
+ bool RigidBody::FreezePositionZ::get()
+ {
+ return GetNativeComponent()->GetFreezePositionZ();
+ }
+ void RigidBody::FreezePositionZ::set(bool value)
+ {
+ return GetNativeComponent()->SetFreezePositionZ(value);
+ }
+ bool RigidBody::FreezeRotationX::get()
+ {
+ return GetNativeComponent()->GetFreezeRotationX();
+ }
+ void RigidBody::FreezeRotationX::set(bool value)
+ {
+ return GetNativeComponent()->SetFreezeRotationX(value);
+ }
+ bool RigidBody::FreezeRotationY::get()
+ {
+ return GetNativeComponent()->GetFreezeRotationY();
+ }
+ void RigidBody::FreezeRotationY::set(bool value)
+ {
+ return GetNativeComponent()->SetFreezeRotationY(value);
+ }
+ bool RigidBody::FreezeRotationZ::get()
+ {
+ return GetNativeComponent()->GetFreezeRotationZ();
+ }
+ void RigidBody::FreezeRotationZ::set(bool value)
+ {
+ return GetNativeComponent()->SetFreezeRotationZ(value);
+ }
+ Vector3 RigidBody::LinearVelocity::get()
+ {
+ return Convert::ToCLI(GetNativeComponent()->GetLinearVelocity());
+ }
+ void RigidBody::LinearVelocity::set(Vector3 value)
+ {
+ return GetNativeComponent()->SetLinearVelocity(Convert::ToNative(value));
+ }
+ Vector3 RigidBody::AngularVelocity::get()
+ {
+ return Convert::ToCLI(GetNativeComponent()->GetAngularVelocity());
+ }
+ void RigidBody::AngularVelocity::set(Vector3 value)
+ {
+ return GetNativeComponent()->SetAngularVelocity(Convert::ToNative(value));
+ }
+ Vector3 RigidBody::Force::get()
+ {
+ return Convert::ToCLI(GetNativeComponent()->GetForce());
+ }
+ Vector3 RigidBody::Torque::get()
+ {
+ return Convert::ToCLI(GetNativeComponent()->GetTorque());
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Force Functions */
+ /*---------------------------------------------------------------------------------*/
+ void RigidBody::AddForce(Vector3 force)
+ {
+ GetNativeComponent()->AddForce(Convert::ToNative(force));
+ }
+
+ void RigidBody::AddForceAtLocalPos(Vector3 force, Vector3 localPos)
+ {
+ GetNativeComponent()->AddForceAtLocalPos(Convert::ToNative(force), Convert::ToNative(localPos));
+ }
+
+ void RigidBody::AddForceAtWorldPos(Vector3 force, Vector3 worldPos)
+ {
+ GetNativeComponent()->AddForceAtWorldPos(Convert::ToNative(force), Convert::ToNative(worldPos));
+ }
+
+ void RigidBody::AddRelativeForce(Vector3 relativeForce)
+ {
+ GetNativeComponent()->AddRelativeForce(Convert::ToNative(relativeForce));
+ }
+
+ void RigidBody::AddRelativeForceAtLocalPos(Vector3 relativeForce, Vector3 localPos)
+ {
+ GetNativeComponent()->AddRelativeForceAtLocalPos(Convert::ToNative(relativeForce), Convert::ToNative(localPos));
+ }
+
+ void RigidBody::AddRelativeForceAtWorldPos(Vector3 relativeForce, Vector3 worldPos)
+ {
+ GetNativeComponent()->AddRelativeForceAtWorldPos(Convert::ToNative(relativeForce), Convert::ToNative(worldPos));
+ }
+
+ /*---------------------------------------------------------------------------------*/
+ /* Torque Functions */
+ /*---------------------------------------------------------------------------------*/
+ void RigidBody::AddTorque(Vector3 torque)
+ {
+ GetNativeComponent()->AddTorque(Convert::ToNative(torque));
+ }
+
+ void RigidBody::AddRelativeTorque(Vector3 relativeTorque)
+ {
+ GetNativeComponent()->AddRelativeTorque(Convert::ToNative(relativeTorque));
+ }
+}
\ No newline at end of file
diff --git a/SHADE_Managed/src/Components/RigidBody.hxx b/SHADE_Managed/src/Components/RigidBody.hxx
new file mode 100644
index 00000000..b3e031ba
--- /dev/null
+++ b/SHADE_Managed/src/Components/RigidBody.hxx
@@ -0,0 +1,150 @@
+/************************************************************************************//*!
+\file RigidBody.hxx
+\author Tng Kah Wei, kahwei.tng, 390009620
+\par email: kahwei.tng\@digipen.edu
+\date Oct 22, 2022
+\brief Contains the definition of the managed Collider class with the
+ declaration of functions for working with it.
+
+ 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.
+*//*************************************************************************************/
+#pragma once
+
+// External Dependencies
+#include "Physics/Components/SHRigidBodyComponent.h"
+// Project Includes
+#include "Components/Component.hxx"
+
+namespace SHADE
+{
+ ///
+ /// CLR version of the the SHADE Engine's SHRigidBodyComponent.
+ ///
+ public ref class RigidBody : public Component
+ {
+ internal:
+ /*-----------------------------------------------------------------------------*/
+ /* Constructors */
+ /*-----------------------------------------------------------------------------*/
+ ///
+ /// Constructs a RigidBody Component that represents a native
+ /// SHRigidBodyComponent component tied to the specified Entity.
+ ///
+ /// Entity that this Component will be tied to.
+ RigidBody(Entity entity);
+
+ public:
+ /*-----------------------------------------------------------------------------*/
+ /* Type Definitions */
+ /*-----------------------------------------------------------------------------*/
+ enum class Type
+ {
+ Static,
+ Kinematic,
+ Dynamic
+ };
+
+ /*-----------------------------------------------------------------------------*/
+ /* Properties */
+ /*-----------------------------------------------------------------------------*/
+ property bool IsGravityEnabled
+ {
+ bool get();
+ void set(bool value);
+ }
+ property bool IsAllowedToSleep
+ {
+ bool get();
+ void set(bool value);
+ }
+ property Type BodyType
+ {
+ Type get();
+ void set(Type value);
+ }
+ property float Mass
+ {
+ float get();
+ void set(float value);
+ }
+ property float Drag
+ {
+ float get();
+ void set(float value);
+ }
+ property float AngularDrag
+ {
+ float get();
+ void set(float value);
+ }
+ property bool FreezePositionX
+ {
+ bool get();
+ void set(bool value);
+ }
+ property bool FreezePositionY
+ {
+ bool get();
+ void set(bool value);
+ }
+ property bool FreezePositionZ
+ {
+ bool get();
+ void set(bool value);
+ }
+ property bool FreezeRotationX
+ {
+ bool get();
+ void set(bool value);
+ }
+ property bool FreezeRotationY
+ {
+ bool get();
+ void set(bool value);
+ }
+ property bool FreezeRotationZ
+ {
+ bool get();
+ void set(bool value);
+ }
+ property Vector3 LinearVelocity
+ {
+ Vector3 get();
+ void set(Vector3 value);
+ }
+ property Vector3 AngularVelocity
+ {
+ Vector3 get();
+ void set(Vector3 value);
+ }
+ property Vector3 Force
+ {
+ Vector3 get();
+ }
+ property Vector3 Torque
+ {
+ Vector3 get();
+ }
+
+ /*-----------------------------------------------------------------------------*/
+ /* Force Functions */
+ /*-----------------------------------------------------------------------------*/
+ void AddForce(Vector3 force);
+ void AddForceAtLocalPos(Vector3 force, Vector3 localPos);
+ void AddForceAtWorldPos(Vector3 force, Vector3 worldPos);
+ void AddRelativeForce(Vector3 relativeForce);
+ void AddRelativeForceAtLocalPos(Vector3 relativeForce, Vector3 localPos);
+ void AddRelativeForceAtWorldPos(Vector3 relativeForce, Vector3 worldPos);
+
+ /*-----------------------------------------------------------------------------*/
+ /* Torque Functions */
+ /*-----------------------------------------------------------------------------*/
+ void AddTorque(Vector3 force);
+ void AddRelativeTorque(Vector3 relativeForce);
+ };
+
+}
\ No newline at end of file
diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx
index 120f0274..1097e203 100644
--- a/SHADE_Managed/src/Editor/Editor.cxx
+++ b/SHADE_Managed/src/Editor/Editor.cxx
@@ -68,36 +68,36 @@ using namespace System::Collections::Generic;
/// The managed type of the object to edit.
/// The native type of the object to edit.
/// The SHEditorUI:: function to use for editing.
-#define RENDER_FIELD_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \
-(field->FieldType == MANAGED_TYPE::typeid) \
-{ \
- NATIVE_TYPE val = safe_cast(field->GetValue(object)); \
- NATIVE_TYPE oldVal = val; \
- \
- RangeAttribute^ rangeAttrib = hasAttribute(field); \
- const std::string FIELD_NAME = Convert::ToNative(field->Name); \
- bool changed = false; \
- if (rangeAttrib) \
- { \
- changed = SHEditorUI::InputSlider \
- ( \
- FIELD_NAME, \
- static_cast(rangeAttrib->Min), \
- static_cast(rangeAttrib->Max), \
- val, &isHovered \
- ); \
- } \
- else \
- { \
- changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \
- } \
- \
- if (changed) \
- { \
- field->SetValue(object, val); \
- registerUndoAction(object, field, val, oldVal); \
- } \
-} \
+#define RENDER_FIELD_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \
+(field->FieldType == MANAGED_TYPE::typeid) \
+{ \
+ NATIVE_TYPE val = safe_cast(field->GetValue(object)); \
+ NATIVE_TYPE oldVal = val; \
+ \
+ RangeAttribute^ rangeAttrib = hasAttribute(field);\
+ const std::string FIELD_NAME = Convert::ToNative(field->Name); \
+ bool changed = false; \
+ if (rangeAttrib) \
+ { \
+ changed = SHEditorUI::InputSlider \
+ ( \
+ FIELD_NAME, \
+ static_cast(rangeAttrib->Min), \
+ static_cast(rangeAttrib->Max), \
+ val, &isHovered \
+ ); \
+ } \
+ else \
+ { \
+ changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \
+ } \
+ \
+ if (changed) \
+ { \
+ field->SetValue(object, val); \
+ registerUndoAction(object, field, val, oldVal); \
+ } \
+} \
///
/// Macro expansion that is used in renderFieldInInspector() to check the type of a field
/// named "field" against the specified type and if it matches, retrieves the value of
@@ -197,7 +197,7 @@ namespace SHADE
void Editor::renderScriptInInspector(Entity entity, Script^ script, int index)
{
// Constants
- const std::string LABEL = Convert::ToNative(script->GetType()->Name);
+ const std::string LABEL = Convert::ToNative(script->GetType()->Name);
// Header
SHEditorUI::PushID(index);
@@ -286,6 +286,76 @@ namespace SHADE
registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal));
}
}
+ else
+ {
+ array^ interfaces = field->FieldType->GetInterfaces();
+ if (interfaces->Length > 0 && interfaces[0] == ICallbackEvent::typeid)
+ {
+ array^ typeArgs = field->FieldType->GenericTypeArguments;
+ System::String^ title = field->Name + " : CallbackEvent<";
+ for (int i = 0; i < typeArgs->Length; ++i)
+ {
+ title += typeArgs[i]->Name;
+ if (i < typeArgs->Length - 1)
+ title += ", ";
+ }
+ title += ">";
+ if (SHEditorUI::CollapsingHeader(Convert::ToNative(title)))
+ {
+ // Constants
+ const std::string LABEL = Convert::ToNative(field->Name);
+ SHEditorUI::PushID(LABEL);
+
+ ICallbackEvent^ callbackEvent = safe_cast(field->GetValue(object));
+ if (callbackEvent == nullptr)
+ {
+ // Construct one since it was not constructed before
+ callbackEvent = safe_cast(System::Activator::CreateInstance(field->FieldType));
+ }
+ for each (ICallbackAction ^ action in callbackEvent->Actions)
+ {
+ if (action->IsRuntimeAction)
+ continue;
+
+ // Attempt to get the object if any
+ int entityId = static_cast(-1);
+ if (action->TargetObject)
+ {
+ Script^ script = safe_cast