Merge remote-tracking branch 'origin/main' into SP3-2-Physics

This commit is contained in:
Diren D Bharwani 2022-11-14 18:39:06 +08:00
commit d897ac01e6
15 changed files with 395 additions and 8 deletions

27
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,27 @@
---
name: Bug report
about: Report a bug that should be fixed
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest a feature for the project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -560,6 +560,34 @@ namespace SHADE
assetCollection.emplace(newAsset.id, newAsset); assetCollection.emplace(newAsset.id, newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset); SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
}
else if (ext == SCENE_EXTENSION)
{
SHAsset newAsset{
path.stem().string(),
GenerateAssetID(AssetType::SCENE),
AssetType::SCENE,
path,
false
};
assetCollection.emplace(newAsset.id, newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
}
else if (ext == FONT_EXTENSION)
{
SHAsset newAsset{
path.stem().string(),
GenerateAssetID(AssetType::FONT),
AssetType::FONT,
path,
false
};
assetCollection.emplace(newAsset.id, newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id; return newAsset.id;
} }
} }
@ -571,8 +599,11 @@ namespace SHADE
for (auto& file : toGenNew) for (auto& file : toGenNew)
{ {
auto newID{ GenerateNewMeta(file->path).value() }; auto newID{ GenerateNewMeta(file->path) };
file->assetMeta = &assetCollection[newID]; if (newID.has_value())
{
file->assetMeta = &assetCollection[newID.value()];
}
} }
for (auto& asset : std::ranges::views::values(assetCollection)) for (auto& asset : std::ranges::views::values(assetCollection))

View File

@ -130,6 +130,14 @@ namespace SHADE
} }
// If item is folder // If item is folder
if (path.stem().string() == "bin"
|| path.stem().string() == "obj"
|| !std::filesystem::exists(path))
{
SHLOG_INFO("[FileSystem] Skipped paths in directory building: {}", path.string());
continue;
}
auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) }; auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) };
folderStack.push(newFolder); folderStack.push(newFolder);
} }

View File

