diff --git a/packages/frontend/src/pages/room.vue b/packages/frontend/src/pages/room.vue
index a2d22a4c6f..659de04a98 100644
--- a/packages/frontend/src/pages/room.vue
+++ b/packages/frontend/src/pages/room.vue
@@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ selectedObjectDef.name }}
- controller.updateObjectOption(controller.selected.value.objectId, k, v, attachments)">
+ updateObjectOption(k, v)">
@@ -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: podtMrssageのコスト削減のためattachmentsは更新がある場合のみ送る
+ controller.updateObjectOption(controller.selected.value.objectId, k, v, attachments);
+}
+
async function addObject(ev: PointerEvent) {
// 重いので止める
controller.pauseRender();
diff --git a/packages/frontend/src/world/room/engine.ts b/packages/frontend/src/world/room/engine.ts
index 2e7d4872ad..8d9d3d83a9 100644
--- a/packages/frontend/src/world/room/engine.ts
+++ b/packages/frontend/src/world/room/engine.ts
@@ -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();
+ 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;
diff --git a/packages/frontend/src/world/room/object-defs.ts b/packages/frontend/src/world/room/object-defs.ts
index 0a0ac77e5b..1b1e965c83 100644
--- a/packages/frontend/src/world/room/object-defs.ts
+++ b/packages/frontend/src/world/room/object-defs.ts
@@ -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}`);
}
diff --git a/packages/frontend/src/world/room/object.ts b/packages/frontend/src/world/room/object.ts
index b2d80841f5..9b247eb7aa 100644
--- a/packages/frontend/src/world/room/object.ts
+++ b/packages/frontend/src/world/room/object.ts
@@ -115,13 +115,13 @@ type GetConvertedOptionsSchemaValues = {
never;
};
-export type ObjectDef = {
+export type ObjectDef = {
id: string;
name: string;
path?: string;
options: {
- schema: OpSc;
- default: GetRawOptionsSchemaValues;
+ schema: OpSc extends undefined ? OptionsSchema : NonNullable;
+ default: OpSc extends undefined ? RawOptions : GetRawOptionsSchemaValues>;
};
placement: 'top' | 'side' | 'bottom' | 'wall' | 'ceiling' | 'floor';
hasCollisions?: boolean;
@@ -141,13 +141,13 @@ export type ObjectDef = {
};
lc: BABYLON.ClusteredLightContainer | null;
root: BABYLON.Mesh;
- options: Readonly>;
+ options: OpSc extends undefined ? ConvertedOptions : Readonly>>;
model: ModelManager;
id: string;
timer: Timer;
graphicsQuality: number;
stickyMarkerMeshUpdated?: (mesh: BABYLON.Mesh) => void;
- }) => RoomObjectInstance> | Promise>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
+ }) => RoomObjectInstance>> | Promise>>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
};
export function defineObject(def: ObjectDef): ObjectDef {
@@ -162,8 +162,8 @@ export function defineObjectClass(baseDef: Par
};
}
-export function convertRawOptions(schema: OpSc, raw: RawOptions, attachments: RoomAttachments): GetConvertedOptionsSchemaValues {
- const converted = {} as GetConvertedOptionsSchemaValues;
+export function convertRawOptions(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];