From 488fd51d05d210a264705c8551375b756b544587 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Thu, 20 Oct 2022 17:07:21 +0800 Subject: [PATCH 01/10] Added Collider component and Ray struct for C# --- SHADE_Managed/src/Components/Collider.cxx | 192 ++++++++++++++++++ SHADE_Managed/src/Components/Collider.h++ | 41 ++++ SHADE_Managed/src/Components/Collider.hxx | 228 ++++++++++++++++++++++ SHADE_Managed/src/Math/Ray.cxx | 28 +++ SHADE_Managed/src/Math/Ray.hxx | 50 +++++ SHADE_Managed/src/Utility/Convert.cxx | 11 ++ SHADE_Managed/src/Utility/Convert.hxx | 14 ++ 7 files changed, 564 insertions(+) create mode 100644 SHADE_Managed/src/Components/Collider.cxx create mode 100644 SHADE_Managed/src/Components/Collider.h++ create mode 100644 SHADE_Managed/src/Components/Collider.hxx create mode 100644 SHADE_Managed/src/Math/Ray.cxx create mode 100644 SHADE_Managed/src/Math/Ray.hxx diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx new file mode 100644 index 00000000..e09b7ead --- /dev/null +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -0,0 +1,192 @@ +/************************************************************************************//*! +\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) + {} + + /*---------------------------------------------------------------------------------*/ + /* 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) + { + subColliderList = gcnew System::Collections::Generic::List(); + for (const auto& collider : GetNativeComponent()->GetColliders()) + { + ColliderBound^ bound = nullptr; + switch (collider.first.GetType()) + { + case SHCollider::Type::BOX: + bound = gcnew BoxColliderBound(index, Owner.GetEntity()); + break; + case SHCollider::Type::SPHERE: + bound = gcnew SphereColliderBound(index, Owner.GetEntity()); + break; + case SHCollider::Type::CAPSULE: + // TODO + break; + default: + Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping."); + break; + } + + // Add into list + subColliderList->Add(bound); + } + } + + // 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)); + } +} 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..a831e5f9 --- /dev/null +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -0,0 +1,228 @@ +/************************************************************************************//*! +\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); + + private: + System::Collections::Generic::List^ subColliderList; // TODO: Update elements in this list if the list on native collider changes + }; +} + +#include "Collider.h++" \ No newline at end of file diff --git a/SHADE_Managed/src/Math/Ray.cxx b/SHADE_Managed/src/Math/Ray.cxx new file mode 100644 index 00000000..ee614cbe --- /dev/null +++ b/SHADE_Managed/src/Math/Ray.cxx @@ -0,0 +1,28 @@ +/************************************************************************************//*! +\file Ray.cxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 20, 2022 +\brief Contains the definitions of functions of the Vector2 struct. + + 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 "Math/Ray.hxx" + +namespace SHADE +{ + /*---------------------------------------------------------------------------------*/ + /* Constructors */ + /*---------------------------------------------------------------------------------*/ + Ray::Ray(Vector3 origin, Vector3 direction) + : Origin { origin } + , Direction{ direction } + {} +} \ No newline at end of file diff --git a/SHADE_Managed/src/Math/Ray.hxx b/SHADE_Managed/src/Math/Ray.hxx new file mode 100644 index 00000000..c50191f8 --- /dev/null +++ b/SHADE_Managed/src/Math/Ray.hxx @@ -0,0 +1,50 @@ +/************************************************************************************//*! +\file Ray.hxx +\author Tng Kah Wei, kahwei.tng, 390009620 +\par email: kahwei.tng\@digipen.edu +\date Oct 20, 2021 +\brief Contains the definitions of Vector2 struct. + + 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 + +// Project Includes +#include "Vector3.hxx" + +namespace SHADE +{ + /// + /// CLR version of the the SHADE Engine's Ray class that represents a ray in + /// 3-Dimensional space. + /// + public value struct Ray + { + public: + /*-----------------------------------------------------------------------------*/ + /* Public Members */ + /*-----------------------------------------------------------------------------*/ + /// + /// The start point of the ray. + /// + Vector3 Origin; + /// + /// The direction that a ray travels in. + /// + Vector3 Direction; + + /*-----------------------------------------------------------------------------*/ + /* Constructors */ + /*-----------------------------------------------------------------------------*/ + /// + /// Creates a ray starting at origin along direction. + /// + /// Source of the ray. + /// Direction the ray travels in. + Ray(Vector3 origin, Vector3 direction); + }; +} diff --git a/SHADE_Managed/src/Utility/Convert.cxx b/SHADE_Managed/src/Utility/Convert.cxx index 661eb3e4..33c4e4dc 100644 --- a/SHADE_Managed/src/Utility/Convert.cxx +++ b/SHADE_Managed/src/Utility/Convert.cxx @@ -40,6 +40,7 @@ namespace SHADE const double Z = vec.z; return SHVec3(X, Y, Z); } + Vector3 Convert::ToCLI(const SHVec3& vec) { return Vector3(vec.x, vec.y, vec.z); @@ -56,6 +57,16 @@ namespace SHADE return Vector2(vec.x, vec.y); } + SHRay Convert::ToNative(Ray vec) + { + return SHRay(ToNative(vec.Origin), ToNative(vec.Direction)); + } + + Ray Convert::ToCLI(const SHRay& vec) + { + return Ray(ToCLI(vec.position), ToCLI(vec.direction)); + } + /*---------------------------------------------------------------------------------*/ /* String Conversions */ /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Utility/Convert.hxx b/SHADE_Managed/src/Utility/Convert.hxx index f04cbf4b..fd0ecdce 100644 --- a/SHADE_Managed/src/Utility/Convert.hxx +++ b/SHADE_Managed/src/Utility/Convert.hxx @@ -18,10 +18,12 @@ of DigiPen Institute of Technology is prohibited. #include "ECS_Base/Entity/SHEntity.h" #include "Math/Vector/SHVec2.h" #include "Math/Vector/SHVec3.h" +#include "Math/SHRay.h" // Project Includes #include "Engine/Entity.hxx" #include "Math/Vector2.hxx" #include "Math/Vector3.hxx" +#include "Math/Ray.hxx" namespace SHADE { @@ -74,6 +76,18 @@ namespace SHADE /// The native Vector2 to convert from. /// Managed copy of a native Vector2. static Vector2 ToCLI(const SHVec2& vec); + /// + /// Converts from a managed Vector2 to a native Vector2. + /// + /// The managed Vector2 to convert from. + /// Native copy of a managed Vector2. + static SHRay ToNative(Ray vec); + /// + /// Converts from a native Vector2 to a managed Vector2. + /// + /// The native Vector2 to convert from. + /// Managed copy of a native Vector2. + static Ray ToCLI(const SHRay& vec); /*-----------------------------------------------------------------------------*/ /* String Conversions */ From 2bd633c11b5b487e748347076b75327944d06d27 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sat, 22 Oct 2022 23:00:50 +0800 Subject: [PATCH 02/10] Added RigidBody component --- SHADE_Managed/src/Components/Collider.hxx | 3 + SHADE_Managed/src/Components/RigidBody.cxx | 197 +++++++++++++++++++++ SHADE_Managed/src/Components/RigidBody.hxx | 150 ++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 SHADE_Managed/src/Components/RigidBody.cxx create mode 100644 SHADE_Managed/src/Components/RigidBody.hxx diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index a831e5f9..c85ee21c 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -221,6 +221,9 @@ namespace SHADE T GetColliderBound(int index); private: + /*-----------------------------------------------------------------------------*/ + /* Data Members */ + /*-----------------------------------------------------------------------------*/ System::Collections::Generic::List^ subColliderList; // TODO: Update elements in this list if the list on native collider changes }; } 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 From 10a945a35d0d081331dc4c3cd43e6ef27e9f6aa5 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Sun, 23 Oct 2022 18:20:38 +0800 Subject: [PATCH 03/10] Added SHADE_CSharp --- SHADE_CSharp/premake5.lua | 48 +++++++++++++++++++++++++++++++++++++++ premake5.lua | 1 + 2 files changed, 49 insertions(+) create mode 100644 SHADE_CSharp/premake5.lua diff --git a/SHADE_CSharp/premake5.lua b/SHADE_CSharp/premake5.lua new file mode 100644 index 00000000..c6efa145 --- /dev/null +++ b/SHADE_CSharp/premake5.lua @@ -0,0 +1,48 @@ +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"} + + 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/premake5.lua b/premake5.lua index cebb5544..35bff9d2 100644 --- a/premake5.lua +++ b/premake5.lua @@ -22,6 +22,7 @@ workspace "SHADE" include "SHADE_Engine" include "SHADE_Application" include "SHADE_Managed" + include "SHADE_CSharp" group "Dependencies" include "Dependencies/msdf" From 51c79d33d619e2a0ae87423f3bea316abd1f5d98 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Mon, 24 Oct 2022 02:04:05 +0800 Subject: [PATCH 04/10] Added C-style versions of SHLog functions and P/Invoke versions in SHADE_CSharp --- SHADE_CSharp/premake5.lua | 4 ++ SHADE_CSharp/src/Utility/Debug.cs | 37 +++++++++++++++ SHADE_Engine/src/Tools/SHLog.cpp | 20 ++++++++ SHADE_Engine/src/Tools/SHLog.h | 8 ++++ SHADE_Managed/premake5.lua | 3 +- SHADE_Managed/src/Editor/Editor.cxx | 72 +++++++++++++++++------------ 6 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 SHADE_CSharp/src/Utility/Debug.cs diff --git a/SHADE_CSharp/premake5.lua b/SHADE_CSharp/premake5.lua index c6efa145..2d6c1edb 100644 --- a/SHADE_CSharp/premake5.lua +++ b/SHADE_CSharp/premake5.lua @@ -35,6 +35,10 @@ project "SHADE_CSharp" optimize "On" defines{"_RELEASE"} + filter "configurations:Publish" + optimize "On" + defines{"_RELEASE"} + require "vstudio" function platformsElement(cfg) 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/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/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 120f0274..c2b34d44 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 @@ -286,6 +286,18 @@ namespace SHADE registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); } } + else if (field->FieldType->BaseType == ICallbackEvent::typeid) + { + // Needs to present + // - name and param list + // Needs to present for each callbackaction + // - object, methodinfo OR action + // - Ways to add or remove items + } + else + { + return; + } // Check if the field has a specific attribute TooltipAttribute^ toolTip = hasAttribute(field); From c6d29a10382732f12f57031cf36127f2c2ddb93a Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Mon, 24 Oct 2022 02:04:22 +0800 Subject: [PATCH 05/10] Added CallbackAction and CallbackEvent --- SHADE_CSharp/src/Events/CallbackAction.cs | 812 ++++++++++++++++++++ SHADE_CSharp/src/Events/CallbackAction.tt | 128 ++++ SHADE_CSharp/src/Events/CallbackEvent.cs | 854 ++++++++++++++++++++++ SHADE_CSharp/src/Events/CallbackEvent.tt | 143 ++++ 4 files changed, 1937 insertions(+) create mode 100644 SHADE_CSharp/src/Events/CallbackAction.cs create mode 100644 SHADE_CSharp/src/Events/CallbackAction.tt create mode 100644 SHADE_CSharp/src/Events/CallbackEvent.cs create mode 100644 SHADE_CSharp/src/Events/CallbackEvent.tt diff --git a/SHADE_CSharp/src/Events/CallbackAction.cs b/SHADE_CSharp/src/Events/CallbackAction.cs new file mode 100644 index 00000000..ec34ca5c --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackAction.cs @@ -0,0 +1,812 @@ +/************************************************************************************//*! +\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 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 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 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 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 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 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 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 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 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 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..0b1efb83 --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackAction.tt @@ -0,0 +1,128 @@ +<# +/************************************************************************************//*! +\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 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..7b30a8ec --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackEvent.cs @@ -0,0 +1,854 @@ +/************************************************************************************//*! +\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 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(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(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(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(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(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(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(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(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(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(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..74fadd08 --- /dev/null +++ b/SHADE_CSharp/src/Events/CallbackEvent.tt @@ -0,0 +1,143 @@ +<# +/************************************************************************************//*! +\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 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(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 + } +<# } #> +} From f6cbb1814386e4d624df0c0ec26ac45524516041 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 25 Oct 2022 01:34:46 +0800 Subject: [PATCH 06/10] Added display of WIP CallbackEvents on the inspector --- SHADE_CSharp/src/Events/CallbackAction.cs | 40 +++++++++++++ SHADE_CSharp/src/Events/CallbackAction.tt | 4 ++ SHADE_CSharp/src/Events/CallbackEvent.cs | 54 +++++++++++++++++ SHADE_CSharp/src/Events/CallbackEvent.tt | 9 +++ SHADE_Engine/src/Editor/SHEditorUI.cpp | 2 +- SHADE_Engine/src/Scripting/SHScriptEngine.cpp | 4 ++ SHADE_Managed/src/Editor/Editor.cxx | 60 ++++++++++++++++--- TempScriptsFolder/RaccoonSpin.cs | 4 ++ 8 files changed, 167 insertions(+), 10 deletions(-) diff --git a/SHADE_CSharp/src/Events/CallbackAction.cs b/SHADE_CSharp/src/Events/CallbackAction.cs index ec34ca5c..968302ed 100644 --- a/SHADE_CSharp/src/Events/CallbackAction.cs +++ b/SHADE_CSharp/src/Events/CallbackAction.cs @@ -57,6 +57,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -130,6 +134,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -204,6 +212,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -279,6 +291,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -355,6 +371,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -432,6 +452,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -510,6 +534,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -589,6 +617,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -669,6 +701,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// @@ -750,6 +786,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// diff --git a/SHADE_CSharp/src/Events/CallbackAction.tt b/SHADE_CSharp/src/Events/CallbackAction.tt index 0b1efb83..fffd4251 100644 --- a/SHADE_CSharp/src/Events/CallbackAction.tt +++ b/SHADE_CSharp/src/Events/CallbackAction.tt @@ -74,6 +74,10 @@ namespace SHADE #region Constructors ------------------------------------------------------------ /// + /// Constructs an empty Callback action. + /// + public CallbackAction() {} + /// /// Constructs a CallbackAction that represents a call to the specified method on the /// specified target. /// diff --git a/SHADE_CSharp/src/Events/CallbackEvent.cs b/SHADE_CSharp/src/Events/CallbackEvent.cs index 7b30a8ec..ec464ba9 100644 --- a/SHADE_CSharp/src/Events/CallbackEvent.cs +++ b/SHADE_CSharp/src/Events/CallbackEvent.cs @@ -22,6 +22,10 @@ namespace SHADE /// public interface ICallbackEvent { + /// + /// Registers an empty ICallbackAction. + /// + void RegisterAction(); /// /// Registers an ICallbackAction with the event such that it will be called in /// future @@ -59,6 +63,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -140,6 +149,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -221,6 +235,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -302,6 +321,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -383,6 +407,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -464,6 +493,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -545,6 +579,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -626,6 +665,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -707,6 +751,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action @@ -788,6 +837,11 @@ namespace SHADE #region Usage Functions --------------------------------------------------------- /// + public void RegisterAction() + { + actions.Add(new CallbackAction()); + } + /// public void RegisterAction(ICallbackAction action) { // Check if valid action diff --git a/SHADE_CSharp/src/Events/CallbackEvent.tt b/SHADE_CSharp/src/Events/CallbackEvent.tt index 74fadd08..6a545601 100644 --- a/SHADE_CSharp/src/Events/CallbackEvent.tt +++ b/SHADE_CSharp/src/Events/CallbackEvent.tt @@ -38,6 +38,10 @@ namespace SHADE /// public interface ICallbackEvent { + /// + /// Registers an empty ICallbackAction. + /// + void RegisterAction(); /// /// Registers an ICallbackAction with the event such that it will be called in /// future @@ -76,6 +80,11 @@ namespace SHADE #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 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/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index fea59353..195d8ee3 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -255,6 +255,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\ "; diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index c2b34d44..018a9591 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -286,17 +286,59 @@ namespace SHADE registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); } } - else if (field->FieldType->BaseType == ICallbackEvent::typeid) - { - // Needs to present - // - name and param list - // Needs to present for each callbackaction - // - object, methodinfo OR action - // - Ways to add or remove items - } else { - return; + 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))) + { + 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; + + if (action->TargetObject == nullptr) + SHEditorUI::Text("Target Object"); + else + SHEditorUI::Text(Convert::ToNative(action->TargetObject->GetType()->Name)); + SHEditorUI::SameLine(); + + if (action->TargetMethodName == nullptr) + SHEditorUI::Text("Target Method Name"); + else + SHEditorUI::Text(Convert::ToNative(action->TargetMethodName)); + } + if (SHEditorUI::Button("Add Action")) + { + callbackEvent->RegisterAction(); + } + } + // Needs to present + // - name and param list + // Needs to present for each callbackaction + // - object, methodinfo OR action + // - Ways to add or remove items + } + else + { + return; + } } // Check if the field has a specific attribute diff --git a/TempScriptsFolder/RaccoonSpin.cs b/TempScriptsFolder/RaccoonSpin.cs index d6ee1c9f..6bbd1462 100644 --- a/TempScriptsFolder/RaccoonSpin.cs +++ b/TempScriptsFolder/RaccoonSpin.cs @@ -7,6 +7,10 @@ public class RaccoonSpin : Script [Tooltip("Speed of the rotation in radians per second.")] private double RotateSpeed = 1.0; private double rotation = 0.0; + [SerializeField] + private CallbackEvent testEvent; + [SerializeField] + private CallbackEvent testEvent3 = new CallbackEvent(); private Transform Transform; public RaccoonSpin(GameObject gameObj) : base(gameObj) { } From 3bdc48260f84e3a7f6641e7585143964acd4ae3e Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Tue, 25 Oct 2022 16:55:50 +0800 Subject: [PATCH 07/10] Improved CallbackEvent inspector --- SHADE_Managed/src/Editor/Editor.cxx | 46 +++++++++++++++++++---------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 018a9591..1097e203 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -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); @@ -302,6 +302,10 @@ namespace SHADE 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) { @@ -313,27 +317,39 @@ namespace SHADE if (action->IsRuntimeAction) continue; - if (action->TargetObject == nullptr) - SHEditorUI::Text("Target Object"); - else - SHEditorUI::Text(Convert::ToNative(action->TargetObject->GetType()->Name)); + // Attempt to get the object if any + int entityId = static_cast(-1); + if (action->TargetObject) + { + Script^ script = safe_cast(action->TargetObject); + if (script) + { + entityId = static_cast(script->Owner.GetEntity()); + } + } + SHEditorUI::InputInt("", entityId); SHEditorUI::SameLine(); - - if (action->TargetMethodName == nullptr) - SHEditorUI::Text("Target Method Name"); - else - SHEditorUI::Text(Convert::ToNative(action->TargetMethodName)); + System::String^ methodName = ""; + if (action->TargetMethodName != nullptr) + { + methodName = action->TargetMethodName; + } + std::string methodNameNative = Convert::ToNative(methodName); + SHEditorUI::InputTextField("", methodNameNative); + SHEditorUI::SameLine(); + if (SHEditorUI::Button("-")) + { + callbackEvent->DeregisterAction(action); + break; + } } if (SHEditorUI::Button("Add Action")) { callbackEvent->RegisterAction(); } + + SHEditorUI::PopID(); } - // Needs to present - // - name and param list - // Needs to present for each callbackaction - // - object, methodinfo OR action - // - Ways to add or remove items } else { From d45d62170136a23796c139eba8416020426fa5e3 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Thu, 27 Oct 2022 12:32:06 +0800 Subject: [PATCH 08/10] Collider now will have it's sub collider list updated based on events --- .../Components/SHRigidBodyComponent.cpp | 3 + .../Physics/Components/SHRigidBodyComponent.h | 8 +- SHADE_Engine/src/Scripting/SHScriptEngine.cpp | 40 +++++++- SHADE_Engine/src/Scripting/SHScriptEngine.h | 5 + SHADE_Managed/src/Components/Collider.cxx | 99 ++++++++++++++----- SHADE_Managed/src/Components/Collider.hxx | 28 +++++- SHADE_Managed/src/Engine/ECS.cxx | 6 ++ SHADE_Managed/src/Scripts/ScriptStore.hxx | 4 +- TempScriptsFolder/PhysicsTest.cs | 36 +++++++ TempScriptsFolder/RaccoonShowcase.cs | 10 +- TempScriptsFolder/RaccoonSpin.cs | 9 +- 11 files changed, 202 insertions(+), 46 deletions(-) create mode 100644 TempScriptsFolder/PhysicsTest.cs 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 195d8ee3..3a2ea29f 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() @@ -284,6 +285,20 @@ 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; + } + /*-----------------------------------------------------------------------------------*/ /* Helper Functions */ /*-----------------------------------------------------------------------------------*/ @@ -384,6 +399,12 @@ namespace SHADE DEFAULT_CSHARP_NAMESPACE + ".ScriptStore", "DeserialiseScripts" ); + csColliderOnListChanged = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Collider", + "OnColliderBoundChanged" + ); csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, @@ -411,8 +432,21 @@ 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)); } 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..a909a334 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,8 @@ namespace SHADE CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr; CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr; CsScriptDeserialiseYamlFuncPtr csScriptsDeserialiseYaml = nullptr; + // - Events + CsEventRelayFuncPtr csColliderOnListChanged = nullptr; // - Editor CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; CsFuncPtr csEditorUndo = nullptr; @@ -259,6 +262,8 @@ namespace SHADE /* Event Handler Functions */ /*-----------------------------------------------------------------------------*/ SHEventHandle onEntityDestroyed(SHEventPtr eventPtr); + SHEventHandle onColliderAdded(SHEventPtr eventPtr); + SHEventHandle onColliderRemoved(SHEventPtr eventPtr); /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index e09b7ead..7f41ad44 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -134,7 +134,16 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ 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 */ @@ -152,29 +161,7 @@ namespace SHADE // Populate the list if it hasn't been if (subColliderList == nullptr) { - subColliderList = gcnew System::Collections::Generic::List(); - for (const auto& collider : GetNativeComponent()->GetColliders()) - { - ColliderBound^ bound = nullptr; - switch (collider.first.GetType()) - { - case SHCollider::Type::BOX: - bound = gcnew BoxColliderBound(index, Owner.GetEntity()); - break; - case SHCollider::Type::SPHERE: - bound = gcnew SphereColliderBound(index, Owner.GetEntity()); - break; - case SHCollider::Type::CAPSULE: - // TODO - break; - default: - Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping."); - break; - } - - // Add into list - subColliderList->Add(bound); - } + updateSubColliderList(); } // Check if valid @@ -189,4 +176,68 @@ namespace SHADE { return safe_cast(GetColliderBound(index)); } + + /*---------------------------------------------------------------------------------*/ + /* Event Handling Functions */ + /*---------------------------------------------------------------------------------*/ + void Collider::OnColliderBoundChanged(EntityID entity) + { + // 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); + } + } + + 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.hxx b/SHADE_Managed/src/Components/Collider.hxx index c85ee21c..8e63fc83 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -136,7 +136,7 @@ namespace SHADE /// public ref class SphereColliderBound : public ColliderBound { - public: + public: /*-----------------------------------------------------------------------------*/ /* Properties */ /*-----------------------------------------------------------------------------*/ @@ -165,7 +165,7 @@ namespace SHADE /// bool Raycast(Ray ray, float maxDistance) override; - internal: + internal: /*-----------------------------------------------------------------------------*/ /* Constructors */ /*-----------------------------------------------------------------------------*/ @@ -220,11 +220,33 @@ namespace SHADE generic where T:ColliderBound T GetColliderBound(int index); + internal: + /*-----------------------------------------------------------------------------*/ + /* Event Handling Functions */ + /*-----------------------------------------------------------------------------*/ + 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; // TODO: Update elements in this list if the list on native collider changes + System::Collections::Generic::List^ subColliderList; + + /*-----------------------------------------------------------------------------*/ + /* Helper Functions */ + /*-----------------------------------------------------------------------------*/ + void updateSubColliderList(); }; } diff --git a/SHADE_Managed/src/Engine/ECS.cxx b/SHADE_Managed/src/Engine/ECS.cxx index 4d62f643..df67c788 100644 --- a/SHADE_Managed/src/Engine/ECS.cxx +++ b/SHADE_Managed/src/Engine/ECS.cxx @@ -22,6 +22,8 @@ of DigiPen Institute of Technology is prohibited. // External Dependencies #include "ECS_Base/Managers/SHEntityManager.h" #include "Math/Transform/SHTransformComponent.h" +#include "Physics\Components\SHColliderComponent.h" +#include "Physics\Components\SHRigidBodyComponent.h" #include "Scene/SHSceneManager.h" #include "Scene/SHSceneGraph.h" #include "Tools/SHLog.h" @@ -29,6 +31,8 @@ of DigiPen Institute of Technology is prohibited. #include "Utility/Convert.hxx" #include "Utility/Debug.hxx" #include "Components/Transform.hxx" +#include "Components\RigidBody.hxx" +#include "Components\Collider.hxx" namespace SHADE { @@ -242,6 +246,8 @@ namespace SHADE static ECS::ECS() { componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); + componentMap.Add(createComponentSet()); } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Managed/src/Scripts/ScriptStore.hxx b/SHADE_Managed/src/Scripts/ScriptStore.hxx index 4a9be721..9aa66fcd 100644 --- a/SHADE_Managed/src/Scripts/ScriptStore.hxx +++ b/SHADE_Managed/src/Scripts/ScriptStore.hxx @@ -132,7 +132,7 @@ namespace SHADE /// Immutable list of references to scripts of the specified type. /// generic where T : ref class, Script - static System::Collections::Generic::IEnumerable ^ GetScripts(Entity entity); + static System::Collections::Generic::IEnumerable^ GetScripts(Entity entity); /// /// Retrieves an immutable list of all scripts attached to a specified Entity. /// @@ -295,4 +295,4 @@ namespace SHADE static System::Type^ getScriptType(System::String^ scriptName); static bool isEntityActive(Entity entity); }; -} // namespace PlushieAPI \ No newline at end of file +} diff --git a/TempScriptsFolder/PhysicsTest.cs b/TempScriptsFolder/PhysicsTest.cs new file mode 100644 index 00000000..72e8a205 --- /dev/null +++ b/TempScriptsFolder/PhysicsTest.cs @@ -0,0 +1,36 @@ +using SHADE; +using System; + +public class PhysicsTest : Script +{ + [SerializeField] + [Tooltip("Force to apply when pressing Space.")] + private Vector3 Force = new Vector3(0.0f, 1.0f, 0.0f); + private RigidBody RigidBody; + private Collider Collider; + public PhysicsTest(GameObject gameObj) : base(gameObj) { } + + protected override void awake() + { + RigidBody = GetComponent(); + if (RigidBody == null) + { + Debug.LogError("RigidBody is NULL!"); + } + Collider = GetComponent(); + if (Collider == null) + { + Debug.LogError("Collider is NULL!"); + } + + var subColider = Collider.ColliderBoundsCount; + Debug.Log($"There are {subColider} colliders."); + } + protected override void update() + { + if (Input.GetKeyUp(Input.KeyCode.Space)) + { + RigidBody.AddForce(Force); + } + } +} \ No newline at end of file diff --git a/TempScriptsFolder/RaccoonShowcase.cs b/TempScriptsFolder/RaccoonShowcase.cs index 4191a6e5..da0b89d2 100644 --- a/TempScriptsFolder/RaccoonShowcase.cs +++ b/TempScriptsFolder/RaccoonShowcase.cs @@ -12,7 +12,7 @@ public class RaccoonShowcase : Script //private int test = 5; [SerializeField] [Tooltip("Speed of the scaling in radians per second around each axis.")] - private Vector3 ScaleSpeed = new Vector3(1.0, 1.0, 0.0); + private Vector3 ScaleSpeed = Vector3.One; private Transform Transform; private double rotation = 0.0; private Vector3 scale = Vector3.Zero; @@ -31,9 +31,9 @@ public class RaccoonShowcase : Script } protected override void update() { - rotation += RotateSpeed * 0.16; - scale += ScaleSpeed * 0.16; - Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); - Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale); + //rotation += RotateSpeed * 0.16; + //scale += ScaleSpeed * 0.16; + //Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); + //Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale); } } \ No newline at end of file diff --git a/TempScriptsFolder/RaccoonSpin.cs b/TempScriptsFolder/RaccoonSpin.cs index 6bbd1462..c5420ffb 100644 --- a/TempScriptsFolder/RaccoonSpin.cs +++ b/TempScriptsFolder/RaccoonSpin.cs @@ -5,8 +5,8 @@ public class RaccoonSpin : Script { [SerializeField] [Tooltip("Speed of the rotation in radians per second.")] - private double RotateSpeed = 1.0; - private double rotation = 0.0; + private float RotateSpeed = 1.0f; + private float rotation = 0.0f; [SerializeField] private CallbackEvent testEvent; [SerializeField] @@ -22,9 +22,4 @@ public class RaccoonSpin : Script Debug.LogError("Transform is NULL!"); } } - protected override void update() - { - rotation += RotateSpeed * 0.16; - Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f); - } } \ No newline at end of file From 97432b866687da2a4b5e67a1d25704298b3b6782 Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Thu, 27 Oct 2022 12:46:42 +0800 Subject: [PATCH 09/10] Accounted for updating collider storage when a collider is removed --- SHADE_Engine/src/Scripting/SHScriptEngine.cpp | 21 +++++++++++++++++++ SHADE_Engine/src/Scripting/SHScriptEngine.h | 2 ++ SHADE_Managed/src/Components/Collider.cxx | 14 +++++++++++++ SHADE_Managed/src/Components/Collider.hxx | 11 ++++++++++ 4 files changed, 48 insertions(+) diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 3a2ea29f..0a687601 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -299,6 +299,14 @@ namespace SHADE 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 */ /*-----------------------------------------------------------------------------------*/ @@ -405,6 +413,12 @@ namespace SHADE DEFAULT_CSHARP_NAMESPACE + ".Collider", "OnColliderBoundChanged" ); + csColliderOnRemoved = dotNet.GetFunctionPtr + ( + DEFAULT_CSHARP_LIB_NAME, + DEFAULT_CSHARP_NAMESPACE + ".Collider", + "OnColliderRemoved" + ); csEditorRenderScripts = dotNet.GetFunctionPtr ( DEFAULT_CSHARP_LIB_NAME, @@ -447,6 +461,13 @@ namespace SHADE 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 a909a334..c38e3618 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.h +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.h @@ -253,6 +253,7 @@ namespace SHADE CsScriptDeserialiseYamlFuncPtr csScriptsDeserialiseYaml = nullptr; // - Events CsEventRelayFuncPtr csColliderOnListChanged = nullptr; + CsEventRelayFuncPtr csColliderOnRemoved = nullptr; // - Editor CsScriptEditorFuncPtr csEditorRenderScripts = nullptr; CsFuncPtr csEditorUndo = nullptr; @@ -264,6 +265,7 @@ namespace SHADE SHEventHandle onEntityDestroyed(SHEventPtr eventPtr); SHEventHandle onColliderAdded(SHEventPtr eventPtr); SHEventHandle onColliderRemoved(SHEventPtr eventPtr); + SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr); /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Managed/src/Components/Collider.cxx b/SHADE_Managed/src/Components/Collider.cxx index 7f41ad44..6d2c2f01 100644 --- a/SHADE_Managed/src/Components/Collider.cxx +++ b/SHADE_Managed/src/Components/Collider.cxx @@ -180,8 +180,21 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* 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; @@ -204,6 +217,7 @@ namespace SHADE { collidersList->Remove(wr); } + SAFE_NATIVE_CALL_END("Collider.OnColliderBoundChanged") } void Collider::updateSubColliderList() diff --git a/SHADE_Managed/src/Components/Collider.hxx b/SHADE_Managed/src/Components/Collider.hxx index 8e63fc83..f827ab71 100644 --- a/SHADE_Managed/src/Components/Collider.hxx +++ b/SHADE_Managed/src/Components/Collider.hxx @@ -224,6 +224,17 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* 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: From 623e9641607b3a5287c4c79bc8ada2ce8cc889fa Mon Sep 17 00:00:00 2001 From: Kah Wei Date: Thu, 27 Oct 2022 17:51:30 +0800 Subject: [PATCH 10/10] Fixed bug causing issues with debugging not working --- SHADE_Engine/src/Scripting/SHScriptEngine.cpp | 6 ++++++ TempScriptsFolder/PhysicsTest.cs | 11 +++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp index 0a687601..f0f8912b 100644 --- a/SHADE_Engine/src/Scripting/SHScriptEngine.cpp +++ b/SHADE_Engine/src/Scripting/SHScriptEngine.cpp @@ -192,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()); } diff --git a/TempScriptsFolder/PhysicsTest.cs b/TempScriptsFolder/PhysicsTest.cs index 72e8a205..6f9774c9 100644 --- a/TempScriptsFolder/PhysicsTest.cs +++ b/TempScriptsFolder/PhysicsTest.cs @@ -1,17 +1,22 @@ using SHADE; using System; - public class PhysicsTest : Script { [SerializeField] [Tooltip("Force to apply when pressing Space.")] - private Vector3 Force = new Vector3(0.0f, 1.0f, 0.0f); + private Vector3 Force = new Vector3(0.0f, 200.0f, 0.0f); + private Transform Transform; private RigidBody RigidBody; private Collider Collider; public PhysicsTest(GameObject gameObj) : base(gameObj) { } protected override void awake() { + Transform = GetComponent(); + if (Transform == null) + { + Debug.LogError("Transform is NULL!"); + } RigidBody = GetComponent(); if (RigidBody == null) { @@ -31,6 +36,8 @@ public class PhysicsTest : Script if (Input.GetKeyUp(Input.KeyCode.Space)) { RigidBody.AddForce(Force); + Debug.Log($"Jump!"); } + Debug.Log($"{Transform.LocalPosition.y}"); } } \ No newline at end of file