using System; using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Component.GUI; using KamiToolKit.Classes; namespace KamiToolKit.Nodes; public abstract unsafe class ComponentNode(NodeType nodeType) : NodeBase(nodeType) { public abstract CollisionNode CollisionNode { get; } public abstract AtkComponentBase* ComponentBase { get; } public abstract AtkUldComponentDataBase* DataBase { get; } } public abstract unsafe class ComponentNode : ComponentNode where T : unmanaged, ICreatable where TU : unmanaged { public sealed override CollisionNode CollisionNode { get; } public sealed override AtkComponentBase* ComponentBase => Node->Component; public sealed override AtkUldComponentDataBase* DataBase => Node->Component->UldManager.ComponentData; protected ComponentNode() : base(NodeType.Component) { Node->Component = (AtkComponentBase*) NativeMemoryHelper.Create(); Node->Component->UldManager.ComponentData = (AtkUldComponentDataBase*)NativeMemoryHelper.UiAlloc(); ComponentBase->Initialize(); CollisionNode = new CollisionNode { NodeId = 1, LinkedComponent = ComponentBase, NodeFlags = NodeFlags.Visible | NodeFlags.Enabled | NodeFlags.HasCollision | NodeFlags.RespondToMouse | NodeFlags.Focusable | NodeFlags.EmitsEvents | NodeFlags.Fill, }; CollisionNode.ResNode->ParentNode = ResNode; CollisionNode.ParentUldManager = &((AtkComponentBase*)Component)->UldManager; ChildNodes.Add(CollisionNode); ComponentBase->OwnerNode = Node; ComponentBase->ComponentFlags = 1; ref var uldManager = ref ComponentBase->UldManager; uldManager.Objects = (AtkUldObjectInfo*)NativeMemoryHelper.UiAlloc(); ref var objects = ref uldManager.Objects; uldManager.ObjectCount = 1; SetInternalComponentType(ComponentType.Base); objects->NodeList = (AtkResNode**)NativeMemoryHelper.Malloc(8); objects->NodeList[0] = CollisionNode; objects->NodeCount = 1; objects->Id = 1000; uldManager.InitializeResourceRendererManager(); uldManager.RootNode = CollisionNode; uldManager.UpdateDrawNodeList(); uldManager.ResourceFlags = AtkUldManagerResourceFlag.Initialized | AtkUldManagerResourceFlag.ArraysAllocated; uldManager.LoadedState = AtkLoadState.Loaded; } protected override void Dispose(bool disposing, bool isNativeDestructor) { if (disposing) { try { if (!isNativeDestructor) { Node->Component->Deinitialize(); Node->Component->Dtor(1); Node->Component = null; } } catch (Exception e) { Log.Exception(e); } finally { base.Dispose(disposing, isNativeDestructor); } } } public static implicit operator AtkEventListener*(ComponentNode node) => &node.ComponentBase->AtkEventListener; public static implicit operator T*(ComponentNode node) => node.Component; public static implicit operator TU*(ComponentNode node) => node.Data; protected void SetInternalComponentType(ComponentType type) { var componentInfo = (AtkUldComponentInfo*)ComponentBase->UldManager.Objects; componentInfo->ComponentType = type; } protected void InitializeComponentEvents() { ComponentBase->InitializeFromComponentData(DataBase); ComponentBase->Setup(); ComponentBase->SetEnabledState(true); } protected override void OnSizeChanged() { base.OnSizeChanged(); CollisionNode.Size = Size; ComponentBase->UldManager.RootNodeHeight = (ushort)Height; ComponentBase->UldManager.RootNodeWidth = (ushort)Width; } public virtual bool IsEnabled { get => NodeFlags.HasFlag(NodeFlags.Enabled); set => ComponentBase->SetEnabledState(value); } public override int ChildCount => ComponentBase->UldManager.NodeListCount; public T* Component => (T*)ComponentBase; public TU* Data => (TU*)DataBase; }