Merge branch 'main' into SP3-2-Physics

This commit is contained in:
Diren D Bharwani 2022-11-13 17:57:30 +08:00
commit c953931f4f
40 changed files with 772 additions and 272 deletions

View File

@ -1,5 +1,5 @@
- EID: 0 - EID: 0
Name: Default Name: Camera
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -22,7 +22,7 @@
Strength: 0 Strength: 0
Scripts: ~ Scripts: ~
- EID: 1 - EID: 1
Name: Default Name: Floor
IsActive: true IsActive: true
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
@ -87,4 +87,145 @@
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1
Position Offset: {x: 0, y: 0, z: 0} Position Offset: {x: 0, y: 0, z: 0}
Scripts: ~ Scripts: ~
- EID: 3
Name: Empty
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -0.0094268322, y: 0, z: 0}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1}
Scripts: ~
- EID: 4
Name: Empty2
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0, z: 0}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
Scripts: ~
- EID: 9
Name: Bag
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: 0, z: 0}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
Renderable Component:
Mesh: 144838771
Material: 123745521
Scripts: ~
- EID: 6
Name: AI
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -8, y: -2, z: 2.5}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 1, y: 1, z: 1}
Renderable Component:
Mesh: 149697411
Material: 126974645
RigidBody Component:
Type: Dynamic
Mass: 1
Drag: 0
Angular Drag: 0
Use Gravity: true
Interpolate: false
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: true
Freeze Rotation Y: true
Freeze Rotation Z: true
Collider Component:
Colliders:
- Is Trigger: false
Type: Box
Half Extents: {x: 0.5, y: 0.5, z: 0.5}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0.5, z: 0}
Scripts: ~
- EID: 7
Name: BigBoi
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -16.8647861, z: -14.039052}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 28.1434975, y: 28.1434975, z: 28.1434975}
Renderable Component:
Mesh: 149697411
Material: 126974645
Scripts: ~
- EID: 8
Name: AmbientLight
IsActive: true
NumberOfChildren: 0
Components:
Light Component:
Position: {x: 0, y: 0, z: 0}
Type: Ambient
Direction: {x: 0, y: 0, z: 1}
Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295
Strength: 0.25
Scripts: ~
- EID: 5
Name: item
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0, y: -2, z: -5}
Rotate: {x: 0, y: 0, z: 0}
Scale: {x: 2, y: 2, z: 2}
Renderable Component:
Mesh: 144838771
Material: 123745521
RigidBody Component:
Type: Dynamic
Mass: 1
Drag: 0
Angular Drag: 0
Use Gravity: true
Interpolate: false
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: true
Freeze Rotation Y: true
Freeze Rotation Z: true
Collider Component:
Colliders:
- Is Trigger: false
Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0.5, z: 0}
- Is Trigger: true
Type: Box
Half Extents: {x: 2, y: 2, z: 2}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0.5, z: 0}
Scripts:
- Type: Item
currCategory: 0
- Type: PickAndThrow
throwForce: [100, 200, 100]
item: 51000

View File

