This commit is contained in:
syuilo 2026-05-25 15:51:51 +09:00
commit eb33c8a93f
9 changed files with 70 additions and 57 deletions

View file

@ -69,7 +69,7 @@ import { ref, useTemplateRef, watch, onMounted, onUnmounted, reactive, nextTick,
import * as Misskey from 'misskey-js';
import XObjectCustomizeForm from './room.object-customize-form.vue';
import XItem from './room.add-object-dialog.item.vue';
import type { RawOptions, RoomObjectInstance, RoomStateObject } from '@/world/room/object.js';
import type { RawOptions } from '@/world/room/object.js';
import type { PreviewEngineControllerOptions } from '@/world/room/previewEngineController.js';
import type { RoomAttachments } from '@/world/room/utility.js';
import { i18n } from '@/i18n.js';

View file

@ -163,8 +163,6 @@ export class ObjectContainer {
subRootMesh.dispose();
def.treatLoaderResult?.(loaderResult);
this.registerMeshes(this.subRoot.getChildMeshes());
this.model = new ModelManager(this.subRoot, loaderResult.meshes.filter(m => !m.isDisposed() && m.name !== '__root__'), def.hasTexture, (meshes) => {

View file

@ -3,13 +3,13 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { GetOptionsSchemaUiDef, OptionsSchema } from './object.js';
import type { GetOptionsSchemaUiDef, ObjectSchemaDef } from './object.js';
export type ObjectUiDef<OpSc extends OptionsSchema = OptionsSchema> = {
export type ObjectUiDef<Schema extends ObjectSchemaDef = ObjectSchemaDef> = {
name: string;
options: GetOptionsSchemaUiDef<OpSc>;
options: GetOptionsSchemaUiDef<Schema['options']['schema']>;
};
export function defineObjectUi<const Def extends { options: { schema: OptionsSchema } }>(def: ObjectUiDef<Def['options']['schema']>): ObjectUiDef<Def['options']['schema']> {
export function defineObjectUi<const Schema extends ObjectSchemaDef<any>>(def: ObjectUiDef<Schema>): ObjectUiDef<Schema> {
return def;
}

View file

@ -25,7 +25,7 @@ import { findMaterial, GRAPHICS_QUALITY, ModelManager, SYSTEM_HEYA_MESH_NAMES, S
import { JapaneseEnvManager, MuseumEnvManager, SimpleEnvManager } from './env.js';
import { ObjectContainer } from './ObjectContainer.js';
import type { RoomAttachments } from './utility.js';
import type { ObjectDef, RawOptions, RoomObjectInstance, RoomStateObject } from './object.js';
import type { ObjectDef, RawOptions, RoomStateObject } from './object.js';
import type { GridMaterial } from '@babylonjs/materials';
import type { EnvManager, JapaneseEnvOptions, SimpleEnvOptions } from './env.js';
import { genId } from '@/utility/id.js';

View file

@ -85,7 +85,7 @@ type SeedOptionSchema = {
type: 'seed';
};
export type OptionsSchema = Record<string, NumberOptionSchema | BooleanOptionSchema | StringOptionSchema | ColorOptionSchema | MaterialOptionSchema | LightOptionSchema | EnumOptionSchema | RangeOptionSchema | ImageOptionSchema | SeedOptionSchema>;
type OptionsSchema = Record<string, NumberOptionSchema | BooleanOptionSchema | StringOptionSchema | ColorOptionSchema | MaterialOptionSchema | LightOptionSchema | EnumOptionSchema | RangeOptionSchema | ImageOptionSchema | SeedOptionSchema>;
export type RawOptions = Record<string, unknown> & {
readonly __brand: unique symbol;
@ -146,7 +146,7 @@ export type SnapshotRenderingHelperWrapper = {
fixParticleSystem: (ps: BABYLON.ParticleSystem) => void;
};
export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
export type ObjectSchemaDef<OpSc extends OptionsSchema = OptionsSchema> = {
id: string;
options: {
schema: string extends keyof OpSc ? OptionsSchema : OpSc;
@ -156,10 +156,11 @@ export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
hasCollisions?: boolean;
hasTexture?: boolean;
canPreMeshesMerging?: boolean; // TODO: 除外するメッシュ名を指定できるようにする
//groupingMeshes: string[]; // multi-materialなメッシュは複数のメッシュに分割されるが、それだと不便な場合に追加の親メッシュでグルーピングするための指定
isChair?: boolean;
treatLoaderResult?: (loaderResult: BABYLON.AssetContainer) => void;
path?: (options: string extends keyof OpSc ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<OpSc>>) => string;
};
export type ObjectDef<Schema extends ObjectSchemaDef = ObjectSchemaDef> = Schema & {
path?: (options: string extends keyof Schema['options']['schema'] ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<Schema['options']['schema']>>) => string;
createInstance: (args: {
scene: BABYLON.Scene;
// TODO: snapshot renderingの関心を隠蔽した方が綺麗かもしれない
@ -167,7 +168,7 @@ export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
sr: SnapshotRenderingHelperWrapper;
lc: BABYLON.ClusteredLightContainer | null;
root: BABYLON.TransformNode;
options: string extends keyof OpSc ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<OpSc>>;
options: string extends keyof Schema['options']['schema'] ? ConvertedOptions : Readonly<GetConvertedOptionsSchemaValues<Schema['options']['schema']>>;
model: ModelManager;
id: string;
timer: Timer;
@ -175,18 +176,22 @@ export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
stickyMarkerMeshUpdated?: (mesh: BABYLON.Mesh) => void;
sitChair?: () => void;
reloadModel: () => void;
}) => RoomObjectInstance<string extends keyof OpSc ? ConvertedOptions : GetConvertedOptionsSchemaValues<OpSc>> | Promise<RoomObjectInstance<OpSc extends undefined ? ConvertedOptions : GetConvertedOptionsSchemaValues<OpSc>>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
}) => RoomObjectInstance<string extends keyof Schema['options']['schema'] ? ConvertedOptions : GetConvertedOptionsSchemaValues<Schema['options']['schema']>> | Promise<RoomObjectInstance<Schema['options']['schema'] extends undefined ? ConvertedOptions : GetConvertedOptionsSchemaValues<Schema['options']['schema']>>>; // TODO: createInstanceをasyncにするのではなく、別にreadyみたいなものを返させる
};
export function defineObject<const OpSc extends OptionsSchema>(def: ObjectDef<OpSc>): ObjectDef<OpSc> {
export function defineObjectSchema<const OpSc extends OptionsSchema>(def: ObjectSchemaDef<OpSc>): ObjectSchemaDef<OpSc> {
return def;
}
export function defineObjectClass<const OpSc extends OptionsSchema>(baseDef: Partial<ObjectDef<OpSc>>): {
extend: (childDef: Partial<ObjectDef<OpSc>>) => ObjectDef<OpSc>;
export function defineObject<const Schema extends ObjectSchemaDef<any>>(schema: Schema, def: Pick<ObjectDef<Schema>, 'path' | 'createInstance'>): ObjectDef<Schema> {
return { ...schema, ...def };
}
export function defineObjectClass<const Schema extends ObjectSchemaDef<any>>(baseDef: Partial<ObjectDef<Schema>>): {
extend: (childDef: Partial<ObjectDef<Schema>>) => ObjectDef<Schema>;
} {
return {
extend: (childDef) => ({ ...baseDef, ...childDef }) as ObjectDef<OpSc>,
extend: (childDef) => ({ ...baseDef, ...childDef }) as ObjectDef<Schema>,
};
}

View file

@ -0,0 +1,42 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { defineObjectSchema } from '../object.js';
export const allInOnePc_schema = defineObjectSchema({
id: 'allInOnePc',
placement: 'top',
hasTexture: true,
options: {
schema: {
bodyMat: {
type: 'material',
},
bezelMat: {
type: 'material',
},
screenBrightness: {
type: 'range',
min: 0,
max: 1,
step: 0.01,
},
image: {
type: 'image',
presets: [{
value: 'desktop',
}],
},
},
default: {
bodyMat: { color: [1, 1, 1], roughness: 0.5, metallic: 1 },
bezelMat: { color: [0, 0, 0], roughness: 0, metallic: 0 },
screenBrightness: 0.5,
image: {
type: null,
},
},
},
});

View file

@ -7,41 +7,9 @@ import * as BABYLON from '@babylonjs/core';
import { createTextureManager, defineObject } from '../object.js';
import { cm, WORLD_SCALE } from '../../utility.js';
import { getLightRangeFactorByGraphicsQuality } from '../utility.js';
import { allInOnePc_schema } from './allInOnePc.schema.js';
export const allInOnePc = defineObject({
id: 'allInOnePc',
options: {
schema: {
bodyMat: {
type: 'material',
},
bezelMat: {
type: 'material',
},
screenBrightness: {
type: 'range',
min: 0,
max: 1,
step: 0.01,
},
image: {
type: 'image',
presets: [{
value: 'desktop',
}],
},
},
default: {
bodyMat: { color: [1, 1, 1], roughness: 0.5, metallic: 1 },
bezelMat: { color: [0, 0, 0], roughness: 0, metallic: 0 },
screenBrightness: 0.5,
image: {
type: null,
},
},
},
placement: 'top',
hasTexture: true,
export const allInOnePc = defineObject(allInOnePc_schema, {
createInstance: async ({ lc, scene, options, model, graphicsQuality }) => {
const matrix = model.root.getWorldMatrix(true);
const scale = new BABYLON.Vector3();

View file

@ -4,10 +4,10 @@
*/
import { defineObjectUi } from '../defineObjectUi.js';
import type { allInOnePc } from './allInOnePc.js';
import type { allInOnePc_schema } from './allInOnePc.schema.js';
import { i18n } from '@/i18n.js';
export const allInOnePc_ui = defineObjectUi<typeof allInOnePc>({
export const allInOnePc_ui = defineObjectUi<typeof allInOnePc_schema>({
name: i18n.ts._miRoom._objects.allInOnePc,
options: {
bodyMat: {

View file

@ -9,9 +9,9 @@ import { GridMaterial } from '@babylonjs/materials';
import { camelToKebab, WORLD_SCALE, cm, getMeshesBoundingBox, Timer, sleep, ArcRotateCameraManualInput } from '../utility.js';
import { EngineBase } from '../EngineBase.js';
import { getObjectDef } from './object-defs.js';
import { SYSTEM_MESH_NAMES, ModelManager, GRAPHICS_QUALITY } from './utility.js';
import { SYSTEM_MESH_NAMES, GRAPHICS_QUALITY } from './utility.js';
import { ObjectContainer } from './ObjectContainer.js';
import type { RawOptions, RoomObjectInstance } from './object.js';
import type { RawOptions } from './object.js';
import type { RoomAttachments } from './utility.js';
import { genId } from '@/utility/id.js';
import { deepClone } from '@/utility/clone.js';