Add set box brush name command and update scene document migration
This commit is contained in:
46
src/commands/set-box-brush-name-command.ts
Normal file
46
src/commands/set-box-brush-name-command.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { createOpaqueId } from "../core/ids";
|
||||||
|
import { normalizeBrushName } from "../document/brushes";
|
||||||
|
|
||||||
|
import { getBoxBrushOrThrow, replaceBrush } from "./brush-command-helpers";
|
||||||
|
import type { EditorCommand } from "./command";
|
||||||
|
|
||||||
|
interface SetBoxBrushNameCommandOptions {
|
||||||
|
brushId: string;
|
||||||
|
name: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSetBoxBrushNameCommand(options: SetBoxBrushNameCommandOptions): EditorCommand {
|
||||||
|
const normalizedName = normalizeBrushName(options.name);
|
||||||
|
let previousName: string | undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: createOpaqueId("command"),
|
||||||
|
label: normalizedName === undefined ? "Clear box brush name" : `Rename box brush to ${normalizedName}`,
|
||||||
|
execute(context) {
|
||||||
|
const currentDocument = context.getDocument();
|
||||||
|
const brush = getBoxBrushOrThrow(currentDocument, options.brushId);
|
||||||
|
|
||||||
|
if (previousName === undefined) {
|
||||||
|
previousName = brush.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.setDocument(
|
||||||
|
replaceBrush(currentDocument, {
|
||||||
|
...brush,
|
||||||
|
name: normalizedName
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
undo(context) {
|
||||||
|
const currentDocument = context.getDocument();
|
||||||
|
const brush = getBoxBrushOrThrow(currentDocument, options.brushId);
|
||||||
|
|
||||||
|
context.setDocument(
|
||||||
|
replaceBrush(currentDocument, {
|
||||||
|
...brush,
|
||||||
|
name: previousName
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
createDefaultFaceUvState,
|
createDefaultFaceUvState,
|
||||||
isBoxFaceId,
|
isBoxFaceId,
|
||||||
isFaceUvRotationQuarterTurns,
|
isFaceUvRotationQuarterTurns,
|
||||||
|
normalizeBrushName,
|
||||||
type BoxBrushFaces,
|
type BoxBrushFaces,
|
||||||
type BrushFace,
|
type BrushFace,
|
||||||
type FaceUvState
|
type FaceUvState
|
||||||
@@ -13,6 +14,7 @@ import {
|
|||||||
BOX_BRUSH_SCENE_DOCUMENT_VERSION,
|
BOX_BRUSH_SCENE_DOCUMENT_VERSION,
|
||||||
FACE_MATERIALS_SCENE_DOCUMENT_VERSION,
|
FACE_MATERIALS_SCENE_DOCUMENT_VERSION,
|
||||||
FOUNDATION_SCENE_DOCUMENT_VERSION,
|
FOUNDATION_SCENE_DOCUMENT_VERSION,
|
||||||
|
RUNNER_V1_SCENE_DOCUMENT_VERSION,
|
||||||
SCENE_DOCUMENT_VERSION,
|
SCENE_DOCUMENT_VERSION,
|
||||||
type SceneDocument,
|
type SceneDocument,
|
||||||
type WorldSettings
|
type WorldSettings
|
||||||
@@ -80,6 +82,10 @@ function expectOptionalString(value: unknown, label: string): string | undefined
|
|||||||
return expectString(value, label);
|
return expectString(value, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readOptionalBrushName(value: unknown, label: string): string | undefined {
|
||||||
|
return normalizeBrushName(expectOptionalString(value, label));
|
||||||
|
}
|
||||||
|
|
||||||
function expectEmptyCollection(value: unknown, label: string): Record<string, never> {
|
function expectEmptyCollection(value: unknown, label: string): Record<string, never> {
|
||||||
if (!isRecord(value)) {
|
if (!isRecord(value)) {
|
||||||
throw new Error(`${label} must be a record.`);
|
throw new Error(`${label} must be a record.`);
|
||||||
@@ -264,6 +270,7 @@ function readBrushes(
|
|||||||
|
|
||||||
brushes[brushId] = createBoxBrush({
|
brushes[brushId] = createBoxBrush({
|
||||||
id: expectString(brushValue.id, `brushes.${brushId}.id`),
|
id: expectString(brushValue.id, `brushes.${brushId}.id`),
|
||||||
|
name: readOptionalBrushName(brushValue.name, `brushes.${brushId}.name`),
|
||||||
center,
|
center,
|
||||||
size,
|
size,
|
||||||
faces: readBoxBrushFaces(brushValue.faces, `brushes.${brushId}.faces`, materials, allowMissingUvState),
|
faces: readBoxBrushFaces(brushValue.faces, `brushes.${brushId}.faces`, materials, allowMissingUvState),
|
||||||
@@ -428,6 +435,23 @@ export function migrateSceneDocument(source: unknown): SceneDocument {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (source.version === RUNNER_V1_SCENE_DOCUMENT_VERSION) {
|
||||||
|
const materials = readMaterialRegistry(source.materials, "materials");
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: SCENE_DOCUMENT_VERSION,
|
||||||
|
name: expectString(source.name, "name"),
|
||||||
|
world: readWorldSettings(source.world),
|
||||||
|
materials,
|
||||||
|
textures: expectEmptyCollection(source.textures, "textures"),
|
||||||
|
assets: expectEmptyCollection(source.assets, "assets"),
|
||||||
|
brushes: readBrushes(source.brushes, materials, false),
|
||||||
|
modelInstances: expectEmptyCollection(source.modelInstances, "modelInstances"),
|
||||||
|
entities: readEntities(source.entities),
|
||||||
|
interactionLinks: expectEmptyCollection(source.interactionLinks, "interactionLinks")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (source.version !== SCENE_DOCUMENT_VERSION) {
|
if (source.version !== SCENE_DOCUMENT_VERSION) {
|
||||||
throw new Error(`Unsupported scene document version: ${String(source.version)}.`);
|
throw new Error(`Unsupported scene document version: ${String(source.version)}.`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ export function validateSceneDocument(document: SceneDocument): SceneDocumentVal
|
|||||||
|
|
||||||
registerAuthoredId(brush.id, path, seenIds, diagnostics);
|
registerAuthoredId(brush.id, path, seenIds, diagnostics);
|
||||||
|
|
||||||
|
if (brush.name !== undefined && brush.name.trim().length === 0) {
|
||||||
|
diagnostics.push(createDiagnostic("error", "invalid-box-name", "Box brush names must be non-empty when authored.", `${path}.name`));
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFiniteVec3(brush.size) || !hasPositiveBoxSize(brush.size)) {
|
if (!isFiniteVec3(brush.size) || !hasPositiveBoxSize(brush.size)) {
|
||||||
diagnostics.push(
|
diagnostics.push(
|
||||||
createDiagnostic("error", "invalid-box-size", "Box brush sizes must remain finite and positive on every axis.", `${path}.size`)
|
createDiagnostic("error", "invalid-box-size", "Box brush sizes must remain finite and positive on every axis.", `${path}.size`)
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import type { Brush } from "./brushes";
|
|||||||
import type { EntityInstance } from "../entities/entity-instances";
|
import type { EntityInstance } from "../entities/entity-instances";
|
||||||
import { cloneMaterialRegistry, createStarterMaterialRegistry, type MaterialDef } from "../materials/starter-material-library";
|
import { cloneMaterialRegistry, createStarterMaterialRegistry, type MaterialDef } from "../materials/starter-material-library";
|
||||||
|
|
||||||
export const SCENE_DOCUMENT_VERSION = 4 as const;
|
export const SCENE_DOCUMENT_VERSION = 5 as const;
|
||||||
export const FOUNDATION_SCENE_DOCUMENT_VERSION = 1 as const;
|
export const FOUNDATION_SCENE_DOCUMENT_VERSION = 1 as const;
|
||||||
export const BOX_BRUSH_SCENE_DOCUMENT_VERSION = 2 as const;
|
export const BOX_BRUSH_SCENE_DOCUMENT_VERSION = 2 as const;
|
||||||
export const FACE_MATERIALS_SCENE_DOCUMENT_VERSION = 3 as const;
|
export const FACE_MATERIALS_SCENE_DOCUMENT_VERSION = 3 as const;
|
||||||
|
export const RUNNER_V1_SCENE_DOCUMENT_VERSION = 4 as const;
|
||||||
|
|
||||||
export interface WorldBackgroundSettings {
|
export interface WorldBackgroundSettings {
|
||||||
mode: "solid";
|
mode: "solid";
|
||||||
|
|||||||
Reference in New Issue
Block a user