This commit is contained in:
syuilo 2026-05-14 14:25:17 +09:00
commit 0b17663eeb
4 changed files with 36 additions and 13 deletions

View file

@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="controller.isReady.value && controller.isEditMode.value && controller.selected.value != null && selectedObjectDef != null && !controller.grabbing.value" :key="controller.selected.value.objectId" class="_panel" :class="$style.overlayObjectInfoPanel">
{{ selectedObjectDef.name }}
<XObjectCustomizeForm :addFileAttachment="addFileAttachment" :schema="selectedObjectDef.options.schema" :options="controller.selected.value.objectState.options" @update="(k, v) => controller.updateObjectOption(controller.selected.value.objectId, k, v, attachments)"></XObjectCustomizeForm>
<XObjectCustomizeForm :addFileAttachment="addFileAttachment" :schema="selectedObjectDef.options.schema" :options="controller.selected.value.objectState.options" @update="(k, v) => updateObjectOption(k, v)"></XObjectCustomizeForm>
</div>
<div v-if="isRoomSettingsOpen && controller.isEditMode.value" class="_panel" :class="$style.overlayObjectInfoPanel">
@ -265,6 +265,7 @@ const attachments = {
} as RoomAttachments;
function addFileAttachment(file: Misskey.entities.DriveFile) {
// TODO: clean unused attachment
attachments.files.push(file);
}
@ -460,6 +461,11 @@ function showSnappingMenu(ev: PointerEvent) {
}], ev.currentTarget ?? ev.target);
}
function updateObjectOption(k: string, v: any) {
// TODO: podtMrssageattachments
controller.updateObjectOption(controller.selected.value.objectId, k, v, attachments);
}
async function addObject(ev: PointerEvent) {
//
controller.pauseRender();

View file

@ -19,7 +19,7 @@ import { findMaterial, GRAPHICS_QUALITY, ModelManager, SYSTEM_HEYA_MESH_NAMES, S
import { JapaneseEnvManager, MuseumEnvManager, SimpleEnvManager } from './env.js';
import { convertRawOptions } from './object.js';
import type { RoomAttachments } from './utility.js';
import type { ConvertedOptions, ObjectDef, RoomObjectInstance, RoomStateObject } from './object.js';
import type { ConvertedOptions, ObjectDef, RawOptions, RoomObjectInstance, RoomStateObject } from './object.js';
import type { GridMaterial } from '@babylonjs/materials';
import type { EnvManager, JapaneseEnvOptions, SimpleEnvOptions } from './env.js';
import { genId } from '@/utility/id.js';
@ -42,6 +42,22 @@ export type RoomState = {
worldScale: number;
};
export function collectAttachmentFileIds(roomState: RoomState) {
const fileIds = new Set<string>();
for (const o of roomState.installedObjects) {
const def = getObjectDef(o.type);
for (const schemaRecord of Object.entries(def.options.schema)) {
if (schemaRecord[1].type === 'file') {
const optionValue = o.options[schemaRecord[0]];
if (optionValue != null && optionValue !== '') {
fileIds.add(optionValue);
}
}
}
}
return fileIds;
}
function mergeMeshes(meshes: BABYLON.Mesh[], root: BABYLON.Mesh, hasTexture: boolean) {
const excludeMeshes = root.getChildMeshes().filter(m => SYSTEM_MESH_NAMES.some(s => m.name.includes(s)));
@ -641,7 +657,7 @@ export class RoomEngine extends EventEmitter {
id: string;
position: BABYLON.Vector3;
rotation: BABYLON.Vector3;
options: any;
options: RawOptions;
}) {
const def = getObjectDef(args.type);
@ -1448,7 +1464,7 @@ export class RoomEngine extends EventEmitter {
return root;
}
public async addObject(type: string, _options?: any, attachments?: RoomAttachments) {
public async addObject(type: string, _options?: RawOptions, attachments?: RoomAttachments) {
if (!this.isEditMode) return;
if (this.grabbingCtx != null) return;

View file

@ -114,6 +114,7 @@ import { wireNet } from './objects/wireNet.js';
import { woodRingFloorLamp } from './objects/woodRingFloorLamp.js';
import { woodRingsPendantLight } from './objects/woodRingsPendantLight.js';
import { woodSoundAbsorbingPanel } from './objects/woodSoundAbsorbingPanel.js';
import type { ObjectDef } from './object.js';
export const OBJECT_DEFS = [
a4Case,
@ -229,8 +230,8 @@ export const OBJECT_DEFS = [
wireBasket,
];
export function getObjectDef(type: string): typeof OBJECT_DEFS[number] {
const def = OBJECT_DEFS.find(x => x.id === type);
export function getObjectDef(type: string): ObjectDef {
const def = OBJECT_DEFS.find(x => x.id === type) as ObjectDef | undefined;
if (def == null) {
throw new Error(`Unrecognized object type: ${type}`);
}

View file

@ -115,13 +115,13 @@ type GetConvertedOptionsSchemaValues<T extends OptionsSchema> = {
never;
};
export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
export type ObjectDef<OpSc extends OptionsSchema | undefined = undefined> = {
id: string;
name: string;
path?: string;
options: {
schema: OpSc;
default: GetRawOptionsSchemaValues<OpSc>;
schema: OpSc extends undefined ? OptionsSchema : NonNullable<OpSc>;
default: OpSc extends undefined ? RawOptions : GetRawOptionsSchemaValues<NonNullable<OpSc>>;
};
placement: 'top' | 'side' | 'bottom' | 'wall' | 'ceiling' | 'floor';
hasCollisions?: boolean;
@ -141,13 +141,13 @@ export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
};
lc: BABYLON.ClusteredLightContainer | null;
root: BABYLON.Mesh;
options: Readonly<GetConvertedOptionsSchemaValues<OpSc>>;
options: OpSc extends undefined ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<NonNullable<OpSc>>>;
model: ModelManager;
id: string;
timer: Timer;
graphicsQuality: number;
stickyMarkerMeshUpdated?: (mesh: BABYLON.Mesh) => void;
}) => RoomObjectInstance<GetConvertedOptionsSchemaValues<OpSc>> | Promise<RoomObjectInstance<GetConvertedOptionsSchemaValues<OpSc>>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
}) => RoomObjectInstance<OpSc extends undefined ? ConvertedOptions : GetConvertedOptionsSchemaValues<NonNullable<OpSc>>> | Promise<OpSc extends undefined ? ConvertedOptions : RoomObjectInstance<GetConvertedOptionsSchemaValues<NonNullable<OpSc>>>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
};
export function defineObject<const OpSc extends OptionsSchema>(def: ObjectDef<OpSc>): ObjectDef<OpSc> {
@ -162,8 +162,8 @@ export function defineObjectClass<const OpSc extends OptionsSchema>(baseDef: Par
};
}
export function convertRawOptions<OpSc extends OptionsSchema>(schema: OpSc, raw: RawOptions, attachments: RoomAttachments): GetConvertedOptionsSchemaValues<OpSc> {
const converted = {} as GetConvertedOptionsSchemaValues<OpSc>;
export function convertRawOptions<OpSc extends OptionsSchema>(schema: OpSc, raw: RawOptions, attachments: RoomAttachments): ConvertedOptions {
const converted = {} as ConvertedOptions;
for (const record of Object.entries(schema)) {
const k = record[0];
const v = raw[k];