GameObjects can now be marked as invalid #181

Merged
Pycorax merged 3 commits from SP3-6-c-scripting into main 2022-11-08 13:52:08 +08:00
7 changed files with 119 additions and 38 deletions

View File

@ -256,4 +256,7 @@
Color: {x: 1, y: 1, z: 1, w: 1} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 0.25 Strength: 0.25
Scripts: ~ Scripts:
- Type: PickAndThrow
throwForce: [100, 200, 100]
item: 1

View File

@ -288,7 +288,7 @@ namespace SHADE
return CHANGED; return CHANGED;
} }
bool SHEditorUI::InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered) bool SHEditorUI::InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered, bool alwaysNull)
{ {
ImGui::Text(label.c_str()); ImGui::Text(label.c_str());
if (isHovered) if (isHovered)
@ -296,7 +296,7 @@ namespace SHADE
ImGui::SameLine(); ImGui::SameLine();
SHEntity* entity = SHEntityManager::GetEntityByID(value); SHEntity* entity = SHEntityManager::GetEntityByID(value);
std::ostringstream oss; std::ostringstream oss;
if (entity) if (!alwaysNull && entity)
{ {
oss << value << ": " << entity->name; oss << value << ": " << entity->name;
} }
@ -314,6 +314,13 @@ namespace SHADE
SHDragDrop::EndTarget(); SHDragDrop::EndTarget();
} }
} }
ImGui::SameLine();
if (ImGui::Button("Clear"))
{
value = MAX_EID;
changed = true;
}
return changed; return changed;
} }

View File

@ -313,8 +313,12 @@ namespace SHADE
/// <param name="label">Label used to identify this widget.</param> /// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param> /// <param name="value">Reference to the variable to store the result.</param>
/// <param name="isHovered>If set, stores the hover state of this widget.</param> /// <param name="isHovered>If set, stores the hover state of this widget.</param>
/// <param name="alwaysNull>
/// If set, the field displayed will always be blank regardless of specified
/// GameObject.
/// </param>
/// <returns>True if the value was changed.</returns> /// <returns>True if the value was changed.</returns>
static bool InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered = nullptr); static bool InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered = nullptr, bool alwaysNull = false);
/// <summary> /// <summary>
/// Creates a combo box for enumeration input. /// Creates a combo box for enumeration input.
/// </summary> /// </summary>

View File