@ -51,7 +51,6 @@ public class AIPrototype : Script
private GameObject? player; private GameObject? player;
public AIPrototype(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -7,7 +7,6 @@ namespace SHADE_Scripting
{ {
public float turnSpeed = 0.5f; public float turnSpeed = 0.5f;
public CameraControl(GameObject go) : base(go) { }
protected override void update() protected override void update()
{ {
//Camera //Camera

View File

@ -3,7 +3,6 @@ using System;
public class CameraFix : Script public class CameraFix : Script
{ {
public CameraFix(GameObject gameObj) : base(gameObj) { }
private Transform tranform; private Transform tranform;
public Vector3 pos = Vector3.Zero; public Vector3 pos = Vector3.Zero;

View File

@ -10,7 +10,6 @@ public class Item : Script
} }
public ItemCategory currCategory; public ItemCategory currCategory;
public Item(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -8,7 +8,6 @@ public class PhysicsTest : Script
private Transform Transform; private Transform Transform;
private RigidBody RigidBody; private RigidBody RigidBody;
private Collider Collider; private Collider Collider;
public PhysicsTest(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -14,7 +14,6 @@ public class PickAndThrow : Script
private float lastXDir; private float lastXDir;
private float lastZDir; private float lastZDir;
private bool inRange = false; private bool inRange = false;
public PickAndThrow(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -73,8 +73,6 @@ public class PlayerController : Script
public float mediumMultiper = 0.5f; public float mediumMultiper = 0.5f;
public float heavyMultiper = 0.25f; public float heavyMultiper = 0.25f;
public PlayerController(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {
//default setup //default setup

View File

@ -2,8 +2,6 @@
public class PrintWhenActive : Script public class PrintWhenActive : Script
{ {
public PrintWhenActive(GameObject gameObj) : base(gameObj) { }
protected override void update() protected override void update()
{ {
Debug.Log("Active!"); Debug.Log("Active!");

View File

@ -23,7 +23,6 @@ public class RaccoonShowcase : Script
[Range(-5, 5)] [Range(-5, 5)]
public List<int> intList = new List<int>(new int[] { 2, 8, 2, 6, 8, 0, 1 }); public List<int> intList = new List<int>(new int[] { 2, 8, 2, 6, 8, 0, 1 });
public List<Light.Type> enumList = new List<Light.Type>(new Light.Type[] { Light.Type.Point, Light.Type.Directional, Light.Type.Ambient }); public List<Light.Type> enumList = new List<Light.Type>(new Light.Type[] { Light.Type.Point, Light.Type.Directional, Light.Type.Ambient });
public RaccoonShowcase(GameObject gameObj) : base(gameObj) {}
protected override void awake() protected override void awake()
{ {

View File

@ -14,8 +14,6 @@ public class RaccoonSpin : Script
[SerializeField] [SerializeField]
private CallbackEvent<int, double, Vector3> testEvent3 = new CallbackEvent<int, double, Vector3>(); private CallbackEvent<int, double, Vector3> testEvent3 = new CallbackEvent<int, double, Vector3>();
private Transform Transform; private Transform Transform;
public RaccoonSpin(GameObject gameObj) : base(gameObj) { }
protected override void awake() protected override void awake()
{ {

View File

@ -15,7 +15,6 @@ namespace SHADE_Scripting
public float turnSpeedPitch = 0.3f; public float turnSpeedPitch = 0.3f;
public float turnSpeedYaw = 0.5f; public float turnSpeedYaw = 0.5f;
public float pitchClamp = 45.0f; public float pitchClamp = 45.0f;
public ThirdPersonCamera(GameObject go) : base(go) { }
protected override void awake() protected override void awake()
{ {

View File

@ -63,14 +63,6 @@ namespace SHADE
} }
UpdateCameraComponent(editorCamera); UpdateCameraComponent(editorCamera);
if (SHInputManager::GetKey(SHInputManager::SH_KEYCODE::LEFT_ALT))
{
UpdateEditorArm(dt, true, SHVec3{ 0.0f });
}
else
UpdateEditorArm(dt, false, SHVec3{ 0.0f });
} }
void SHCameraSystem::UpdateEditorArm(double dt,bool active ,SHVec3 const& targetPos) noexcept void SHCameraSystem::UpdateEditorArm(double dt,bool active ,SHVec3 const& targetPos) noexcept

View File

@ -13,6 +13,7 @@
#include "Editor/SHEditor.h" #include "Editor/SHEditor.h"
#include "Editor/DragDrop/SHDragDrop.hpp" #include "Editor/DragDrop/SHDragDrop.hpp"
#include "Editor/EditorWindow/MaterialInspector/SHMaterialInspector.h" #include "Editor/EditorWindow/MaterialInspector/SHMaterialInspector.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
namespace SHADE namespace SHADE
{ {

View File

@ -15,6 +15,7 @@
#include "Editor/DragDrop/SHDragDrop.hpp" #include "Editor/DragDrop/SHDragDrop.hpp"
#include "Tools/SHException.h" #include "Tools/SHException.h"
#include "Editor/IconsMaterialDesign.h" #include "Editor/IconsMaterialDesign.h"
#include "SHHierarchyPanelCommands.h"
//#==============================================================# //#==============================================================#
//|| Library Includes || //|| Library Includes ||
@ -105,14 +106,21 @@ namespace SHADE
PasteEntities(editor->selectedEntities.back()); PasteEntities(editor->selectedEntities.back());
} }
} }
if(ImGui::IsKeyReleased(ImGuiKey_Delete))
{
DeleteSelectedEntities();
}
} }
} }
if(ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) if(ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{ {
ParentSelectedEntities(MAX_EID, draggingEntities); if(ImGui::IsDragDropActive())
draggingEntities.clear(); {
ImGui::ClearDragDrop(); ParentSelectedEntities(MAX_EID, draggingEntities);
draggingEntities.clear();
ImGui::ClearDragDrop();
}
} }
ImGui::End(); ImGui::End();
} }
@ -255,9 +263,10 @@ namespace SHADE
PasteEntities(eid); PasteEntities(eid);
skipFrame = true; skipFrame = true;
} }
if (ImGui::Selectable(std::format("{} Delete", ICON_MD_DELETE).data())) if (ImGui::Selectable(std::format("{} Delete selected", ICON_MD_DELETE).data()))
{ {
SHEntityManager::DestroyEntity(eid); //SHEntityManager::DestroyEntity(eid);
DeleteSelectedEntities();
} }
if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data())) if ((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
@ -282,9 +291,12 @@ namespace SHADE
} }
else editor->selectedEntities.clear(); else editor->selectedEntities.clear();
} }
else if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) else
editor->selectedEntities.clear(); {
editor->selectedEntities.push_back(eid); if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid);
}
}//if not selected }//if not selected
else else
{ {
@ -365,14 +377,16 @@ namespace SHADE
if (eid == beginEID || eid == endEID) if (eid == beginEID || eid == endEID)
{ {
startSelecting = true; startSelecting = true;
editor->selectedEntities.push_back(eid); if(std::ranges::find(editor->selectedEntities, eid) == editor->selectedEntities.end())
editor->selectedEntities.push_back(eid);
} }
} }
else else
{ {
if (!endSelecting) if (!endSelecting)
{ {
editor->selectedEntities.push_back(eid); if (std::ranges::find(editor->selectedEntities, eid) == editor->selectedEntities.end())
editor->selectedEntities.push_back(eid);
if (eid == endEID || eid == beginEID) if (eid == endEID || eid == beginEID)
{ {
endSelecting = true; endSelecting = true;
@ -397,47 +411,39 @@ namespace SHADE
void SHHierarchyPanel::CopySelectedEntities() void SHHierarchyPanel::CopySelectedEntities()
{ {
const auto editor = SHSystemManager::GetSystem<SHEditor>(); const auto editor = SHSystemManager::GetSystem<SHEditor>();
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(editor->selectedEntities)); auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
std::vector<EntityID> entitiesToCopy{};
std::ranges::copy_if(editor->selectedEntities, std::back_inserter(entitiesToCopy), [&sceneGraph](EntityID const& eid)
{
if(sceneGraph.GetParent(eid)->GetEntityID() == MAX_EID)
return true;
return false;
});
SHClipboardUtilities::WriteToClipboard(SHSerialization::SerializeEntitiesToString(entitiesToCopy));
} }
void SHHierarchyPanel::PasteEntities(EntityID parentEID) void SHHierarchyPanel::PasteEntities(EntityID parentEID)
{ {
SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), parentEID)); //SetScrollTo(SHSerialization::DeserializeEntitiesFromString(SHClipboardUtilities::GetDataFromClipboard(), parentEID).front());
SHCommandManager::PerformCommand(std::make_shared<SHPasteEntitiesCommand>(SHClipboardUtilities::GetDataFromClipboard(), parentEID));
} }
void SHCreateEntityCommand::Execute() void SHHierarchyPanel::DeleteSelectedEntities()
{ {
EntityID newEID = SHEntityManager::CreateEntity(eid); const auto editor = SHSystemManager::GetSystem<SHEditor>();
if (eid == MAX_EID) auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
eid = newEID;
std::vector<EntityID> entitiesToDelete{};
std::ranges::copy_if(editor->selectedEntities, std::back_inserter(entitiesToDelete), [&sceneGraph, &selectedEntities = editor->selectedEntities](EntityID const& eid)
{
EntityID parentEID = sceneGraph.GetParent(eid)->GetEntityID();
if (parentEID == MAX_EID)
return true;
else if(std::ranges::find(selectedEntities, parentEID) == selectedEntities.end())
return true;
return false;
});
SHCommandManager::PerformCommand(std::make_shared<SHDeleteEntitiesCommand>(entitiesToDelete));
} }
void SHCreateEntityCommand::Undo()
{
SHEntityManager::DestroyEntity(eid);
}
void SHEntityParentCommand::Execute()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].newParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
}
}
void SHEntityParentCommand::Undo()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].oldParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
}
}
}//namespace SHADE }//namespace SHADE

View File

@ -10,7 +10,6 @@
#include "imgui_internal.h" #include "imgui_internal.h"
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h" #include "Editor/EditorWindow/SHEditorWindow.h"
#include "Editor/Command/SHCommand.hpp"
namespace SHADE namespace SHADE
{ {
class SHSceneNode; class SHSceneNode;
@ -33,6 +32,7 @@ namespace SHADE
void SelectAllEntities(); void SelectAllEntities();
void CopySelectedEntities(); void CopySelectedEntities();
void PasteEntities(EntityID parentEID = MAX_EID); void PasteEntities(EntityID parentEID = MAX_EID);
void DeleteSelectedEntities();
bool skipFrame = false; bool skipFrame = false;
std::string filter; std::string filter;
bool isAnyNodeSelected = false; bool isAnyNodeSelected = false;
@ -41,33 +41,4 @@ namespace SHADE
};//class SHHierarchyPanel };//class SHHierarchyPanel
//Might move to a different file
class SHCreateEntityCommand final : public SHBaseCommand
{
public:
void Execute() override;
void Undo() override;
private:
EntityID eid = MAX_EID;
};
class SHEntityParentCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID oldParentEID = MAX_EID;
EntityID newParentEID = MAX_EID;
};
using EntityParentData = std::unordered_map<EntityID, Data>;
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData):entities(entityIDs),entityParentData(inEntityParentData){}
void Execute() override;
void Undo() override;
private:
std::vector<EntityID> entities;
std::unordered_map<EntityID, Data> entityParentData;
};
}//namespace SHADE }//namespace SHADE

View File

