From 7a51ac2891d36b6debf29545b3bbd00e3967f0a3 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 14 Feb 2026 23:25:06 +0100 Subject: [PATCH 01/12] Rename input text labels for input and output pins --- Mods/Editor/Src/Components/EntityProperties.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 2e85a371..c1ebffc4 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -416,7 +416,7 @@ void Editor::DrawEntityProperties() { ImGui::SameLine(0, 5); if (ImGui::InputText( - "In", s_InputPinInput, IM_ARRAYSIZE(s_InputPinInput), ImGuiInputTextFlags_EnterReturnsTrue + "Input Pin", s_InputPinInput, IM_ARRAYSIZE(s_InputPinInput), ImGuiInputTextFlags_EnterReturnsTrue )) { OnSignalEntityPin(s_SelectedEntity, s_InputPinInput, false); s_InputPinInput[0] = '\0'; @@ -433,7 +433,7 @@ void Editor::DrawEntityProperties() { ImGui::SameLine(0, 5); if (ImGui::InputText( - "Out", s_OutputPinInput, IM_ARRAYSIZE(s_OutputPinInput), ImGuiInputTextFlags_EnterReturnsTrue + "Output Pin", s_OutputPinInput, IM_ARRAYSIZE(s_OutputPinInput), ImGuiInputTextFlags_EnterReturnsTrue )) { OnSignalEntityPin(s_SelectedEntity, s_OutputPinInput, true); s_OutputPinInput[0] = '\0'; From 75ca495beb9de7a492d994366fdf3e7ac08e0ad7 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 14 Feb 2026 23:26:27 +0100 Subject: [PATCH 02/12] Rename s_InputPinInput to s_InputPinName and s_OutputPinInput to s_OutputPinName --- .../Src/Components/EntityProperties.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index c1ebffc4..2b32848a 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -406,37 +406,37 @@ void Editor::DrawEntityProperties() { ImGui::Separator(); - static char s_InputPinInput[1024] = {}; + static char s_InputPinName[1024] = {}; if (ImGui::Button(ICON_MD_BOLT "##fireInputPin")) { - OnSignalEntityPin(s_SelectedEntity, s_InputPinInput, false); - s_InputPinInput[0] = '\0'; + OnSignalEntityPin(s_SelectedEntity, s_InputPinName, false); + s_InputPinName[0] = '\0'; } ImGui::SameLine(0, 5); if (ImGui::InputText( - "Input Pin", 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'; + OnSignalEntityPin(s_SelectedEntity, s_InputPinName, false); + s_InputPinName[0] = '\0'; } - static char s_OutputPinInput[1024] = {}; + static char s_OutputPinName[1024] = {}; if (ImGui::Button(ICON_MD_BOLT "##fireOutputPin")) { - OnSignalEntityPin(s_SelectedEntity, s_OutputPinInput, true); - s_OutputPinInput[0] = '\0'; + OnSignalEntityPin(s_SelectedEntity, s_OutputPinName, true); + s_OutputPinName[0] = '\0'; } ImGui::SameLine(0, 5); if (ImGui::InputText( - "Output Pin", 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'; + OnSignalEntityPin(s_SelectedEntity, s_OutputPinName, true); + s_OutputPinName[0] = '\0'; } ImGui::Separator(); From 440bfa0762862974a9b7fd2b541e37bc508a327b Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 14 Feb 2026 23:40:04 +0100 Subject: [PATCH 03/12] Add support for passing data when triggering entity pins --- .../Src/Components/EntityProperties.cpp | 378 +++++++++++++++++- Mods/Editor/Src/Editor.h | 22 +- 2 files changed, 394 insertions(+), 6 deletions(-) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 2b32848a..44483789 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(); @@ -407,10 +411,27 @@ void Editor::DrawEntityProperties() { ImGui::Separator(); static char s_InputPinName[1024] = {}; + static char s_InputPinTypeName[2048] = {}; if (ImGui::Button(ICON_MD_BOLT "##fireInputPin")) { - OnSignalEntityPin(s_SelectedEntity, s_InputPinName, false); + 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); @@ -418,16 +439,105 @@ void Editor::DrawEntityProperties() { if (ImGui::InputText( "Input Pin", s_InputPinName, IM_ARRAYSIZE(s_InputPinName), ImGuiInputTextFlags_EnterReturnsTrue )) { - OnSignalEntityPin(s_SelectedEntity, s_InputPinName, false); + 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::Text("Data"); + + ImGui::Spacing(); + + 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 + ); + + memset(m_InputPinData, 0, s_TypeSize); + }, + [](auto& p_Pair) -> STypeID* { + return p_Pair.second; + } + ); + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Value"); + ImGui::SameLine(); + + if (s_InputPinTypeName[0] == '\0') { + static char s_EmptyBuffer[1] = {}; + + ImGui::BeginDisabled(); + + ImGui::InputText( + "##InputPinValue", + s_EmptyBuffer, + sizeof(s_EmptyBuffer) + ); + + 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_OutputPinName, true); + 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); @@ -435,8 +545,81 @@ void Editor::DrawEntityProperties() { if (ImGui::InputText( "Output Pin", s_OutputPinName, IM_ARRAYSIZE(s_OutputPinName), ImGuiInputTextFlags_EnterReturnsTrue )) { - OnSignalEntityPin(s_SelectedEntity, s_OutputPinName, true); + 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::Text("Data"); + + ImGui::Spacing(); + + 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 + ); + + memset(m_OutputPinData, 0, s_TypeSize); + }, + [](auto& p_Pair) -> STypeID* { + return p_Pair.second; + } + ); + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Value"); + 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 +837,190 @@ 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.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) From 58c49bac037a5143f8766d22f1558da975759f1b Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 14 Feb 2026 23:42:12 +0100 Subject: [PATCH 04/12] Register types for entity pin data --- Mods/Editor/Src/Editor.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Mods/Editor/Src/Editor.cpp b/Mods/Editor/Src/Editor.cpp index 62382776..1a369244 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) { From 14a4a1c6cdd69ec67f30d79add8a3409466c6e4e Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 14 Feb 2026 23:43:24 +0100 Subject: [PATCH 05/12] Update OnSignalEntityPin to forward pin data --- Mods/Editor/Src/Properties/Common.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) 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( From 3a6f8f903eba9cd8633bf0edf329cf89ef26f261 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 14 Feb 2026 23:44:57 +0100 Subject: [PATCH 06/12] Clear input and output pin type IDs and data on scene clear --- Mods/Editor/Src/Editor.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Mods/Editor/Src/Editor.cpp b/Mods/Editor/Src/Editor.cpp index 1a369244..6bcc3cd2 100644 --- a/Mods/Editor/Src/Editor.cpp +++ b/Mods/Editor/Src/Editor.cpp @@ -1065,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() }; } From c2e808b1889069637f0e8e5961ab23fc914e1abf Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 14 Feb 2026 23:56:56 +0100 Subject: [PATCH 07/12] Add non-templated QueryInterface overload to ZEntityRef --- ZHMModSDK/Include/Glacier/ZEntity.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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(); From 503906e16d99d73db38e4669974918fd03270f2f Mon Sep 17 00:00:00 2001 From: Pavle Date: Sun, 15 Feb 2026 09:46:37 +0100 Subject: [PATCH 08/12] Initialize SMatrix43 input and output pin data using default constructor --- .../Editor/Src/Components/EntityProperties.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 44483789..31ba3104 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -488,7 +488,14 @@ void Editor::DrawEntityProperties() { s_TypeSize, s_TypeAlignment ); - memset(m_InputPinData, 0, s_TypeSize); + 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; @@ -594,7 +601,14 @@ void Editor::DrawEntityProperties() { s_TypeSize, s_TypeAlignment ); - memset(m_OutputPinData, 0, s_TypeSize); + 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; From 16da0a457b4c286963878ab0d5c4f083e63411b2 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sun, 15 Feb 2026 09:50:38 +0100 Subject: [PATCH 09/12] Skip SameLine for SMatrix43 input and output pin values --- Mods/Editor/Src/Components/EntityProperties.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 31ba3104..4d3d8054 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -504,7 +504,10 @@ void Editor::DrawEntityProperties() { ImGui::AlignTextToFramePadding(); ImGui::Text("Value"); - ImGui::SameLine(); + + if (std::string(s_InputPinTypeName) != "SMatrix43") { + ImGui::SameLine(); + } if (s_InputPinTypeName[0] == '\0') { static char s_EmptyBuffer[1] = {}; @@ -617,7 +620,10 @@ void Editor::DrawEntityProperties() { ImGui::AlignTextToFramePadding(); ImGui::Text("Value"); - ImGui::SameLine(); + + if (std::string(s_InputPinTypeName) != "SMatrix43") { + ImGui::SameLine(); + } if (s_OutputPinTypeName[0] == '\0') { static char s_EmptyBuffer[1] = {}; From 9997c782dba7d5aed80e1e905914033803d2a2f1 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sun, 15 Feb 2026 12:22:32 +0100 Subject: [PATCH 10/12] Remove "Data" labels and spacing, and add space after "Type" label --- Mods/Editor/Src/Components/EntityProperties.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 4d3d8054..3b9585ef 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -459,10 +459,6 @@ void Editor::DrawEntityProperties() { } } - ImGui::Text("Data"); - - ImGui::Spacing(); - ImGui::AlignTextToFramePadding(); ImGui::Text("Type"); ImGui::SameLine(); @@ -575,12 +571,8 @@ void Editor::DrawEntityProperties() { } } - ImGui::Text("Data"); - - ImGui::Spacing(); - ImGui::AlignTextToFramePadding(); - ImGui::Text("Type"); + ImGui::Text("Type "); ImGui::SameLine(); Util::ImGuiUtils::InputWithAutocomplete( From d4bd98cb15ed13ff1ef9747851918fff35f1f9b0 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sun, 15 Feb 2026 12:24:53 +0100 Subject: [PATCH 11/12] Add missing space after "Type" label --- Mods/Editor/Src/Components/EntityProperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 3b9585ef..5db6edcb 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -460,7 +460,7 @@ void Editor::DrawEntityProperties() { } ImGui::AlignTextToFramePadding(); - ImGui::Text("Type"); + ImGui::Text("Type "); ImGui::SameLine(); Util::ImGuiUtils::InputWithAutocomplete( From f4321868bc2fa94bea91df0a7ab8b5adb99eb178 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sun, 15 Feb 2026 13:05:57 +0100 Subject: [PATCH 12/12] Add empty line before m_pInterfaceRef assignment --- Mods/Editor/Src/Components/EntityProperties.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Mods/Editor/Src/Components/EntityProperties.cpp b/Mods/Editor/Src/Components/EntityProperties.cpp index 5db6edcb..b3287597 100644 --- a/Mods/Editor/Src/Components/EntityProperties.cpp +++ b/Mods/Editor/Src/Components/EntityProperties.cpp @@ -1006,6 +1006,7 @@ void Editor::DrawEntityPinValue(const std::string& p_Id, const std::string& p_Ty 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; }