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,
|
||||
isBoxFaceId,
|
||||
isFaceUvRotationQuarterTurns,
|
||||
normalizeBrushName,
|
||||
type BoxBrushFaces,
|
||||
type BrushFace,
|
||||
type FaceUvState
|
||||
@@ -13,6 +14,7 @@ import {
|
||||
BOX_BRUSH_SCENE_DOCUMENT_VERSION,
|
||||
FACE_MATERIALS_SCENE_DOCUMENT_VERSION,
|
||||
FOUNDATION_SCENE_DOCUMENT_VERSION,
|
||||
RUNNER_V1_SCENE_DOCUMENT_VERSION,
|
||||
SCENE_DOCUMENT_VERSION,
|
||||
type SceneDocument,
|
||||
type WorldSettings
|
||||
@@ -80,6 +82,10 @@ function expectOptionalString(value: unknown, label: string): string | undefined
|
||||
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> {
|
||||
if (!isRecord(value)) {
|
||||
throw new Error(`${label} must be a record.`);
|
||||
@@ -264,6 +270,7 @@ function readBrushes(
|
||||
|
||||
brushes[brushId] = createBoxBrush({
|
||||
id: expectString(brushValue.id, `brushes.${brushId}.id`),
|
||||
name: readOptionalBrushName(brushValue.name, `brushes.${brushId}.name`),
|
||||
center,
|
||||
size,
|
||||
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) {
|
||||
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);
|
||||
|
||||
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)) {
|
||||
diagnostics.push(
|
||||
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 { 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 BOX_BRUSH_SCENE_DOCUMENT_VERSION = 2 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 {
|
||||
mode: "solid";
|
||||
|
||||
Reference in New Issue
Block a user