@ -0,0 +1,84 @@
#include "SHpch.h"
#include "SHHierarchyPanelCommands.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Scene/SHSceneManager.h"
#include "Serialization/SHSerialization.h"
#include "SHHierarchyPanel.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
namespace SHADE
{
void SHCreateEntityCommand::Execute()
{
EntityID newEID = SHEntityManager::CreateEntity(eid);
if (eid == MAX_EID)
eid = newEID;
}
void SHCreateEntityCommand::Undo()
{
SHEntityManager::DestroyEntity(eid);
}
void SHEntityParentCommand::Execute()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].newParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
}
}
void SHEntityParentCommand::Undo()
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
for (auto const& eid : entities)
{
if (entityParentData[eid].oldParentEID == MAX_EID)
sceneGraph.SetParent(eid, nullptr);
else
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
}
}
void SHPasteEntitiesCommand::Execute()
{
data.createdEntities.clear();
data.createdEntities = SHSerialization::DeserializeEntitiesFromString(data.entityData, data.parentEID);
data.entityData = SHSerialization::ResolveSerializedEntityIndices(data.entityData, data.createdEntities);
SHEditorWindowManager::GetEditorWindow<SHHierarchyPanel>()->SetScrollTo(data.createdEntities.begin()->second);
}
void SHPasteEntitiesCommand::Undo()
{
for (auto const& [oldEID, newEID] : data.createdEntities)
{
SHEntityManager::DestroyEntity(newEID);
}
}
void SHDeleteEntitiesCommand::Execute()
{
if(!data.createdEntities.empty())
{
for(auto& eid : data.entitiesToDelete)
{
eid = data.createdEntities[eid];
}
}
data.entityData = SHSerialization::SerializeEntitiesToString(data.entitiesToDelete);
for (auto const& eid : data.entitiesToDelete)
{
SHEntityManager::DestroyEntity(eid);
}
}
void SHDeleteEntitiesCommand::Undo()
{
data.createdEntities = SHSerialization::DeserializeEntitiesFromString(data.entityData);
data.entityData = SHSerialization::ResolveSerializedEntityIndices(data.entityData, data.createdEntities);
}
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <unordered_map>
#include "ECS_Base/SHECSMacros.h"
#include "Editor/Command/SHCommand.hpp"
#include "Serialization/SHSerialization.h"
namespace SHADE
{
class SHCreateEntityCommand final : public SHBaseCommand
{
public:
void Execute() override;
void Undo() override;
private:
EntityID eid = MAX_EID;
};
class SHEntityParentCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID oldParentEID = MAX_EID;
EntityID newParentEID = MAX_EID;
};
using EntityParentData = std::unordered_map<EntityID, Data>;
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData) :entities(entityIDs), entityParentData(inEntityParentData) {}
void Execute() override;
void Undo() override;
private:
std::vector<EntityID> entities{};
std::unordered_map<EntityID, Data> entityParentData{};
};
class SHPasteEntitiesCommand final : public SHBaseCommand
{
public:
struct Data
{
EntityID parentEID{MAX_EID};
std::string entityData{};
SHSerialization::CreatedEntitiesList createdEntities{};
};
SHPasteEntitiesCommand() = delete;
SHPasteEntitiesCommand(std::string const& serializedEntityData, EntityID parentEid = MAX_EID):data({parentEid, serializedEntityData, {}}){}
void Execute() override;
void Undo() override;
private:
Data data;
};
class SHDeleteEntitiesCommand final : public SHBaseCommand
{
public:
struct Data
{
std::vector<EntityID> entitiesToDelete{};
SHSerialization::CreatedEntitiesList createdEntities{};
std::string entityData{};
};
SHDeleteEntitiesCommand() = delete;
SHDeleteEntitiesCommand(std::vector<EntityID> entitiesToBeDeleted): data{entitiesToBeDeleted}{}
void Execute() override;
void Undo() override;
private:
Data data;
};
}

View File

@ -23,7 +23,7 @@
#include "Scene/SHSceneManager.h" #include "Scene/SHSceneManager.h"
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include "Serialization/Configurations/SHConfigurationManager.h" #include "Serialization/Configurations/SHConfigurationManager.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" }; const std::string LAYOUT_FOLDER_PATH{ std::string(ASSET_ROOT) + "/Editor/Layouts" };

View File

@ -0,0 +1,8 @@
#include "SHpch.h"
#include "SHEditorWindowManager.h"
namespace SHADE
{
SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{};
SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{};
}

View File