@ -34,8 +34,11 @@ namespace SHADE
void SHRenderable::OnDestroy() void SHRenderable::OnDestroy()
{ {
// Remove from SuperBatch // Remove from SuperBatch
if (sharedMaterial)
{
Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); Handle<SHSuperBatch> superBatch = sharedMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();
superBatch->Remove(this); superBatch->Remove(this);
}
// Free resources // Free resources
if (material) if (material)

View File

@ -288,7 +288,15 @@ namespace YAML
{ {
YAML::Node node; YAML::Node node;
node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMesh>(rhs.GetMesh()).value_or(0); node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMesh>(rhs.GetMesh()).value_or(0);
auto mat = rhs.GetMaterial();
if (mat)
{
node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMaterial>(rhs.GetMaterial()->GetBaseMaterial()).value_or(0); node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMaterial>(rhs.GetMaterial()->GetBaseMaterial()).value_or(0);
}
else
{
node[MAT_YAML_TAG.data()] = 0;
}
return node; return node;
} }
static bool decode(YAML::Node const& node, SHRenderable& rhs) static bool decode(YAML::Node const& node, SHRenderable& rhs)

View File

@ -27,6 +27,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Scene/SHSceneGraph.h" #include "Scene/SHSceneGraph.h"
#include "Tools/SHLog.h" #include "Tools/SHLog.h"
#include "Graphics\MiddleEnd\Interface\SHRenderable.h"
// Project Headers // Project Headers
#include "Utility/Convert.hxx" #include "Utility/Convert.hxx"
#include "Utility/Debug.hxx" #include "Utility/Debug.hxx"
@ -36,6 +37,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Components/Camera.hxx" #include "Components/Camera.hxx"
#include "Components/CameraArm.hxx" #include "Components/CameraArm.hxx"
#include "Components/Light.hxx" #include "Components/Light.hxx"
#include "Components\Renderable.hxx"
namespace SHADE namespace SHADE
{ {
@ -166,6 +168,70 @@ namespace SHADE
return T(); return T();
} }
generic<typename T>
System::Collections::Generic::IEnumerable<T>^ ECS::GetComponentsInChildren(EntityID entity)
{
System::Type^ componentType = T::typeid;
// Check if entity is correct
if (!SHEntityManager::IsValidEID(entity))
{
std::ostringstream oss;
oss << "[ECS] Attempted to retrieve Component \""
<< Convert::ToNative(componentType->Name)
<< "\" from invalid Entity.";
Debug::LogError(oss.str());
return nullptr;
}
// Search all elements via a iterative breadth first search
System::Collections::Generic::List<T>^ results;
System::Collections::Generic::Queue<Entity>^ searchSpace = gcnew System::Collections::Generic::Queue<Entity>();
// Start off with direct children
SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(entity);
if (entityNode == nullptr)
{
std::ostringstream oss;
oss << "[ScriptStore] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
SHLog::Warning(oss.str());
}
for (const auto& child : entityNode->GetChildren())
{
searchSpace->Enqueue(child->GetEntityID());
}
// Continue with all subsequent children
while (searchSpace->Count > 0)
{
// Check if this entity has the component we need
Entity curr = searchSpace->Dequeue();
T component = GetComponent<T>(curr);
if (component != nullptr)
{
// We only construct if we need to
if (results == nullptr)
results = gcnew System::Collections::Generic::List<T>();
results->Add(component);
}
// Add children to the queue
SHSceneNode* sceneGraphNode = SHSceneManager::GetCurrentSceneGraph().GetNode(curr);
if (sceneGraphNode == nullptr)
{
std::ostringstream oss;
oss << "[ECS_CLI] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
SHLog::Warning(oss.str());
continue;
}
for (const auto& child : sceneGraphNode->GetChildren())
{
searchSpace->Enqueue(child->GetEntityID());
}
}
// None here
return results;
}
generic <typename T> generic <typename T>
T ECS::EnsureComponent(EntityID entity) T ECS::EnsureComponent(EntityID entity)
{ {
@ -249,6 +315,7 @@ namespace SHADE
static ECS::ECS() static ECS::ECS()
{ {
componentMap.Add(createComponentSet<SHTransformComponent, Transform>()); componentMap.Add(createComponentSet<SHTransformComponent, Transform>());
componentMap.Add(createComponentSet<SHRenderable, Renderable>());
componentMap.Add(createComponentSet<SHColliderComponent, Collider>()); componentMap.Add(createComponentSet<SHColliderComponent, Collider>());
componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>()); componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>());
componentMap.Add(createComponentSet<SHCameraComponent, Camera>()); componentMap.Add(createComponentSet<SHCameraComponent, Camera>());

View File

@ -53,7 +53,7 @@ namespace SHADE
generic<typename T> where T : BaseComponent generic<typename T> where T : BaseComponent
static T GetComponent(EntityID entity); static T GetComponent(EntityID entity);
/// <summary> /// <summary>
/// Retrieves the first Component from the specified GameObjectt's children that /// Retrieves the first Component from the specified GameObject's children that
/// matches the specified type. /// matches the specified type.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam> /// <typeparam name="T">Type of the Component to get.</typeparam>
@ -65,6 +65,20 @@ namespace SHADE
generic<typename T> where T : BaseComponent generic<typename T> where T : BaseComponent
static T GetComponentInChildren(EntityID entity); static T GetComponentInChildren(EntityID entity);
/// <summary> /// <summary>
/// Retrieves a list of Components from the specified GameObject's children that
/// matches the specified type.
/// This function performs allocations. If expecting only 1 component, use
/// GetComponentInChildren() instead.
/// This does not search the specified entity.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <param name="entity"> Entity object to get the Component from. </param>
/// <returns>
/// Newly allocated List of components. Will be null if no components are found.
/// </returns>
generic<typename T> where T : BaseComponent
static System::Collections::Generic::IEnumerable<T>^ GetComponentsInChildren(EntityID entity);
/// <summary>
/// Ensures a Component on the specified Entity. /// Ensures a Component on the specified Entity.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the Component to ensure.</typeparam> /// <typeparam name="T">Type of the Component to ensure.</typeparam>

View File

@ -170,6 +170,14 @@ namespace SHADE
return ECS::GetComponentInChildren<T>(entity); return ECS::GetComponentInChildren<T>(entity);
} }
generic<typename T>
System::Collections::Generic::IEnumerable<T>^ GameObject::GetComponentsInChildren()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::GetComponentsInChildren<T>(entity);
}
generic <typename T> generic <typename T>
T GameObject::EnsureComponent() T GameObject::EnsureComponent()
{ {
@ -212,6 +220,13 @@ namespace SHADE
throw gcnew System::NullReferenceException(); throw gcnew System::NullReferenceException();
return ScriptStore::GetScriptInChildren<T>(entity); return ScriptStore::GetScriptInChildren<T>(entity);
} }
generic <typename T>
System::Collections::Generic::IEnumerable<T>^ GameObject::GetScriptsInChildren()
{
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::GetScriptsInChildren<T>(entity);
}
generic <typename T> generic <typename T>
System::Collections::Generic::IEnumerable<T>^ GameObject::GetScripts() System::Collections::Generic::IEnumerable<T>^ GameObject::GetScripts()

