fix(editor): preserve hierarchical map saves
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { SceneData } from "@/types/editor/editor";
|
||||
import { parseMapNodes } from "@/utils/map/mapNodeValidation";
|
||||
import { parseMapData } from "@/utils/map/mapNodeValidation";
|
||||
|
||||
const MAP_JSON_PATH = "/map.json";
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function createSceneDataFromFiles(
|
||||
}
|
||||
|
||||
const mapPayload: unknown = JSON.parse(await mapFile.text());
|
||||
const mapNodes = parseMapNodes(mapPayload);
|
||||
const { mapNodes, mapTree } = parseMapData(mapPayload);
|
||||
const models = new Map<string, string>();
|
||||
|
||||
for (const [path, file] of fileMap.entries()) {
|
||||
@@ -31,7 +31,7 @@ export async function createSceneDataFromFiles(
|
||||
}
|
||||
}
|
||||
|
||||
return { mapNodes, models };
|
||||
return { mapNodes, models, mapTree };
|
||||
}
|
||||
|
||||
function getProjectRelativePath(file: File): string {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { MapNode, SceneData } from "@/types/editor/editor";
|
||||
import { parseMapNodes } from "@/utils/map/mapNodeValidation";
|
||||
import type {
|
||||
HierarchicalMapNode,
|
||||
MapNode,
|
||||
SceneData,
|
||||
} from "@/types/editor/editor";
|
||||
import { parseMapData } from "@/utils/map/mapNodeValidation";
|
||||
|
||||
const MAP_JSON_PATH = "/map.json";
|
||||
const MODEL_FILE_NAMES = ["model.glb", "model.gltf"];
|
||||
@@ -21,8 +25,12 @@ export async function loadMapSceneData(): Promise<SceneData | null> {
|
||||
}
|
||||
|
||||
loadingPromise = loadMapSceneDataInternal();
|
||||
cachedSceneData = await loadingPromise;
|
||||
loadingPromise = null;
|
||||
|
||||
try {
|
||||
cachedSceneData = await loadingPromise;
|
||||
} finally {
|
||||
loadingPromise = null;
|
||||
}
|
||||
|
||||
return cachedSceneData;
|
||||
}
|
||||
@@ -45,9 +53,9 @@ async function loadMapSceneDataInternal(): Promise<SceneData | null> {
|
||||
}
|
||||
|
||||
const mapPayload: unknown = await response.json();
|
||||
const mapNodes = parseMapNodes(mapPayload);
|
||||
const { mapNodes, mapTree } = parseMapData(mapPayload);
|
||||
const deduplicatedNodes = deduplicateMapNodes(mapNodes);
|
||||
return createSceneData(deduplicatedNodes);
|
||||
return createSceneData(deduplicatedNodes, mapTree);
|
||||
}
|
||||
|
||||
function createPositionKey(node: MapNode): string {
|
||||
@@ -84,9 +92,12 @@ function deduplicateMapNodes(nodes: MapNode[]): MapNode[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function createSceneData(mapNodes: MapNode[]): Promise<SceneData> {
|
||||
async function createSceneData(
|
||||
mapNodes: MapNode[],
|
||||
mapTree: HierarchicalMapNode | HierarchicalMapNode[],
|
||||
): Promise<SceneData> {
|
||||
const models = await loadMapModelUrls(mapNodes);
|
||||
return { mapNodes, models };
|
||||
return { mapNodes, models, mapTree };
|
||||
}
|
||||
|
||||
async function loadMapModelUrls(
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import type { HierarchicalMapNode, MapNode } from "../../types/editor/editor";
|
||||
|
||||
export interface ParsedMapNodes {
|
||||
mapNodes: MapNode[];
|
||||
mapTree: HierarchicalMapNode | HierarchicalMapNode[];
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null;
|
||||
}
|
||||
@@ -46,15 +51,19 @@ function isHierarchicalMapNode(value: unknown): value is HierarchicalMapNode {
|
||||
);
|
||||
}
|
||||
|
||||
function flattenMapNode(node: HierarchicalMapNode): MapNode[] {
|
||||
function flattenMapNode(node: HierarchicalMapNode, path: number[]): MapNode[] {
|
||||
const mapNode: MapNode = {
|
||||
name: node.name,
|
||||
type: node.type,
|
||||
position: node.position,
|
||||
rotation: node.rotation,
|
||||
scale: node.scale,
|
||||
sourcePath: path,
|
||||
};
|
||||
const childNodes = node.children?.flatMap(flattenMapNode) ?? [];
|
||||
const childNodes =
|
||||
node.children?.flatMap((child, index) =>
|
||||
flattenMapNode(child, [...path, index]),
|
||||
) ?? [];
|
||||
|
||||
if (node.role === "group") {
|
||||
return childNodes;
|
||||
@@ -64,12 +73,22 @@ function flattenMapNode(node: HierarchicalMapNode): MapNode[] {
|
||||
}
|
||||
|
||||
export function parseMapNodes(value: unknown): MapNode[] {
|
||||
return parseMapData(value).mapNodes;
|
||||
}
|
||||
|
||||
export function parseMapData(value: unknown): ParsedMapNodes {
|
||||
if (Array.isArray(value) && value.every(isHierarchicalMapNode)) {
|
||||
return value.flatMap(flattenMapNode);
|
||||
return {
|
||||
mapNodes: value.flatMap((node, index) => flattenMapNode(node, [index])),
|
||||
mapTree: value,
|
||||
};
|
||||
}
|
||||
|
||||
if (isHierarchicalMapNode(value)) {
|
||||
return flattenMapNode(value);
|
||||
return {
|
||||
mapNodes: flattenMapNode(value, []),
|
||||
mapTree: value,
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error("Invalid map node data");
|
||||
|
||||
Reference in New Issue
Block a user