diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 2e85a371..b3287597 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -10,6 +10,10 @@ #include "Logging.h" #include "Glacier/ZPhysics.h" #include +#include "Util/ImGuiUtils.h" +#include "Glacier/SColorRGB.h" +#include "Glacier/SColorRGBA.h" +#include "Glacier/ZGameTime.h" void Editor::DrawEntityProperties() { auto s_ImgGuiIO = ImGui::GetIO(); @@ -406,37 +410,228 @@ void Editor::DrawEntityProperties() { ImGui::Separator(); - static char s_InputPinInput[1024] = {}; + static char s_InputPinName[1024] = {}; + static char s_InputPinTypeName[2048] = {}; if (ImGui::Button(ICON_MD_BOLT "##fireInputPin")) { - OnSignalEntityPin(s_SelectedEntity, s_InputPinInput, false); - s_InputPinInput[0] = '\0'; + ZObjectRef s_ObjectRef; + + if (m_InputPinData) { + s_ObjectRef.Assign(m_InputPinTypeID, m_InputPinData); + } + + OnSignalEntityPin(s_SelectedEntity, s_InputPinName, false, s_ObjectRef); + + s_InputPinName[0] = '\0'; + s_InputPinTypeName[0] = '\0'; + + m_InputPinTypeID = nullptr; + + if (m_InputPinData) { + (*Globals::MemoryManager)->m_pNormalAllocator->Free(m_InputPinData); + + m_InputPinData = nullptr; + } } ImGui::SameLine(0, 5); if (ImGui::InputText( - "In", s_InputPinInput, IM_ARRAYSIZE(s_InputPinInput), ImGuiInputTextFlags_EnterReturnsTrue + "Input Pin", s_InputPinName, IM_ARRAYSIZE(s_InputPinName), ImGuiInputTextFlags_EnterReturnsTrue )) { - OnSignalEntityPin(s_SelectedEntity, s_InputPinInput, false); - s_InputPinInput[0] = '\0'; + ZObjectRef s_ObjectRef; + + if (m_InputPinData) { + s_ObjectRef.Assign(m_InputPinTypeID, m_InputPinData); + } + + OnSignalEntityPin(s_SelectedEntity, s_InputPinName, false, s_ObjectRef); + + s_InputPinName[0] = '\0'; + s_InputPinTypeName[0] = '\0'; + + m_InputPinTypeID = nullptr; + + if (m_InputPinData) { + (*Globals::MemoryManager)->m_pNormalAllocator->Free(m_InputPinData); + + m_InputPinData = nullptr; + } + } + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Type "); + ImGui::SameLine(); + + Util::ImGuiUtils::InputWithAutocomplete( + "##InputPinTypeNamesPopup", + s_InputPinTypeName, + sizeof(s_InputPinTypeName), + m_PinDataTypes, + [](auto& p_Pair) -> const std::string& { + return p_Pair.first; + }, + [](auto& p_Pair) -> const std::string& { + return p_Pair.first; + }, + [&](const std::string&, const std::string& p_TypeName, STypeID* s_TypeID) { + const uint16_t s_TypeSize = s_TypeID->GetTypeInfo()->m_nTypeSize; + const uint16_t s_TypeAlignment = s_TypeID->GetTypeInfo()->m_nTypeAlignment; + + m_InputPinTypeID = s_TypeID; + + m_InputPinData = (*Globals::MemoryManager)->m_pNormalAllocator->AllocateAligned( + s_TypeSize, s_TypeAlignment + ); + + if (std::string(s_InputPinTypeName) == "SMatrix43") { + auto s_Value = static_cast(m_InputPinData); + + *s_Value = SMatrix43 {}; + } + else { + memset(m_InputPinData, 0, s_TypeSize); + } + }, + [](auto& p_Pair) -> STypeID* { + return p_Pair.second; + } + ); + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Value"); + + if (std::string(s_InputPinTypeName) != "SMatrix43") { + ImGui::SameLine(); } + if (s_InputPinTypeName[0] == '\0') { + static char s_EmptyBuffer[1] = {}; + + ImGui::BeginDisabled(); + + ImGui::InputText( + "##InputPinValue", + s_EmptyBuffer, + sizeof(s_EmptyBuffer) + ); - static char s_OutputPinInput[1024] = {}; + ImGui::EndDisabled(); + } + else { + DrawEntityPinValue("##InputPinValue", s_InputPinTypeName, m_InputPinData); + } + + static char s_OutputPinName[1024] = {}; + static char s_OutputPinTypeName[2048] = {}; if (ImGui::Button(ICON_MD_BOLT "##fireOutputPin")) { - OnSignalEntityPin(s_SelectedEntity, s_OutputPinInput, true); - s_OutputPinInput[0] = '\0'; + ZObjectRef s_ObjectRef; + + if (m_OutputPinData) { + s_ObjectRef.Assign(m_OutputPinTypeID, m_OutputPinData); + } + + OnSignalEntityPin(s_SelectedEntity, s_OutputPinName, true, s_ObjectRef); + + s_OutputPinName[0] = '\0'; + s_OutputPinTypeName[0] = '\0'; + + m_OutputPinTypeID = nullptr; + + if (m_OutputPinData) { + (*Globals::MemoryManager)->m_pNormalAllocator->Free(m_OutputPinData); + + m_OutputPinData = nullptr; + } } ImGui::SameLine(0, 5); if (ImGui::InputText( - "Out", s_OutputPinInput, IM_ARRAYSIZE(s_OutputPinInput), ImGuiInputTextFlags_EnterReturnsTrue + "Output Pin", s_OutputPinName, IM_ARRAYSIZE(s_OutputPinName), ImGuiInputTextFlags_EnterReturnsTrue )) { - OnSignalEntityPin(s_SelectedEntity, s_OutputPinInput, true); - s_OutputPinInput[0] = '\0'; + ZObjectRef s_ObjectRef; + + if (m_OutputPinData) { + s_ObjectRef.Assign(m_OutputPinTypeID, m_OutputPinData); + } + + OnSignalEntityPin(s_SelectedEntity, s_OutputPinName, true, s_ObjectRef); + + s_OutputPinName[0] = '\0'; + s_OutputPinTypeName[0] = '\0'; + + m_OutputPinTypeID = nullptr; + + if (m_OutputPinData) { + (*Globals::MemoryManager)->m_pNormalAllocator->Free(m_OutputPinData); + + m_OutputPinData = nullptr; + } + } + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Type "); + ImGui::SameLine(); + + Util::ImGuiUtils::InputWithAutocomplete( + "##OutputPinTypeNamesPopup", + s_OutputPinTypeName, + sizeof(s_OutputPinTypeName), + m_PinDataTypes, + [](auto& p_Pair) -> const std::string& { + return p_Pair.first; + }, + [](auto& p_Pair) -> const std::string& { + return p_Pair.first; + }, + [&](const std::string&, const std::string& p_TypeName, STypeID* s_TypeID) { + const uint16_t s_TypeSize = s_TypeID->GetTypeInfo()->m_nTypeSize; + const uint16_t s_TypeAlignment = s_TypeID->GetTypeInfo()->m_nTypeAlignment; + + m_OutputPinTypeID = s_TypeID; + + m_OutputPinData = (*Globals::MemoryManager)->m_pNormalAllocator->AllocateAligned( + s_TypeSize, s_TypeAlignment + ); + + if (std::string(s_InputPinTypeName) == "SMatrix43") { + auto s_Value = static_cast(m_InputPinData); + + *s_Value = SMatrix43 {}; + } + else { + memset(m_InputPinData, 0, s_TypeSize); + } + }, + [](auto& p_Pair) -> STypeID* { + return p_Pair.second; + } + ); + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Value"); + + if (std::string(s_InputPinTypeName) != "SMatrix43") { + ImGui::SameLine(); + } + + if (s_OutputPinTypeName[0] == '\0') { + static char s_EmptyBuffer[1] = {}; + + ImGui::BeginDisabled(); + + ImGui::InputText( + "##OuputPinValue", + s_EmptyBuffer, + sizeof(s_EmptyBuffer) + ); + + ImGui::EndDisabled(); + } + else { + DrawEntityPinValue("##OuputPinValue", s_OutputPinTypeName, m_OutputPinData); } ImGui::Separator(); @@ -654,3 +849,191 @@ bool Editor::DrawEntityPropertyValue( return s_IsChanged; } + +void Editor::DrawEntityPinValue(const std::string& p_Id, const std::string& p_TypeName, void* p_Data) { + if (p_TypeName == "bool") { + auto s_Value = static_cast(p_Data); + + ImGui::Checkbox(p_Id.c_str(), s_Value); + } + else if (p_TypeName == "uint8") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_U8, s_Value); + } + else if (p_TypeName == "int8") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_S8, s_Value); + } + else if (p_TypeName == "uint16") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_U16, s_Value); + } + else if (p_TypeName == "int16") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_S16, s_Value); + } + else if (p_TypeName == "uint32") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_U32, s_Value); + } + else if (p_TypeName == "int32") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_S32, s_Value); + } + else if (p_TypeName == "uint64") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_U64, s_Value); + } + else if (p_TypeName == "int64") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_S64, s_Value); + } + else if (p_TypeName == "float32") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_Float, s_Value, 0.1f); + } + else if (p_TypeName == "float64") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_Double, s_Value, 0.1f); + } + else if (p_TypeName == "SVector2") { + auto s_Value = static_cast(p_Data); + + ImGui::DragFloat2(p_Id.c_str(), &s_Value->x, 0.1f); + } + else if (p_TypeName == "SVector3") { + auto s_Value = static_cast(p_Data); + + ImGui::DragFloat3(p_Id.c_str(), &s_Value->x, 0.1f); + } + else if (p_TypeName == "SVector4") { + auto s_Value = static_cast(p_Data); + + ImGui::DragFloat4(p_Id.c_str(), &s_Value->x, 0.1f); + } + else if (p_TypeName == "SMatrix43") { + auto s_Value = static_cast(p_Data); + + if (m_UseQneTransforms) { + auto s_QneTransform = MatrixToQneTransform(*s_Value); + + if (ImGui::DragFloat3((p_Id + "p").c_str(), &s_QneTransform.Position.x, 0.1f)) { + const auto s_Matrix = QneTransformToMatrix(s_QneTransform); + *s_Value = s_Matrix.ToMatrix43(); + } + + if (ImGui::DragFloat3((p_Id + "r").c_str(), &s_QneTransform.Rotation.x, 0.1f)) { + const auto s_Matrix = QneTransformToMatrix(s_QneTransform); + *s_Value = s_Matrix.ToMatrix43(); + } + } + else { + ImGui::DragFloat3((p_Id + "x").c_str(), &s_Value->XAxis.x, 0.1f); + ImGui::DragFloat3((p_Id + "y").c_str(), &s_Value->YAxis.x, 0.1f); + ImGui::DragFloat3((p_Id + "z").c_str(), &s_Value->ZAxis.x, 0.1f); + ImGui::DragFloat3((p_Id + "t").c_str(), &s_Value->Trans.x, 0.1f); + } + } + else if (p_TypeName == "SColorRGB") { + auto s_Value = static_cast(p_Data); + + ImGui::ColorEdit3(p_Id.c_str(), &s_Value->r); + } + else if (p_TypeName == "SColorRGBA") { + auto s_Value = static_cast(p_Data); + + ImGui::ColorEdit4(p_Id.c_str(), &s_Value->r); + } + if (p_TypeName == "ZString") { + auto* s_String = static_cast(p_Data); + + static char s_StringBuffer[65536] = {}; + + if (ImGui::InputText(p_Id.c_str(), s_StringBuffer, sizeof(s_StringBuffer))) { + *s_String = ZString(s_StringBuffer); + } + } + else if (p_TypeName == "ZRuntimeResourceID") { + auto* s_RuntimeResourceID = static_cast(p_Data); + + static char s_StringBuffer[65536] = {}; + + if (ImGui::InputText(p_Id.c_str(), s_StringBuffer, sizeof(s_StringBuffer))) { + *s_RuntimeResourceID = ZRuntimeResourceID::FromString(s_StringBuffer); + } + } + else if (p_TypeName.starts_with("ZEntityRef")) { + auto s_EntityRef = reinterpret_cast(p_Data); + + static char s_StringBuffer[65536] = {}; + + if (ImGui::InputText(p_Id.c_str(), s_StringBuffer, sizeof(s_StringBuffer))) { + uint64 s_EntityId = std::strtoull(s_StringBuffer, nullptr, 16); + + std::shared_lock s_TreeLock(m_CachedEntityTreeMutex); + + for (const auto& s_Pair : m_CachedEntityTreeMap) { + if (s_Pair.first.GetEntity()->GetType()->m_nEntityID == s_EntityId) { + *s_EntityRef = s_Pair.first; + break; + } + } + } + } + else if (p_TypeName.starts_with("TEntityRef")) { + auto s_EntityRef = reinterpret_cast*>(p_Data); + + static char s_StringBuffer[65536] = {}; + + if (ImGui::InputText(p_Id.c_str(), s_StringBuffer, sizeof(s_StringBuffer))) { + uint64 s_EntityId = std::strtoull(s_StringBuffer, nullptr, 16); + + std::shared_lock s_TreeLock(m_CachedEntityTreeMutex); + + for (const auto& s_Pair : m_CachedEntityTreeMap) { + if (s_Pair.first.GetEntity()->GetType()->m_nEntityID == s_EntityId) { + s_EntityRef->m_entityRef = s_Pair.first; + + std::string s_TypeName = p_TypeName.substr(11, p_TypeName.find(">") - 11); + STypeID* s_TypeID = (*Globals::TypeRegistry)->GetTypeID(s_TypeName); + + s_EntityRef->m_pInterfaceRef = s_EntityRef->m_entityRef.QueryInterface(s_TypeID); + break; + } + } + } + } + else if (p_TypeName == "ZRepositoryID") { + auto s_RepositoryId = reinterpret_cast(p_Data); + + static char s_StringBuffer[65536] = {}; + + if (ImGui::InputText(p_Id.c_str(), s_StringBuffer, sizeof(s_StringBuffer))) { + *s_RepositoryId = ZString(s_StringBuffer); + } + } + else if (p_TypeName == "ZGuid") { + auto s_Guid = reinterpret_cast(p_Data); + + static char s_StringBuffer[65536] = {}; + + if (ImGui::InputText(p_Id.c_str(), s_StringBuffer, sizeof(s_StringBuffer))) { + *s_Guid = ZString(s_StringBuffer); + } + } + else if (p_TypeName == "ZGameTime") { + auto s_Value = static_cast(p_Data); + + ImGui::DragScalar(p_Id.c_str(), ImGuiDataType_S64, &s_Value->m_nTicks); + } +} \ No newline at end of file diff --git a/Mods/Editor/Src/Editor.cpp b/Mods/Editor/Src/Editor.cpp index 62382776..6bcc3cd2 100644 --- a/Mods/Editor/Src/Editor.cpp +++ b/Mods/Editor/Src/Editor.cpp @@ -268,6 +268,40 @@ void Editor::OnDepthDraw3D(IRenderer* p_Renderer) { void Editor::OnEngineInitialized() { const ZMemberDelegate s_Delegate(this, &Editor::OnFrameUpdate); Globals::GameLoopManager->RegisterFrameUpdate(s_Delegate, 1, EUpdateMode::eUpdateAlways); + + ZTypeRegistry* s_TypeRegistry = (*Globals::TypeRegistry); + + m_PinDataTypes.push_back(std::make_pair("bool", s_TypeRegistry->GetTypeID("bool"))); + m_PinDataTypes.push_back(std::make_pair("uint8", s_TypeRegistry->GetTypeID("uint8"))); + m_PinDataTypes.push_back(std::make_pair("int8", s_TypeRegistry->GetTypeID("int8"))); + m_PinDataTypes.push_back(std::make_pair("uint16", s_TypeRegistry->GetTypeID("uint16"))); + m_PinDataTypes.push_back(std::make_pair("int16", s_TypeRegistry->GetTypeID("int16"))); + m_PinDataTypes.push_back(std::make_pair("uint32", s_TypeRegistry->GetTypeID("uint32"))); + m_PinDataTypes.push_back(std::make_pair("int32", s_TypeRegistry->GetTypeID("int32"))); + m_PinDataTypes.push_back(std::make_pair("uint64", s_TypeRegistry->GetTypeID("uint64"))); + m_PinDataTypes.push_back(std::make_pair("int64", s_TypeRegistry->GetTypeID("int64"))); + m_PinDataTypes.push_back(std::make_pair("float32", s_TypeRegistry->GetTypeID("float32"))); + m_PinDataTypes.push_back(std::make_pair("float64", s_TypeRegistry->GetTypeID("float64"))); + m_PinDataTypes.push_back(std::make_pair("SVector2", s_TypeRegistry->GetTypeID("SVector2"))); + m_PinDataTypes.push_back(std::make_pair("SVector3", s_TypeRegistry->GetTypeID("SVector3"))); + m_PinDataTypes.push_back(std::make_pair("SVector4", s_TypeRegistry->GetTypeID("SVector4"))); + m_PinDataTypes.push_back(std::make_pair("SMatrix43", s_TypeRegistry->GetTypeID("SMatrix43"))); + m_PinDataTypes.push_back(std::make_pair("SColorRGB", s_TypeRegistry->GetTypeID("SColorRGB"))); + m_PinDataTypes.push_back(std::make_pair("SColorRGBA", s_TypeRegistry->GetTypeID("SColorRGBA"))); + m_PinDataTypes.push_back(std::make_pair("ZString", s_TypeRegistry->GetTypeID("ZString"))); + m_PinDataTypes.push_back(std::make_pair("ZRuntimeResourceID", s_TypeRegistry->GetTypeID("ZRuntimeResourceID"))); + m_PinDataTypes.push_back(std::make_pair("ZEntityRef", s_TypeRegistry->GetTypeID("ZEntityRef"))); + m_PinDataTypes.push_back(std::make_pair("ZRepositoryID", s_TypeRegistry->GetTypeID("ZRepositoryID"))); + m_PinDataTypes.push_back(std::make_pair("ZGuid", s_TypeRegistry->GetTypeID("ZGuid"))); + m_PinDataTypes.push_back(std::make_pair("ZGameTime", s_TypeRegistry->GetTypeID("ZGameTime"))); + + for (const auto& [s_TypeName, s_TypeID] : (*Globals::TypeRegistry)->m_types) { + if (s_TypeID->GetTypeInfo()->IsClass()) { + if (s_TypeName.StartsWith("TEntityRef<") || s_TypeName.StartsWith("TResourcePtr<")) { + m_PinDataTypes.push_back(std::make_pair(s_TypeName.c_str(), s_TypeRegistry->GetTypeID(s_TypeName))); + } + } + } } bool Editor::ImGuiCopyWidget(const std::string& p_Id) { @@ -1031,6 +1065,22 @@ DEFINE_PLUGIN_DETOUR(Editor, void, OnClearScene, ZEntitySceneContext* th, bool p m_SortedRoomEntities.clear(); + m_InputPinTypeID = nullptr; + + if (m_InputPinData) { + (*Globals::MemoryManager)->m_pNormalAllocator->Free(m_InputPinData); + + m_InputPinData = nullptr; + } + + m_OutputPinTypeID = nullptr; + + if (m_OutputPinData) { + (*Globals::MemoryManager)->m_pNormalAllocator->Free(m_OutputPinData); + + m_OutputPinData = nullptr; + } + return { HookAction::Continue() }; } diff --git a/Mods/Editor/Src/Editor.h b/Mods/Editor/Src/Editor.h index fc2bcd62..3ced669e 100644 --- a/Mods/Editor/Src/Editor.h +++ b/Mods/Editor/Src/Editor.h @@ -120,6 +120,8 @@ class Editor : public IPluginInterface { const IArrayType* p_ArrayType ); + void DrawEntityPinValue(const std::string& p_Id, const std::string& p_TypeName, void* p_Data); + void DrawLibrary(); void DrawSettings(bool p_HasFocus); @@ -153,8 +155,18 @@ class Editor : public IPluginInterface { void OnSetPropertyValue( ZEntityRef p_Entity, uint32_t p_PropertyId, const ZObjectRef& p_Value, std::optional p_ClientId ); - void OnSignalEntityPin(ZEntityRef p_Entity, const std::string& p_Pin, bool p_Output); - void OnSignalEntityPin(ZEntityRef p_Entity, uint32_t p_PinId, bool p_Output); + void OnSignalEntityPin( + ZEntityRef p_Entity, + const std::string& p_Pin, + bool p_Output, + const ZObjectRef& p_Data = ZObjectRef() + ); + void OnSignalEntityPin( + ZEntityRef p_Entity, + uint32_t p_PinId, + bool p_Output, + const ZObjectRef& p_Data = ZObjectRef() + ); void OnFrameUpdate(const SGameUpdateEvent& p_UpdateEvent); @@ -570,6 +582,12 @@ class Editor : public IPluginInterface { std::mutex m_TaskMutex; std::vector> m_TaskQueue; + + std::vector> m_PinDataTypes; + STypeID* m_InputPinTypeID = nullptr; + void* m_InputPinData = nullptr; + STypeID* m_OutputPinTypeID = nullptr; + void* m_OutputPinData = nullptr; }; DECLARE_ZHM_PLUGIN(Editor) diff --git a/Mods/Editor/Src/Properties/Common.cpp b/Mods/Editor/Src/Properties/Common.cpp index 109ba423..26a84603 100644 --- a/Mods/Editor/Src/Properties/Common.cpp +++ b/Mods/Editor/Src/Properties/Common.cpp @@ -20,17 +20,27 @@ void Editor::OnSetPropertyValue( m_Server.OnEntityPropertySet(p_Entity, p_PropertyId, std::move(p_ClientId)); } -void Editor::OnSignalEntityPin(ZEntityRef p_Entity, uint32_t p_PinId, bool p_Output) { +void Editor::OnSignalEntityPin( + ZEntityRef p_Entity, + uint32_t p_PinId, + bool p_Output, + const ZObjectRef& p_Data +) { if (p_Output) { - p_Entity.SignalOutputPin(p_PinId); + p_Entity.SignalOutputPin(p_PinId, p_Data); } else { - p_Entity.SignalInputPin(p_PinId); + p_Entity.SignalInputPin(p_PinId, p_Data); } } -void Editor::OnSignalEntityPin(ZEntityRef p_Entity, const std::string& p_Pin, bool p_Output) { - OnSignalEntityPin(p_Entity, Hash::Crc32(p_Pin.c_str(), p_Pin.size()), p_Output); +void Editor::OnSignalEntityPin( + ZEntityRef p_Entity, + const std::string& p_Pin, + bool p_Output, + const ZObjectRef& p_Data +) { + OnSignalEntityPin(p_Entity, Hash::Crc32(p_Pin.c_str(), p_Pin.size()), p_Output, p_Data); } void Editor::UnsupportedProperty( diff --git a/ZHMModSDK/Include/Glacier/ZEntity.h b/ZHMModSDK/Include/Glacier/ZEntity.h index e0ff0c64..ca7c3191 100644 --- a/ZHMModSDK/Include/Glacier/ZEntity.h +++ b/ZHMModSDK/Include/Glacier/ZEntity.h @@ -410,6 +410,21 @@ class ZEntityRef { return nullptr; } + void* QueryInterface(const STypeID* p_TypeID) const { + const auto s_Entity = GetEntity(); + + if (!s_Entity || !*Globals::TypeRegistry || !s_Entity->GetType()) + return nullptr; + + for (const auto& s_Interface : *s_Entity->GetType()->m_pInterfaceData) { + if (s_Interface.m_Type == p_TypeID) { + return reinterpret_cast(reinterpret_cast(m_pObj) + s_Interface.m_nInterfaceOffset); + } + } + + return nullptr; + } + template bool HasInterface() const { const auto s_Entity = GetEntity();