View File

@ -153,6 +153,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Retrieves the first Component from this GameObject's children that matches /// Retrieves the first Component from this GameObject's children that matches
/// the specified type. /// the specified type.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam> /// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns> /// <returns>
@ -162,6 +163,19 @@ namespace SHADE
generic<typename T> where T : BaseComponent generic<typename T> where T : BaseComponent
T GetComponentInChildren(); T GetComponentInChildren();
/// <summary> /// <summary>
/// Retrieves a list of Components from this GameObject's children that matches
/// the specified type.
/// This function performs allocations. If expecting only 1 component, use
/// GetComponentInChildren() instead.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns>
/// Newly allocated List of components. Will be null if no components are found.
/// </returns>
generic<typename T> where T : BaseComponent
System::Collections::Generic::IEnumerable<T>^ GetComponentsInChildren();
/// <summary>
/// Ensures a Component on this GameObject. /// Ensures a Component on this GameObject.
/// </summary> /// </summary>
/// <typeparam name="T">Type of the Component to ensure.</typeparam> /// <typeparam name="T">Type of the Component to ensure.</typeparam>
@ -201,12 +215,26 @@ namespace SHADE
/// Retrieves a Script of the specified type from child GameObjects. /// Retrieves a Script of the specified type from child GameObjects.
/// If multiple Scripts of the same specified type are added on the same /// If multiple Scripts of the same specified type are added on the same
/// child GameObject, this will retrieve the first one added. /// child GameObject, this will retrieve the first one added.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary> /// </summary>
/// <typeparam name="T">Type of Script to retrieve.</typeparam> /// <typeparam name="T">Type of Script to retrieve.</typeparam>
/// <returns>Reference to the Script to retrieve.</returns> /// <returns>Reference to the Script to retrieve.</returns>
generic<typename T> where T : ref class, Script generic<typename T> where T : ref class, Script
T GetScriptInChildren(); T GetScriptInChildren();
/// <summary> /// <summary>
/// Retrieves a list of Scripts from this GameObject's children that matches
/// the specified type.
/// This function performs allocations. If expecting only 1 component, use
/// GetComponentInChildren() instead.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns>
/// Newly allocated List of components. Will be null if no components are found.
/// </returns>
generic<typename T> where T : ref class, Script
System::Collections::Generic::IEnumerable<T>^ GetScriptsInChildren();
/// <summary>
/// Retrieves a immutable list of Scripts of the specified type from this /// Retrieves a immutable list of Scripts of the specified type from this
/// GameObject. /// GameObject.
/// </summary> /// </summary>

View File