@ -0,0 +1,77 @@
#pragma once
#include <memory>
#include <unordered_map>
#include "SHEditorWindow.h"
#include "Tools/SHLog.h"
namespace SHADE
{
class SH_API SHEditorWindowManager
{
public:
//#==============================================================#
//|| Type Aliases ||
//#==============================================================#
using EditorWindowID = uint8_t;
using EditorWindowPtr = std::unique_ptr<SHEditorWindow>;
using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>;
/**
* @brief Get ID for the Editor Window Type
*
* @tparam T Type of Editor Window
* @return EditorWindowID ID of Editor Window Type
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static EditorWindowID GetEditorWindowID()
{
static EditorWindowID id;
static bool idCreated = false;
if (!idCreated)
{
id = windowCount++;
idCreated = true;
}
return id;
}
/**
* @brief Create an Editor Window
*
* @tparam T Type of Editor Window to create
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static void CreateEditorWindow()
{
static bool isCreated = false;
if (!isCreated)
{
editorWindows[GetEditorWindowID<T>()] = std::make_unique<T>();
isCreated = true;
}
else
{
SHLog::Warning("Attempt to create duplicate of Editor window type");
}
}
/**
* @brief Get pointer to the Editor Window
*
* @tparam T Type of editor window to retrieve
* @return T* Pointer to the editor window
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static T* GetEditorWindow()
{
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get());
}
static EditorWindowMap editorWindows;
private:
// Number of windows; used for Editor Window ID Generation
static EditorWindowID windowCount;
// Map of Editor Windows
friend class SHEditor;
};
}

View File

@ -33,14 +33,32 @@ namespace SHADE
void SHEditorViewport::Update() void SHEditorViewport::Update()
{ {
SHEditorWindow::Update(); SHEditorWindow::Update();
if (shouldUpdateCamera) auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>();
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (!editor->selectedEntities.empty())
{
if (SHTransformComponent* transform = SHComponentManager::GetComponent_s<SHTransformComponent>(editor->selectedEntities.front()))
{
targetPos = transform->GetWorldPosition();
}
else
{
targetPos = {};
}
}
else
{
targetPos = {};
}
if (shouldUpdateCamera || shouldUpdateCamArm)
{ {
auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>();
camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime()); camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime());
shouldUpdateCamera = false; shouldUpdateCamera = false;
} }
camSystem->UpdateEditorArm(SHFrameRateController::GetRawDeltaTime(), shouldUpdateCamArm, targetPos);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
SHEditor* editor = SHSystemManager::GetSystem<SHEditor>();
if (Begin()) if (Begin())
{ {
@ -64,6 +82,9 @@ namespace SHADE
shouldUpdateCamera = true; shouldUpdateCamera = true;
} }
shouldUpdateCamArm = ImGui::IsWindowHovered() && ImGui::IsKeyDown(ImGuiKey_LeftAlt) && ImGui::IsMouseDown(ImGuiMouseButton_Left);
if (editor->editorState != SHEditor::State::PLAY && ImGui::IsWindowFocused() && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) if (editor->editorState != SHEditor::State::PLAY && ImGui::IsWindowFocused() && !ImGui::IsMouseDown(ImGuiMouseButton_Right))
{ {
if (ImGui::IsKeyReleased(ImGuiKey_W)) if (ImGui::IsKeyReleased(ImGuiKey_W))

View File

@ -29,5 +29,7 @@ namespace SHADE
void DrawMenuBar() noexcept; void DrawMenuBar() noexcept;
SHVec2 beginCursorPos; SHVec2 beginCursorPos;
bool shouldUpdateCamera = false; bool shouldUpdateCamera = false;
bool shouldUpdateCamArm = false;
SHVec3 targetPos;
};//class SHEditorViewport };//class SHEditorViewport
}//namespace SHADE }//namespace SHADE

View File

@ -11,6 +11,8 @@
#include "Camera/SHCameraSystem.h" #include "Camera/SHCameraSystem.h"
#include "Editor/Command/SHCommandManager.h" #include "Editor/Command/SHCommandManager.h"
#include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h" #include "Editor/EditorWindow/ViewportWindow/SHEditorViewport.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
namespace SHADE namespace SHADE
{ {
void SHTransformGizmo::Init() void SHTransformGizmo::Init()

View File

@ -29,6 +29,7 @@
//#==============================================================# //#==============================================================#
//|| Editor Window Includes || //|| Editor Window Includes ||
//#==============================================================# //#==============================================================#
#include "EditorWindow/SHEditorWindowManager.h"
#include "EditorWindow/SHEditorWindowIncludes.h" #include "EditorWindow/SHEditorWindowIncludes.h"
//#==============================================================# //#==============================================================#
@ -77,8 +78,6 @@ namespace SHADE
//#==============================================================# //#==============================================================#
//Handle<SHVkCommandPool> SHEditor::imguiCommandPool; //Handle<SHVkCommandPool> SHEditor::imguiCommandPool;
//Handle<SHVkCommandBuffer> SHEditor::imguiCommandBuffer; //Handle<SHVkCommandBuffer> SHEditor::imguiCommandBuffer;
SHEditorWindowManager::EditorWindowMap SHEditorWindowManager::editorWindows{};
SHEditorWindowManager::EditorWindowID SHEditorWindowManager::windowCount{};
//std::vector<EntityID> SHEditor::selectedEntities; //std::vector<EntityID> SHEditor::selectedEntities;
//#==============================================================# //#==============================================================#

View File

@ -36,73 +36,7 @@ namespace SHADE
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkCommandPool; class SHVkCommandPool;
class SHEditorWindowManager
{
public:
//#==============================================================#
//|| Type Aliases ||
//#==============================================================#
using EditorWindowID = uint8_t;
using EditorWindowPtr = std::unique_ptr<SHEditorWindow>;
using EditorWindowMap = std::unordered_map<EditorWindowID, EditorWindowPtr>;
/**
* @brief Get ID for the Editor Window Type
*
* @tparam T Type of Editor Window
* @return EditorWindowID ID of Editor Window Type
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static EditorWindowID GetEditorWindowID()
{
static EditorWindowID id;
static bool idCreated = false;
if (!idCreated)
{
id = windowCount++;
idCreated = true;
}
return id;
}
/**
* @brief Create an Editor Window
*
* @tparam T Type of Editor Window to create
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static void CreateEditorWindow()
{
static bool isCreated = false;
if (!isCreated)
{
editorWindows[GetEditorWindowID<T>()] = std::make_unique<T>();
isCreated = true;
}
else
{
SHLog::Warning("Attempt to create duplicate of Editor window type");
}
}
/**
* @brief Get pointer to the Editor Window
*
* @tparam T Type of editor window to retrieve
* @return T* Pointer to the editor window
*/
template <typename T, std::enable_if_t<std::is_base_of_v<SHEditorWindow, T>, bool> = true>
static T* GetEditorWindow()
{
return reinterpret_cast<T*>(editorWindows[GetEditorWindowID<T>()].get());
}
static EditorWindowMap editorWindows;
private:
// Number of windows; used for Editor Window ID Generation
static EditorWindowID windowCount;
// Map of Editor Windows
friend class SHEditor;
};
/** /**
* @brief SHEditor static class contains editor variables and implementation of editor functions. * @brief SHEditor static class contains editor variables and implementation of editor functions.

View File

@ -17,6 +17,7 @@ of DigiPen Institute of Technology is prohibited.
#include <fstream> // std::fstream #include <fstream> // std::fstream
#include <filesystem> // std::filesystem::canonical, std::filesystem::remove #include <filesystem> // std::filesystem::canonical, std::filesystem::remove
#include <memory> // std::shared_ptr #include <memory> // std::shared_ptr
#include <thread> // std::this_thread::sleep_for
// Project Headers // Project Headers
#include "Tools/SHLogger.h" #include "Tools/SHLogger.h"
#include "Tools/SHStringUtils.h" #include "Tools/SHStringUtils.h"
@ -179,10 +180,10 @@ namespace SHADE
} }
// Prepare directory (delete useless files) // Prepare directory (delete useless files)
deleteFolder(CSPROJ_DIR + "\\net5.0"); deleteFolder(CSPROJ_DIR + "/net5.0");
deleteFolder(CSPROJ_DIR + "\\ref"); deleteFolder(CSPROJ_DIR + "/ref");
deleteFolder(CSPROJ_DIR + "\\obj"); deleteFolder(CSPROJ_DIR + "/obj");
deleteFolder(CSPROJ_DIR + "\\bin"); deleteFolder(CSPROJ_DIR + "/bin");
// Attempt to build the assembly // Attempt to build the assembly
std::ostringstream oss; std::ostringstream oss;
@ -216,7 +217,10 @@ namespace SHADE
// Clean up built files // Clean up built files
deleteFolder("./tmp"); deleteFolder("./tmp");
deleteFolder(CSPROJ_DIR + "\\obj"); deleteFolder(CSPROJ_DIR + "/bin");
using namespace std::chrono_literals;
std::this_thread::sleep_for(50ms); // Not sure why this works but it prevents the folders from respawning
deleteFolder(CSPROJ_DIR + "/obj");
// Read the build log and output to the console // Read the build log and output to the console
dumpBuildLog(BUILD_LOG_PATH); dumpBuildLog(BUILD_LOG_PATH);

View File

@ -61,20 +61,21 @@ namespace SHADE
out << YAML::EndSeq; out << YAML::EndSeq;
} }
static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, std::vector<EntityID>& createdEntities, EntityID parentEID = MAX_EID) static EntityID DeserializeEntity(YAML::iterator& it, YAML::Node const& node, SHSerialization::CreatedEntitiesList& createdEntities, EntityID parentEID = MAX_EID)
{ {
EntityID eid = MAX_EID; EntityID eid{MAX_EID}, oldEID{MAX_EID};
if (!node) if (!node)
return eid; return eid;
if (node[EIDNode]) if (node[EIDNode])
eid = node[EIDNode].as<EntityID>(); oldEID = eid = node[EIDNode].as<EntityID>();
std::string name = "Default"; std::string name = "UnnamedEntitiy";
if (node[EntityNameNode]) if (node[EntityNameNode])
name = node[EntityNameNode].as<std::string>(); name = node[EntityNameNode].as<std::string>();
//Compile component IDs //Compile component IDs
const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]); const auto componentIDList = SHSerialization::GetComponentIDList(node[ComponentsNode]);
eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID); eid = SHEntityManager::CreateEntity(componentIDList, eid, name, parentEID);
createdEntities.push_back(eid); createdEntities[oldEID] = eid;
//createdEntities.push_back(eid);
if (node[NumberOfChildrenNode]) if (node[NumberOfChildrenNode])
{ {
if (const int numOfChildren = node[NumberOfChildrenNode].as<int>(); numOfChildren > 0) if (const int numOfChildren = node[NumberOfChildrenNode].as<int>(); numOfChildren > 0)
@ -106,7 +107,7 @@ namespace SHADE
return NewSceneName.data(); return NewSceneName.data();
} }
YAML::Node entities = YAML::Load(assetData->data); YAML::Node entities = YAML::Load(assetData->data);
std::vector<EntityID> createdEntities{}; CreatedEntitiesList createdEntities{};
//Create Entities //Create Entities
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
@ -122,14 +123,14 @@ namespace SHADE
AssetQueue assetQueue; AssetQueue assetQueue;
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
SHSerializationHelper::FetchAssetsFromComponent<SHRenderable>((*it)[ComponentsNode], *entityVecIt, assetQueue); SHSerializationHelper::FetchAssetsFromComponent<SHRenderable>((*it)[ComponentsNode], createdEntities[(*it)[EIDNode].as<EntityID>()], assetQueue);
} }
LoadAssetsFromAssetQueue(assetQueue); LoadAssetsFromAssetQueue(assetQueue);
//Initialize Entity //Initialize Entity
entityVecIt = createdEntities.begin(); entityVecIt = createdEntities.begin();
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
InitializeEntity(*it, *entityVecIt++); InitializeEntity(*it, createdEntities[(*it)[EIDNode].as<EntityID>()]);
} }
return assetData->name; return assetData->name;
@ -160,9 +161,9 @@ namespace SHADE
return std::string(out.c_str()); return std::string(out.c_str());
} }
void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path) //void SHSerialization::SerializeEntityToFile(std::filesystem::path const& path)
{ //{
} //}
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid) static void AddComponentToComponentNode(YAML::Node& componentsNode, EntityID const& eid)
@ -218,13 +219,13 @@ namespace SHADE
return node; return node;
} }
EntityID SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept SHSerialization::CreatedEntitiesList SHSerialization::DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID) noexcept
{ {
if (data.empty()) if (data.empty())
return MAX_EID; return {};
YAML::Node entities = YAML::Load(data.c_str()); YAML::Node entities = YAML::Load(data.c_str());
EntityID eid{ MAX_EID }; EntityID eid{ MAX_EID };
std::vector<EntityID> createdEntities; CreatedEntitiesList createdEntities{};
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
eid = DeserializeEntity(it, *it, createdEntities, parentEID); eid = DeserializeEntity(it, *it, createdEntities, parentEID);
@ -232,14 +233,14 @@ namespace SHADE
if (createdEntities.empty()) if (createdEntities.empty())
{ {
SHLOG_ERROR("Failed to create entities from deserializaiton") SHLOG_ERROR("Failed to create entities from deserializaiton")
return MAX_EID; return createdEntities;
} }
auto entityVecIt = createdEntities.begin(); //auto entityVecIt = createdEntities.begin();
for (auto it = entities.begin(); it != entities.end(); ++it) for (auto it = entities.begin(); it != entities.end(); ++it)
{ {
InitializeEntity(*it, *entityVecIt++); InitializeEntity(*it, createdEntities[(*it)[EIDNode].as<EntityID>()]);
} }
return eid; return createdEntities;
} }
template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true> template<typename ComponentType, std::enable_if_t<std::is_base_of_v<SHComponent, ComponentType>, bool> = true>
@ -290,6 +291,41 @@ namespace SHADE
SHResourceManager::FinaliseChanges(); SHResourceManager::FinaliseChanges();
} }
void ResolveSerializedEntityID(YAML::Emitter& out, YAML::iterator& it, YAML::Node const& entityNode, SHSerialization::CreatedEntitiesList const& createdEntities)
{
EntityID eid = entityNode[EIDNode].as<EntityID>();
YAML::Node resolvedNode = entityNode;
resolvedNode[EIDNode] = createdEntities.at(eid);
out << resolvedNode;
if (entityNode[NumberOfChildrenNode])
{
if (const int numOfChildren = entityNode[NumberOfChildrenNode].as<int>(); numOfChildren > 0)
{
++it;
for (int i = 0; i < numOfChildren; ++i)
{
ResolveSerializedEntityID(out, it, (*it), createdEntities);
//DeserializeEntity(it, (*it), createdEntities, eid);
if ((i + 1) < numOfChildren)
++it;
}
}
}
}
std::string SHSerialization::ResolveSerializedEntityIndices(std::string serializedEntityData, CreatedEntitiesList const& createdEntities) noexcept
{
YAML::Node entities = YAML::Load(serializedEntityData);
YAML::Emitter out;
out << YAML::BeginSeq;
for (auto it = entities.begin(); it != entities.end(); ++it)
{
ResolveSerializedEntityID(out, it, (*it), createdEntities);
}
out << YAML::EndSeq;
return out.c_str();
}
void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid) void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid)
{ {
auto const componentsNode = entityNode[ComponentsNode]; auto const componentsNode = entityNode[ComponentsNode];

View File

@ -2,7 +2,6 @@
#include "SH_API.h" #include "SH_API.h"
#include <string> #include <string>
#include <filesystem>
#include "ECS_Base/SHECSMacros.h" #include "ECS_Base/SHECSMacros.h"
@ -26,8 +25,12 @@ namespace SHADE
constexpr const char* NumberOfChildrenNode = "NumberOfChildren"; constexpr const char* NumberOfChildrenNode = "NumberOfChildren";
constexpr const char* ScriptsNode = "Scripts"; constexpr const char* ScriptsNode = "Scripts";
struct SH_API SHSerialization class SH_API SHSerialization
{ {
public:
//Original EID : New EID
using CreatedEntitiesList = std::unordered_map<EntityID, EntityID>;
static bool SerializeSceneToFile(AssetID const& sceneAssetID); static bool SerializeSceneToFile(AssetID const& sceneAssetID);
static std::string SerializeSceneToString(); static std::string SerializeSceneToString();
static void SerializeSceneToEmitter(YAML::Emitter& out); static void SerializeSceneToEmitter(YAML::Emitter& out);
@ -38,15 +41,18 @@ namespace SHADE
static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out); static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out);
static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept; static std::string SerializeEntitiesToString(std::vector<EntityID> const& entities) noexcept;
static void SerializeEntityToFile(std::filesystem::path const& path); //static void SerializeEntityToFile(std::filesystem::path const& path);
static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode); static YAML::Node SerializeEntityToNode(SHSceneNode* sceneNode);
static EntityID DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept; static CreatedEntitiesList DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept;
static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode); static std::vector<ComponentTypeID> GetComponentIDList(YAML::Node const& componentsNode);
static void LoadAssetsFromAssetQueue(std::unordered_map<AssetID, AssetType>& assetQueue); static void LoadAssetsFromAssetQueue(std::unordered_map<AssetID, AssetType>& assetQueue);
static std::string ResolveSerializedEntityIndices(std::string serializedEntityData, CreatedEntitiesList const& createdEntities) noexcept;
private: private:
//static void ResolveSerializedEntityID(YAML::Emitter& out, YAML::iterator& it, YAML::Node const& entityNode, CreatedEntitiesList const& createdEntities);
static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid); static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid);
static constexpr std::string_view NewSceneName = "New Scene"; static constexpr std::string_view NewSceneName = "New Scene";

View File

@ -110,7 +110,7 @@ namespace SHADE
/// <param name="c">Component to check.</param> /// <param name="c">Component to check.</param>
static operator bool(BaseComponent^ c); static operator bool(BaseComponent^ c);
protected: internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -193,7 +193,6 @@ namespace SHADE
/// </exception> /// </exception>
NativeComponent* GetNativeComponent(); NativeComponent* GetNativeComponent();
protected:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -79,7 +79,10 @@ namespace SHADE
if (SHEditorUI::Selectable(Convert::ToNative(type->Name))) if (SHEditorUI::Selectable(Convert::ToNative(type->Name)))
{ {
// Add the script // Add the script
ScriptStore::AddScriptViaName(entity, type->Name); Script^ script;
ScriptStore::AddScriptViaNameWithRef(entity, type->Name, script);
registerUndoScriptAddAction(entity, script);
break;
} }
} }
@ -120,7 +123,7 @@ namespace SHADE
SHEditorUI::Indent(); SHEditorUI::Indent();
{ {
// Right Click Menu // Right Click Menu
renderScriptContextMenu(entity, script); renderScriptContextMenu(entity, script, index);
// Go through all fields and output them // Go through all fields and output them
auto fields = ReflectionUtilities::GetInstanceFields(script); auto fields = ReflectionUtilities::GetInstanceFields(script);
@ -143,7 +146,7 @@ namespace SHADE
} }
else else
{ {
renderScriptContextMenu(entity, script); renderScriptContextMenu(entity, script, index);
} }
SHEditorUI::PopID(); SHEditorUI::PopID();
} }
@ -336,7 +339,7 @@ namespace SHADE
return false; return false;
} }
void Editor::renderScriptContextMenu(Entity entity, Script^ script) void Editor::renderScriptContextMenu(Entity entity, Script^ script, int scriptIndex)
{ {
// Right Click Menu // Right Click Menu
if (SHEditorUI::BeginPopupContextItem("scriptContextMenu")) if (SHEditorUI::BeginPopupContextItem("scriptContextMenu"))
@ -345,6 +348,7 @@ namespace SHADE
{ {
// Mark script for removal // Mark script for removal
ScriptStore::RemoveScript(entity, script); ScriptStore::RemoveScript(entity, script);
registerUndoScriptRemoveAction(entity, script, scriptIndex);
} }
SHEditorUI::EndPopup(); SHEditorUI::EndPopup();
} }
@ -392,6 +396,28 @@ namespace SHADE
SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCLICommand>())); SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCLICommand>()));
} }
void Editor::registerUndoScriptAddAction(EntityID id, Script^ script)
{
if (script == nullptr)
return;
actionStack.Add(gcnew ScriptAddCommand(id, script));
// Inform the C++ Undo-Redo stack
SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCLICommand>()));
}
void Editor::registerUndoScriptRemoveAction(EntityID id, Script^ script, int originalIndex)
{
if (script == nullptr)
return;
actionStack.Add(gcnew ScriptRemoveCommand(id, script, originalIndex));
// Inform the C++ Undo-Redo stack
SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCLICommand>()));
}
generic<typename Attribute> generic<typename Attribute>
Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field) Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field)
{ {

View File

@ -69,7 +69,7 @@ namespace SHADE
static UndoRedoStack actionStack; static UndoRedoStack actionStack;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions - Inspector Rendering */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Renders a single specified Script's inspector. /// Renders a single specified Script's inspector.
@ -170,25 +170,25 @@ namespace SHADE
/// <returns>True if the field is modified.</returns> /// <returns>True if the field is modified.</returns>
template<typename NativeType, typename ManagedType> template<typename NativeType, typename ManagedType>
static bool renderFieldEditorInternal(const std::string& fieldName, interior_ptr<ManagedType> managedValPtr, EditorFieldFunc<NativeType> fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib); static bool renderFieldEditorInternal(const std::string& fieldName, interior_ptr<ManagedType> managedValPtr, EditorFieldFunc<NativeType> fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib);
/// <summary> /// <summary>
/// Renders a context menu when right clicked for the scripts /// Renders a context menu when right clicked for the scripts
/// </summary> /// </summary>
/// <param name="entity">The Entity to render the Scripts of.</param> /// <param name="entity">The Entity to render the Scripts of.</param>
/// <param name="script">The Script to render the inspector for.</param> /// <param name="script">The Script to render the inspector for.</param>
static void renderScriptContextMenu(Entity entity, Script^ script); /// <param name="scriptIndex">Index at which the Script is stored.</param>
/// <summary> static void renderScriptContextMenu(Entity entity, Script^ script, int scriptIndex);
/// Adds changes to a variable as an undo-able/redo-able action on the Undo-Redo /*-----------------------------------------------------------------------------*/
/// stack. /* Helper Functions - Undo */
/// </summary> /*-----------------------------------------------------------------------------*/
/// <param name="object">The object that changes are applied to.</param>
/// <param name="field">The field that was changed.</param>
/// <param name="newData">New data to set.</param>
/// <param name="oldData">Data that was overriden.</param>
static void registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData); static void registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData);
static void registerUndoListChangeAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ newData, System::Object^ oldData); static void registerUndoListChangeAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ newData, System::Object^ oldData);
static void registerUndoListAddAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data); static void registerUndoListAddAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data);
static void registerUndoListRemoveAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data); static void registerUndoListRemoveAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data);
static void registerUndoScriptAddAction(EntityID id, Script^ script);
static void registerUndoScriptRemoveAction(EntityID id, Script^ script, int originalIndex);
/*-----------------------------------------------------------------------------*/
/* Helper Functions - Others */
/*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Checks if a specific field has the specified attribute /// Checks if a specific field has the specified attribute
/// </summary> /// </summary>

View File

@ -21,6 +21,7 @@ of DigiPen Institute of Technology is prohibited.
// Project Headers // Project Headers
#include "Utility/Debug.hxx" #include "Utility/Debug.hxx"
#include "Utility/Convert.hxx" #include "Utility/Convert.hxx"
#include "Scripts/ScriptStore.hxx"
namespace SHADE namespace SHADE
{ {
@ -34,7 +35,8 @@ namespace SHADE
bool UndoRedoStack::RedoActionPresent::get() bool UndoRedoStack::RedoActionPresent::get()
{ {
return latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1; const int REDO_ACTION_INDEX = latestActionIndex + 1;
return REDO_ACTION_INDEX >= 0 && REDO_ACTION_INDEX < commandStack->Count;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -69,8 +71,9 @@ namespace SHADE
{ {
if (!RedoActionPresent) if (!RedoActionPresent)
return; return;
ICommand^ cmd = commandStack[latestActionIndex]; const int REDO_ACTION_INDEX = latestActionIndex + 1;
ICommand^ cmd = commandStack[REDO_ACTION_INDEX];
cmd->Execute(); cmd->Execute();
++latestActionIndex; ++latestActionIndex;
} }
@ -180,7 +183,7 @@ namespace SHADE
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* ListElementAddCommand - ICommand Functions */ /* ListElementAddCommand - Constructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
ListElementAddCommand::ListElementAddCommand(System::Collections::IList^ list, int addIndex, System::Object^ data) ListElementAddCommand::ListElementAddCommand(System::Collections::IList^ list, int addIndex, System::Object^ data)
: list { list } : list { list }
@ -220,7 +223,7 @@ namespace SHADE
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* ListElementRemoveCommand - ICommand Functions */ /* ListElementRemoveCommand - Constructor */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
ListElementRemoveCommand::ListElementRemoveCommand(System::Collections::IList^ list, int removeIndex, System::Object^ data) ListElementRemoveCommand::ListElementRemoveCommand(System::Collections::IList^ list, int removeIndex, System::Object^ data)
: list { list } : list { list }
@ -258,4 +261,59 @@ namespace SHADE
// Not allowed // Not allowed
return false; return false;
} }
/*---------------------------------------------------------------------------------*/
/* ScriptAddCommand - Constructor */
/*---------------------------------------------------------------------------------*/
ScriptAddCommand::ScriptAddCommand(EntityID id, Script^ script)
: entity { id }
, addedScript { script }
{}
/*---------------------------------------------------------------------------------*/
/* ScriptAddCommand - ICommand Functions */
/*---------------------------------------------------------------------------------*/
bool ScriptAddCommand::Execute()
{
return ScriptStore::AddScript(entity, addedScript) != nullptr;
}
bool ScriptAddCommand::Unexceute()
{
return ScriptStore::RemoveScript(entity, addedScript);
}
bool ScriptAddCommand::Merge(ICommand^)
{
// Not allowed
return false;
}
/*---------------------------------------------------------------------------------*/
/* ScriptRemoveCommand - Constructor */
/*---------------------------------------------------------------------------------*/
ScriptRemoveCommand::ScriptRemoveCommand(EntityID id, Script^ script, int index)
: entity { id }
, removedScript { script }
, originalIndex { index }
{}
/*---------------------------------------------------------------------------------*/
/* ScriptRemoveCommand - ICommand Functions */
/*---------------------------------------------------------------------------------*/
bool ScriptRemoveCommand::Execute()
{
return ScriptStore::RemoveScript(entity, removedScript);
}
bool ScriptRemoveCommand::Unexceute()
{
return ScriptStore::AddScript(entity, removedScript, originalIndex) != nullptr;
}
bool ScriptRemoveCommand::Merge(ICommand^)
{
// Not allowed
return false;
}
} }

