Files
tts-workshop/packages/extract/src/objects.ts
T
hypercross d8a698986a feat(extract): build containment tree and traverse all containers
Add buildTree to mirror how TTS nests objects, with a display label
(Nickname or class Name). Generalize traverseMod to descend into any
object with ContainedObjects, not just bags, and add Nickname to
TTSObject.
2026-08-08 12:19:39 +08:00

59 lines
1.5 KiB
TypeScript

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';