@ -42,6 +42,12 @@ namespace SHADE
return owner.GetComponentInChildren<T>(); return owner.GetComponentInChildren<T>();
} }
generic<typename T>
System::Collections::Generic::IEnumerable<T>^ Script::GetComponentsInChildren()
{
return owner.GetComponentsInChildren<T>();
}
generic <typename T> generic <typename T>
T Script::EnsureComponent() T Script::EnsureComponent()
{ {
@ -72,6 +78,11 @@ namespace SHADE
{ {
return ScriptStore::GetScriptInChildren<T>(owner.GetEntity()); return ScriptStore::GetScriptInChildren<T>(owner.GetEntity());
} }
generic <typename T>
System::Collections::Generic::IEnumerable<T>^ Script::GetScriptsInChildren()
{
return ScriptStore::GetScriptsInChildren<T>(owner.GetEntity());
}
generic <typename T> generic <typename T>
System::Collections::Generic::IEnumerable<T>^ Script::GetScripts() System::Collections::Generic::IEnumerable<T>^ Script::GetScripts()

View File

@ -69,6 +69,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Retrieves the first Component from this GameObject's children that matches /// Retrieves the first Component from this GameObject's children that matches
/// the specified type. /// the specified type.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary> /// </summary>
/// <typeparam name="T"> /// <typeparam name="T">
/// Type of the Component to get. Must be derived from BaseComponent. /// Type of the Component to get. Must be derived from BaseComponent.
@ -77,6 +78,19 @@ namespace SHADE
generic<typename T> where T : BaseComponent generic<typename T> where T : BaseComponent
T GetComponentInChildren(); T GetComponentInChildren();
/// <summary> /// <summary>
/// Retrieves a list of Components from this GameObject's children that
/// matches the specified type.
/// This function performs allocations. If expecting only 1 component, use
/// GetComponentInChildren() instead.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns>
/// Newly allocated List of components. Will be null if no components are found.
/// </returns>
generic<typename T> where T : BaseComponent
System::Collections::Generic::IEnumerable<T>^ GetComponentsInChildren();
/// <summary>
/// Ensures a Component on the GameObject that this Script belongs to. /// Ensures a Component on the GameObject that this Script belongs to.
/// </summary> /// </summary>
/// <typeparam name="T"> /// <typeparam name="T">
@ -121,6 +135,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Retrieves the first Script from this GameObject's children that matches the /// Retrieves the first Script from this GameObject's children that matches the
/// specified type. /// specified type.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary> /// </summary>
/// <typeparam name="T"> /// <typeparam name="T">
/// Type of script to get. /// Type of script to get.
@ -130,6 +145,19 @@ namespace SHADE
generic<typename T> where T : ref class, Script generic<typename T> where T : ref class, Script
T GetScriptInChildren(); T GetScriptInChildren();
/// <summary> /// <summary>
/// Retrieves a list of Scripts from this GameObject's children that matches
/// the specified type.
/// This function performs allocations. If expecting only 1 component, use
/// GetComponentInChildren() instead.
/// Unlike Unity, we do not search this GameObject, only the children.
/// </summary>
/// <typeparam name="T">Type of the Component to get.</typeparam>
/// <returns>
/// Newly allocated List of components. Will be null if no components are found.
/// </returns>
generic<typename T> where T : ref class, Script
System::Collections::Generic::IEnumerable<T>^ GetScriptsInChildren();
/// <summary>
/// Retrieves a immutable list of scripts from the specified Entity that /// Retrieves a immutable list of scripts from the specified Entity that
/// matches the specified type. /// matches the specified type.
/// <br/> /// <br/>

View File

@ -211,6 +211,70 @@ namespace SHADE
return T(); return T();
} }
generic<typename T>
System::Collections::Generic::IEnumerable<T>^ ScriptStore::GetScriptsInChildren(Entity entity)
{
System::Type^ componentType = T::typeid;
// Check if entity is correct
if (!SHEntityManager::IsValidEID(entity))
{
std::ostringstream oss;
oss << "[ScriptStore] Attempted to retrieve Script \""
<< Convert::ToNative(componentType->Name)
<< "\" from invalid Entity.";
Debug::LogError(oss.str());
return nullptr;
}
// Search all elements via a iterative breadth first search
System::Collections::Generic::List<T>^ results;
System::Collections::Generic::Queue<Entity>^ searchSpace = gcnew System::Collections::Generic::Queue<Entity>();
// Start off with direct children
SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(entity);
if (entityNode == nullptr)
{
std::ostringstream oss;
oss << "[ScriptStore] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
SHLog::Warning(oss.str());
}
for (const auto& child : entityNode->GetChildren())
{
searchSpace->Enqueue(child->GetEntityID());
}
// Continue with all subsequent children
while (searchSpace->Count > 0)
{
// Check if this entity has the component we need
Entity curr = searchSpace->Dequeue();
T script = GetScript<T>(curr);
if (script != nullptr)
{
// We only construct if we need to
if (results == nullptr)
results = gcnew System::Collections::Generic::List<T>();
results->Add(script);
}
// Add children to the queue
SHSceneNode* sceneGraphNode = SHSceneManager::GetCurrentSceneGraph().GetNode(curr);
if (sceneGraphNode == nullptr)
{
std::ostringstream oss;
oss << "[ScriptStore] Failed to retrieve SceneGraphNode of entity #" << entity << ". This should not happen!";
SHLog::Warning(oss.str());
continue;
}
for (const auto& child : sceneGraphNode->GetChildren())
{
searchSpace->Enqueue(child->GetEntityID());
}
}
// None here
return results;
}
generic <typename T> generic <typename T>
System::Collections::Generic::IEnumerable<T>^ ScriptStore::GetScripts(Entity entity) System::Collections::Generic::IEnumerable<T>^ ScriptStore::GetScripts(Entity entity)
{ {

View File

@ -137,6 +137,29 @@ namespace SHADE
generic<typename T> where T : ref class, Script generic<typename T> where T : ref class, Script
static T GetScriptInChildren(Entity entity); static T GetScriptInChildren(Entity entity);
/// <summary> /// <summary>
/// Retrieves the list of Scripts from the specified Entity and the Entity's
/// children that matches the specified type.
/// This function performs allocations. If expecting only 1 component, use
/// GetScriptInChildren() instead.
/// This does not search the specified entity.
/// </summary>
/// <typeparam name="T">
/// Type of script to get.
/// This needs to be a default constructable Script.
/// </typeparam>
/// <param name="entity">
/// The entity which the script to retrieve is attached.
/// </param>
/// <returns>
/// Reference to the script. This can be null if no script of the specified
/// type is attached.
/// </returns>
/// <exception cref="ArgumentException">
/// If the specified Entity is invalid.
/// </exception>
generic<typename T> where T : ref class, Script
static System::Collections::Generic::IEnumerable<T>^ GetScriptsInChildren(Entity entity);
/// <summary>
/// Retrieves a immutable list of scripts from the specified Entity that /// Retrieves a immutable list of scripts from the specified Entity that
/// matches the specified type. /// matches the specified type.
/// <br/> /// <br/>

View File

@ -28,7 +28,47 @@ namespace SHADE
template<typename FieldType> template<typename FieldType>
bool SerialisationUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode) bool SerialisationUtilities::fieldInsertYaml(System::Reflection::FieldInfo^ fieldInfo, System::Object^ object, YAML::Node& fieldNode)
{ {
return varInsertYamlInternal<FieldType>(fieldInfo->GetValue(object), fieldNode); // Handle null objects
System::Object^ fieldObject = fieldInfo->GetValue(object);
if (fieldObject == nullptr)
{
// Default construct if null
if (fieldInfo->FieldType == FieldType::typeid)
{
if constexpr (std::is_same_v<FieldType, System::Enum>)
{
fieldNode = 0;
}
else if constexpr (std::is_same_v<FieldType, System::String>)
{
fieldNode = "";
}
else if constexpr (std::is_same_v<FieldType, Vector2>)
{
fieldNode.SetStyle(YAML::EmitterStyle::Flow);
fieldNode.push_back(0.0f);
fieldNode.push_back(0.0f);
}
else if constexpr (std::is_same_v<FieldType, Vector3>)
{
fieldNode.SetStyle(YAML::EmitterStyle::Flow);
fieldNode.push_back(0.0f);
fieldNode.push_back(0.0f);
fieldNode.push_back(0.0f);
}
else if constexpr (std::is_same_v<FieldType, GameObject>)
{
fieldNode = MAX_EID;
}
else
{
fieldNode = FieldType();
}
return true;
}
return false;
}
return varInsertYamlInternal<FieldType>(fieldObject, fieldNode);
} }
template<typename FieldType> template<typename FieldType>
bool SerialisationUtilities::varInsertYamlInternal(System::Object^ object, YAML::Node& fieldNode) bool SerialisationUtilities::varInsertYamlInternal(System::Object^ object, YAML::Node& fieldNode)