View File

@ -12,6 +12,7 @@ Reproduction or disclosure of this file or its contents without the prior writte
of DigiPen Institute of Technology is prohibited. of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/ *//*************************************************************************************/
#pragma once #pragma once
#include "Scripts/Script.hxx"
namespace SHADE namespace SHADE
{ {
@ -102,6 +103,35 @@ namespace SHADE
System::Object^ data; System::Object^ data;
}; };
private ref class ScriptAddCommand sealed : public ICommand
{
public:
ScriptAddCommand(EntityID id, Script^ script);
bool Execute() override;
bool Unexceute() override;
bool Merge(ICommand^ command) override;
private:
EntityID entity;
Script^ addedScript;
};
private ref class ScriptRemoveCommand sealed : public ICommand
{
public:
ScriptRemoveCommand(EntityID id, Script^ script, int index);
bool Execute() override;
bool Unexceute() override;
bool Merge(ICommand^ command) override;
private:
EntityID entity;
Script^ removedScript;
int originalIndex;
};
/// <summary> /// <summary>
/// Class that is able to store a stack of actions that can be done and redone. /// Class that is able to store a stack of actions that can be done and redone.
/// </summary> /// </summary>

View File

@ -21,7 +21,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Managed version of the generic Handle<void>. /// Managed version of the generic Handle<void>.
/// </summary> /// </summary>
public value struct GenericHandle private value struct GenericHandle
{ {
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -93,6 +93,11 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* "All-time" Lifecycle Functions */ /* "All-time" Lifecycle Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void Script::Initialize(GameObject newOwner)
{
owner = newOwner;
}
void Script::OnAttached() void Script::OnAttached()
{ {
SAFE_NATIVE_CALL_BEGIN SAFE_NATIVE_CALL_BEGIN
@ -198,9 +203,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Script::Script(GameObject gameObj) Script::Script()
: owner { gameObj } : OnGizmosDrawOverriden { false }
, OnGizmosDrawOverriden { false }
{} {}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -165,7 +165,7 @@ namespace SHADE
internal: internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Properties */ /* Fields */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// If true, the OnGizmosDraw function was overridden. /// If true, the OnGizmosDraw function was overridden.
@ -176,6 +176,10 @@ namespace SHADE
/* "All-Time" Lifecycle Functions */ /* "All-Time" Lifecycle Functions */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Used to initialize a Script with a GameObject.
/// </summary>
void Initialize(GameObject newOwner);
/// <summary>
/// Used to call onAttached(). This is called immediately when this script is /// Used to call onAttached(). This is called immediately when this script is
/// attached to a GameObject. /// attached to a GameObject.
/// </summary> /// </summary>
@ -272,13 +276,9 @@ namespace SHADE
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Constructor for Script to tie it to a specific GameObject. /// Default Constructor
/// Constructors of derived Scripts should call this Constructor.
/// </summary> /// </summary>
/// <param name="gameObj"> Script();
/// GameObject that this Script will be tied to.
/// </param>
Script(GameObject gameObj);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Virtual "All-Time" Lifecycle Functions */ /* Virtual "All-Time" Lifecycle Functions */

View File

@ -39,6 +39,19 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
generic<typename T> generic<typename T>
T ScriptStore::AddScript(Entity entity) T ScriptStore::AddScript(Entity entity)
{
// Create the script and add it in
Script^ script = safe_cast<Script^>(System::Activator::CreateInstance(T::typeid));
return safe_cast<T>(AddScript(entity, script));
}
Script^ ScriptStore::AddScript(Entity entity, Script^ script)
{
return AddScript(entity, script, System::Int32::MaxValue);
}
Script^ ScriptStore::AddScript(Entity entity, Script^ script, int index)
{ {
// Check if entity exists // Check if entity exists
if (!EntityUtils::IsValid(entity)) if (!EntityUtils::IsValid(entity))
@ -58,15 +71,22 @@ namespace SHADE
entityScriptList = scripts[entity]; entityScriptList = scripts[entity];
} }
// Create the script and add it in // Add the script in
array<Object^>^ params = gcnew array<Object^>{GameObject(entity)}; script->Initialize(GameObject(entity));
Script^ script = safe_cast<Script^>(System::Activator::CreateInstance(T::typeid, params)); entityScriptList->Insert(System::Math::Clamp(index, 0, entityScriptList->Count), script);
entityScriptList->Add(script); if (Application::IsPlaying)
awakeList.Add(script); {
startList.Add(script); script->Awake();
script->Start();
}
else
{
awakeList.Add(script);
startList.Add(script);
}
script->OnAttached(); script->OnAttached();
return safe_cast<T>(script); return script;
} }
bool ScriptStore::AddScriptViaName(Entity entity, System::String^ scriptName) bool ScriptStore::AddScriptViaName(Entity entity, System::String^ scriptName)
@ -111,6 +131,7 @@ namespace SHADE
std::ostringstream oss; std::ostringstream oss;
oss << "[ScriptStore] Failed to add Script named \"" << Convert::ToNative(scriptName) oss << "[ScriptStore] Failed to add Script named \"" << Convert::ToNative(scriptName)
<< "\" to Entity #" << entity << "! (" << Convert::ToNative(e->GetType()->Name) << ")"; << "\" to Entity #" << entity << "! (" << Convert::ToNative(e->GetType()->Name) << ")";
oss << Convert::ToNative(e->ToString());
Debug::LogError(oss.str()); Debug::LogError(oss.str());
return false; return false;
} }
@ -365,7 +386,10 @@ namespace SHADE
} }
} }
startList.Clear(); startList.Clear();
startList.AddRange(%inactiveStartList); for each (Script ^ script in startList)
{
startList.Add(script);
}
inactiveStartList.Clear(); inactiveStartList.Clear();
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
@ -374,9 +398,8 @@ namespace SHADE
{ {
SAFE_NATIVE_CALL_BEGIN SAFE_NATIVE_CALL_BEGIN
// Clear the queue // Clear the queue
while (disposalQueue.Count > 0) for each (Script^ script in disposalQueue)
{ {;
Script^ script = disposalQueue.Dequeue();
if (Application::IsPlaying) if (Application::IsPlaying)
{ {
script->OnDestroy(); script->OnDestroy();
@ -389,6 +412,7 @@ namespace SHADE
scripts.Remove(entity); scripts.Remove(entity);
} }
} }
disposalQueue.Clear();
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
} }
void ScriptStore::Exit() void ScriptStore::Exit()
@ -437,9 +461,10 @@ namespace SHADE
continue; continue;
// Update each script // Update each script
for each (Script^ script in entity.Value) ScriptList^ scripts = entity.Value;
for (int i = 0; i < scripts->Count; ++i)
{ {
script->FixedUpdate(); scripts[i]->FixedUpdate();
} }
} }
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
@ -454,9 +479,10 @@ namespace SHADE
continue; continue;
// Update each script // Update each script
for each (Script^ script in entity.Value) ScriptList^ scripts = entity.Value;
for (int i = 0; i < scripts->Count; ++i)
{ {
script->Update(); scripts[i]->Update();
} }
} }
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
@ -471,9 +497,10 @@ namespace SHADE
continue; continue;
// Update each script // Update each script
for each (Script^ script in entity.Value) ScriptList^ scripts = entity.Value;
for (int i = 0; i < scripts->Count; ++i)
{ {
script->LateUpdate(); scripts[i]->LateUpdate();
} }
} }
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
@ -489,9 +516,10 @@ namespace SHADE
continue; continue;
// Update each script // Update each script
for each (Script^ script in entity.Value) ScriptList^ scripts = entity.Value;
for (int i = 0; i < scripts->Count; ++i)
{ {
script->OnDrawGizmos(); scripts[i]->OnDrawGizmos();
} }
} }
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
@ -523,8 +551,9 @@ namespace SHADE
auto entityScripts = scripts[entity.first]; auto entityScripts = scripts[entity.first];
if (entityScripts->Count > 0) if (entityScripts->Count > 0)
{ {
for each (Script ^ script in entityScripts) for (int i = 0; i < entityScripts->Count; ++i)
{ {
Script^ script = entityScripts[i];
switch (collisionInfo.GetCollisionState()) switch (collisionInfo.GetCollisionState())
{ {
case SHCollisionInfo::State::ENTER: case SHCollisionInfo::State::ENTER:
@ -564,8 +593,9 @@ namespace SHADE
auto entityScripts = scripts[entity.first]; auto entityScripts = scripts[entity.first];
if (entityScripts->Count > 0) if (entityScripts->Count > 0)
{ {
for each (Script ^ script in entityScripts) for (int i = 0; i < entityScripts->Count; ++i)
{ {
Script^ script = entityScripts[i];
switch (triggerInfo.GetCollisionState()) switch (triggerInfo.GetCollisionState())
{ {
case SHCollisionInfo::State::ENTER: case SHCollisionInfo::State::ENTER:
@ -678,9 +708,9 @@ namespace SHADE
void ScriptStore::removeScript(Script^ script) void ScriptStore::removeScript(Script^ script)
{ {
// Prepare for disposal // Prepare for disposal
disposalQueue.Enqueue(script); disposalQueue.Add(script);
// Also remove it fromm awake and start queues if they were created but not initialised // Also remove it from awake and start queues if they were created but not initialised
awakeList.Remove(script); awakeList.Remove(script);
startList.Remove(script); startList.Remove(script);
script->OnDetached(); script->OnDetached();
@ -750,7 +780,8 @@ namespace SHADE
void ScriptStore::getGenericMethods() void ScriptStore::getGenericMethods()
{ {
addScriptMethod = ScriptStore::typeid->GetMethod("AddScript"); array<System::Type^>^ paramTypes = gcnew array<System::Type^>{ Entity::typeid };
addScriptMethod = ScriptStore::typeid->GetMethod("AddScript", paramTypes);
if (addScriptMethod == nullptr) if (addScriptMethod == nullptr)
{ {
Debug::LogError("[ScriptStore] Failed to get MethodInfo of \"AddScript<T>()\". Adding of scripts from native code will fail."); Debug::LogError("[ScriptStore] Failed to get MethodInfo of \"AddScript<T>()\". Adding of scripts from native code will fail.");

View File

@ -25,7 +25,7 @@ namespace SHADE
/// Responsible for managing all scripts attached to Entities as well as executing /// Responsible for managing all scripts attached to Entities as well as executing
/// all lifecycle functions of scripts. /// all lifecycle functions of scripts.
/// </summary> /// </summary>
public ref class ScriptStore abstract sealed private ref class ScriptStore abstract sealed
{ {
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -46,6 +46,27 @@ namespace SHADE
generic<typename T> where T : ref class, Script generic<typename T> where T : ref class, Script
static T AddScript(Entity entity); static T AddScript(Entity entity);
/// <summary> /// <summary>
/// Adds a specified pre-constructed Script to a specified Entity.
/// </summary>
/// <param name="entity">The entity to add a script to.</param>
/// <param name="script">The pre-constructed Script to add.</param>
/// <returns>Reference to the script added.</returns>
/// <exception cref="ArgumentException">
/// If the specified Entity is invalid.
/// </exception>
static Script^ AddScript(Entity entity, Script^ script);
/// <summary>
/// Adds a specified pre-constructed Script to a specified Entity.
/// </summary>
/// <param name="entity">The entity to add a script to.</param>
/// <param name="script">The pre-constructed Script to add.</param>
/// <param name="index">Location in the script list to add.</param>
/// <returns>Reference to the script added.</returns>
/// <exception cref="ArgumentException">
/// If the specified Entity is invalid.
/// </exception>
static Script^ AddScript(Entity entity, Script^ script, int index);
/// <summary>
/// Adds a Script to a specified Entity. /// Adds a Script to a specified Entity.
/// <br/> /// <br/>
/// This function is meant for consumption from native code. If you are writing /// This function is meant for consumption from native code. If you are writing
@ -281,16 +302,16 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
using ScriptList = System::Collections::Generic::List<Script^>; using ScriptList = System::Collections::Generic::List<Script^>;
using ScriptDictionary = System::Collections::Generic::Dictionary<Entity, ScriptList^>; using ScriptDictionary = System::Collections::Generic::Dictionary<Entity, ScriptList^>;
using ScriptQueue = System::Collections::Generic::Queue<Script^>; using ScriptSet = System::Collections::Generic::HashSet<Script^>;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Static Data Members */ /* Static Data Members */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
static ScriptDictionary scripts; static ScriptDictionary scripts;
static ScriptList awakeList; static ScriptSet awakeList;
static ScriptList startList; static ScriptSet startList;
static ScriptList inactiveStartList; static ScriptSet inactiveStartList;
static ScriptQueue disposalQueue; static ScriptSet disposalQueue;
static System::Collections::Generic::IEnumerable<System::Type^>^ scriptTypeList; static System::Collections::Generic::IEnumerable<System::Type^>^ scriptTypeList;
static System::Reflection::MethodInfo^ addScriptMethod; static System::Reflection::MethodInfo^ addScriptMethod;

View File

@ -28,7 +28,6 @@ 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)
{ {
Debug::Log(FieldType::typeid->Name);
return varInsertYamlInternal<FieldType>(fieldInfo->GetValue(object), fieldNode); return varInsertYamlInternal<FieldType>(fieldInfo->GetValue(object), fieldNode);
} }
template<typename FieldType> template<typename FieldType>
@ -123,16 +122,6 @@ namespace SHADE
return true; return true;
} }
} }
else if constexpr (std::is_same_v<FieldType, System::Collections::IList>)
{
if (ReflectionUtilities::FieldIsList(fieldInfo))
{
System::Collections::IList^ iList = safe_cast<System::Collections::IList^>(object);
object = gcnew
if (node.IsSequence() )
}
}
else else
{ {
if (object->GetType() == FieldType::typeid) if (object->GetType() == FieldType::typeid)