import type { TTSMod, TTSObject } from '@tts/shared'; import { markParent, traverseMod } from './traverse.js'; /** A node in the containment tree of a save. */ export interface ObjectTreeNode { object: TTSObject; /** Display label: `Nickname` when present, else the class `Name`. */ label: string; children: ObjectTreeNode[]; } /** * Build the containment tree of a save, mirroring how TTS nests objects. * Each node carries its object plus a display label and its children. */ export function buildTree(mod: TTSMod): ObjectTreeNode[] { for (const state of mod.ObjectStates) { markParent(state); } return mod.ObjectStates.map(nodeFrom); } function nodeFrom(o: TTSObject): ObjectTreeNode { return { object: o, label: o.Nickname || o.Name, children: (o.ContainedObjects ?? []).map(nodeFrom), }; } /** * Flatten all objects in a save into an array. * Ensures parent links are set before returning. */ export function flattenObjects(mod: TTSMod): TTSObject[] { for (const state of mod.ObjectStates) { markParent(state); } return [...traverseMod(mod)]; } /** * Filter objects by a predicate (name, GUID, type, etc.). */ export function filterObjects( mod: TTSMod, predicate: (o: TTSObject) => boolean, ): TTSObject[] { return flattenObjects(mod).filter(predicate); } /** * Find a single object by GUID. */ export function findObject(mod: TTSMod, guid: string): TTSObject | undefined { return flattenObjects(mod).find((o) => o.GUID === guid); } export { markParent, traverseMod } from './traverse.js';