using System;
using System.Linq;
using FFXIVClientStructs.FFXIV.Component.GUI;
using FFXIVClientStructs.Interop;
using KamiToolKit.Classes;
namespace KamiToolKit.Extensions;
public static unsafe class AtkUldManagerExtensions {
extension(ref AtkUldManager manager) {
private bool IsNodeInObjectList(AtkResNode* node) {
foreach (var objectNode in manager.ObjectNodeSpan) {
if (objectNode.Value == node) return true;
}
return false;
}
public bool IsNodeInDrawList(AtkResNode* node) {
foreach (var drawNode in manager.Nodes) {
if (drawNode.Value == node) return true;
}
return false;
}
///
/// Adds node and all children nodes to this UldManager's Object List
///
public void AddNodeToObjectList(NodeBase node) {
manager.AddNodeToObjectList(node.ResNode);
foreach (var child in NodeBase.GetLocalChildren(node)) {
manager.AddNodeToObjectList(child.ResNode);
}
manager.UpdateDrawNodeList();
}
public void AddNodeToObjectList(AtkResNode* newNode) {
if (newNode is null) return;
// If the node is already in the object list, skip.
if (manager.IsNodeInObjectList(newNode)) return;
var oldSize = manager.Objects->NodeCount;
var newSize = oldSize + 1;
var newBuffer = (AtkResNode**)NativeMemoryHelper.Malloc((ulong)(newSize * 8));
if (oldSize > 0) {
foreach (var index in Enumerable.Range(0, oldSize)) {
newBuffer[index] = manager.Objects->NodeList[index];
}
NativeMemoryHelper.Free(manager.Objects->NodeList, (ulong)(oldSize * 8));
}
newBuffer[newSize - 1] = newNode;
manager.Objects->NodeList = newBuffer;
manager.Objects->NodeCount = newSize;
}
///
/// Removes node and all children nodes from this UldManager's Object List
///
public void RemoveNodeFromObjectList(NodeBase node) {
manager.RemoveNodeFromObjectList(node.ResNode);
foreach (var child in NodeBase.GetLocalChildren(node)) {
manager.RemoveNodeFromObjectList(child.ResNode);
}
manager.UpdateDrawNodeList();
}
public void RemoveNodeFromObjectList(AtkResNode* node) {
if (node is null) return;
// If the node isn't in the object list, skip.
if (!manager.IsNodeInObjectList(node)) return;
var oldSize = manager.Objects->NodeCount;
var newSize = oldSize - 1;
var newBuffer = (AtkResNode**)NativeMemoryHelper.Malloc((ulong)(newSize * 8));
var newIndex = 0;
foreach (var index in Enumerable.Range(0, oldSize)) {
if (manager.Objects->NodeList[index] != node) {
newBuffer[newIndex] = manager.Objects->NodeList[index];
newIndex++;
}
}
NativeMemoryHelper.Free(manager.Objects->NodeList, (ulong)(oldSize * 8));
manager.Objects->NodeList = newBuffer;
manager.Objects->NodeCount = newSize;
}
public void PrintObjectList() {
Log.Debug("Beginning NodeList");
foreach (var index in Enumerable.Range(0, manager.Objects->NodeCount)) {
var nodePointer = manager.Objects->NodeList[index];
Log.Debug($"[{index}]: {(nint)nodePointer:X}");
}
}
public uint GetMaxNodeId() {
uint max = 1;
foreach (var child in manager.Nodes) {
if (child.Value is null) continue;
max = Math.Max(child.Value->NodeId, max);
}
return max;
}
public Span> ObjectNodeSpan
=> new(manager.Objects->NodeList, manager.Objects->NodeCount);
public T* SearchNodeById(uint nodeId) where T : unmanaged {
foreach (var node in manager.Nodes) {
if (node.Value is not null) {
if (node.Value->NodeId == nodeId)
return (T*) node.Value;
}
}
return null;
}
public AtkResNode* SearchNodeById(uint nodeId)
=> manager.SearchNodeById(nodeId);
}
}