@ -290,9 +290,14 @@ namespace SHADE
{ {
GameObject gameObj = safe_cast<GameObject>(field->GetValue(object)); GameObject gameObj = safe_cast<GameObject>(field->GetValue(object));
uint32_t entityId = gameObj.GetEntity(); uint32_t entityId = gameObj.GetEntity();
if (SHEditorUI::InputGameObjectField(Convert::ToNative(field->Name), entityId, &isHovered)) if (SHEditorUI::InputGameObjectField(Convert::ToNative(field->Name), entityId, &isHovered, !gameObj))
{ {
GameObject newVal = GameObject(entityId); GameObject newVal = GameObject(entityId);
if (entityId != MAX_EID)
{
// Null GameObject set
newVal = GameObject(entityId);
}
field->SetValue(object, newVal); field->SetValue(object, newVal);
registerUndoAction(object, field, newVal, gameObj); registerUndoAction(object, field, newVal, gameObj);
} }

View File

@ -36,6 +36,8 @@ namespace SHADE
void GameObject::Destroy(GameObject obj) void GameObject::Destroy(GameObject obj)
{ {
if (!obj.valid)
throw gcnew System::NullReferenceException("Attempted to destroy a null GameObject.");
SHEntityManager::DestroyEntity(static_cast<EntityID>(obj.GetEntity())); SHEntityManager::DestroyEntity(static_cast<EntityID>(obj.GetEntity()));
} }
@ -56,15 +58,21 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
System::String^ GameObject::Name::get() System::String^ GameObject::Name::get()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return Convert::ToCLI(GetNativeEntity().name); return Convert::ToCLI(GetNativeEntity().name);
} }
bool GameObject::IsActiveSelf::get() bool GameObject::IsActiveSelf::get()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return GetNativeEntity().GetActive(); return GetNativeEntity().GetActive();
} }
bool GameObject::IsActiveInHierarchy::get() bool GameObject::IsActiveInHierarchy::get()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
auto node = SHSceneManager::GetCurrentSceneGraph().GetNode(GetEntity()); auto node = SHSceneManager::GetCurrentSceneGraph().GetNode(GetEntity());
if (!node) if (!node)
{ {
@ -75,10 +83,14 @@ namespace SHADE
} }
Entity GameObject::EntityId::get() Entity GameObject::EntityId::get()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return entity; return entity;
} }
GameObject^ GameObject::Parent::get() GameObject^ GameObject::Parent::get()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot(); const auto* ROOT = SCENE_GRAPH.GetRoot();
@ -91,6 +103,8 @@ namespace SHADE
} }
void GameObject::Parent::set(GameObject^ newParent) void GameObject::Parent::set(GameObject^ newParent)
{ {
if (!valid)
throw gcnew System::NullReferenceException();
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph(); const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
if (newParent == nullptr) if (newParent == nullptr)
@ -104,10 +118,14 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void GameObject::SetName(System::String^ name) void GameObject::SetName(System::String^ name)
{ {
if (!valid)
throw gcnew System::NullReferenceException();
GetNativeEntity().name = Convert::ToNative(name); GetNativeEntity().name = Convert::ToNative(name);
} }
void GameObject::SetActive(bool active) void GameObject::SetActive(bool active)
{ {
if (!valid)
throw gcnew System::NullReferenceException();
GetNativeEntity().SetActive(active); GetNativeEntity().SetActive(active);
} }
@ -117,30 +135,40 @@ namespace SHADE
generic <typename T> generic <typename T>
T GameObject::AddComponent() T GameObject::AddComponent()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::AddComponent<T>(entity); return ECS::AddComponent<T>(entity);
} }
generic <typename T> generic <typename T>
T GameObject::GetComponent() T GameObject::GetComponent()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::GetComponent<T>(entity); return ECS::GetComponent<T>(entity);
} }
generic <typename T> generic <typename T>
T GameObject::GetComponentInChildren() T GameObject::GetComponentInChildren()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::GetComponentInChildren<T>(entity); return ECS::GetComponentInChildren<T>(entity);
} }
generic <typename T> generic <typename T>
T GameObject::EnsureComponent() T GameObject::EnsureComponent()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ECS::EnsureComponent<T>(entity); return ECS::EnsureComponent<T>(entity);
} }
generic <typename T> generic <typename T>
void GameObject::RemoveComponent() void GameObject::RemoveComponent()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
ECS::RemoveComponent<T>(entity); ECS::RemoveComponent<T>(entity);
} }
@ -150,30 +178,40 @@ namespace SHADE
generic <typename T> generic <typename T>
T GameObject::AddScript() T GameObject::AddScript()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::AddScript<T>(entity); return ScriptStore::AddScript<T>(entity);
} }
generic <typename T> generic <typename T>
T GameObject::GetScript() T GameObject::GetScript()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::GetScript<T>(entity); return ScriptStore::GetScript<T>(entity);
} }
generic <typename T> generic <typename T>
T GameObject::GetScriptInChildren() T GameObject::GetScriptInChildren()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::GetScriptInChildren<T>(entity); return ScriptStore::GetScriptInChildren<T>(entity);
} }
generic <typename T> generic <typename T>
System::Collections::Generic::IEnumerable<T>^ GameObject::GetScripts() System::Collections::Generic::IEnumerable<T>^ GameObject::GetScripts()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
return ScriptStore::GetScripts<T>(entity); return ScriptStore::GetScripts<T>(entity);
} }
generic <typename T> generic <typename T>
void GameObject::RemoveScript() void GameObject::RemoveScript()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
ScriptStore::RemoveScript<T>(entity); ScriptStore::RemoveScript<T>(entity);
} }
@ -183,11 +221,13 @@ namespace SHADE
GameObject::GameObject(const SHEntity& entity) GameObject::GameObject(const SHEntity& entity)
: entity{ entity.GetEID() } : entity{ entity.GetEID() }
, children{ gcnew System::Collections::ArrayList } , children{ gcnew System::Collections::ArrayList }
, valid{ true }
{} {}
GameObject::GameObject(Entity entity) GameObject::GameObject(Entity entity)
: entity{ entity } : entity{ entity }
, children{ gcnew System::Collections::ArrayList } , children{ gcnew System::Collections::ArrayList }
, valid{ true }
{} {}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -195,6 +235,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
SHEntity& GameObject::GetNativeEntity() SHEntity& GameObject::GetNativeEntity()
{ {
if (!valid)
throw gcnew System::NullReferenceException();
SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity); SHEntity* nativeEntity = SHEntityManager::GetEntityByID(entity);
if (nativeEntity == nullptr) if (nativeEntity == nullptr)
throw gcnew System::InvalidOperationException("[GameObject] Unable to obtain native Entity for GameObject."); throw gcnew System::InvalidOperationException("[GameObject] Unable to obtain native Entity for GameObject.");
@ -202,12 +244,20 @@ namespace SHADE
return *nativeEntity; return *nativeEntity;
} }
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
GameObject::operator bool(GameObject gameObj)
{
return gameObj.valid;
}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* IEquatable */ /* IEquatable */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool GameObject::Equals(GameObject other) bool GameObject::Equals(GameObject other)
{ {
return entity == other.entity; return (!valid && !other.valid) || entity == other.entity;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/

View File

@ -29,8 +29,9 @@ namespace SHADE
/* Class Definitions */ /* Class Definitions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Lightweight object for an PlushieEngine Entity that allows for easy access /// Lightweight object for an Entity that allows for easy access to Component and
/// to Component and Script operations. /// Script operations.
/// Can be set to a invalid/null GameObject by default construction.
/// </summary> /// </summary>
public value class GameObject : public System::IEquatable<GameObject> public value class GameObject : public System::IEquatable<GameObject>
{ {
@ -247,12 +248,22 @@ namespace SHADE
/// <returns>Native Entity object that this GameObject represents.</returns> /// <returns>Native Entity object that this GameObject represents.</returns>
SHEntity& GetNativeEntity(); SHEntity& GetNativeEntity();
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a GameObject is valid.
/// </summary>
/// <param name="gameObj">GameObjects to check.</param>
static operator bool(GameObject gameObj);
private: private:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
Entity entity; Entity entity;
System::Collections::ArrayList^ children; System::Collections::ArrayList^ children;
bool valid;
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -171,7 +171,7 @@ namespace SHADE
else if (fieldInfo->FieldType == GameObject::typeid) else if (fieldInfo->FieldType == GameObject::typeid)
{ {
GameObject gameObj = safe_cast<GameObject>(fieldInfo->GetValue(object)); GameObject gameObj = safe_cast<GameObject>(fieldInfo->GetValue(object));
fieldNode = gameObj.GetEntity(); fieldNode = gameObj ? gameObj.GetEntity() : MAX_EID;
} }
else // Not any of the supported types else // Not any of the supported types
{ {
@ -250,7 +250,8 @@ namespace SHADE
} }
else if (fieldInfo->FieldType == GameObject::typeid) else if (fieldInfo->FieldType == GameObject::typeid)
{ {
fieldInfo->SetValue(object, GameObject(node.as<uint32_t>())); const uint32_t EID = node.as<uint32_t>();
fieldInfo->SetValue(object, EID == MAX_EID ? GameObject() : GameObject(EID));
} }
else // Not any of the supported types else // Not any of the supported types
{ {