diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 38fede5411..88e4a69496 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -3597,6 +3597,8 @@ _miWorld: sit: "座る" lyingDown: "寝そべる" standUp: "立ち上がる" + showUsernameOnAvatar: "アバターにユーザー名を表示" + show2dAvatarOnAvatar: "アバターにユーザーアイコンを表示" _avatars: _default: diff --git a/packages/frontend-misskey-world-engine/src/room/engine.ts b/packages/frontend-misskey-world-engine/src/room/engine.ts index 63074f71de..f6f9b6b7e6 100644 --- a/packages/frontend-misskey-world-engine/src/room/engine.ts +++ b/packages/frontend-misskey-world-engine/src/room/engine.ts @@ -187,8 +187,9 @@ export class RoomEngine extends EngineBase<{ } private playerProfiles: Record = {}; - private playerStates: Record = {}; private playerContainers: PlayerContainer[] = []; + private showUsernameOnAvatar: boolean; + private show2dAvatarOnAvatar: boolean; private inited = false; @@ -199,6 +200,8 @@ export class RoomEngine extends EngineBase<{ antialias: boolean; fov: number; useVirtualJoystick?: boolean; + showUsernameOnAvatar: boolean; + show2dAvatarOnAvatar: boolean; }) { super({ engine: options.engine, @@ -216,6 +219,8 @@ export class RoomEngine extends EngineBase<{ this.graphicsQuality = options.graphicsQuality; this.useGlow = this.graphicsQuality >= GRAPHICS_QUALITY.MEDIUM; this.fov = options.fov; + this.showUsernameOnAvatar = options.showUsernameOnAvatar; + this.show2dAvatarOnAvatar = options.show2dAvatarOnAvatar; this.time = TIME_MAP[new Date().getHours() as keyof typeof TIME_MAP]; registerBuiltInLoaders(); @@ -1504,8 +1509,8 @@ export class RoomEngine extends EngineBase<{ state: states[k], scene: this.scene, sr: this.sr, - showUsername: true, - show2dAvatar: true, + showUsername: this.showUsernameOnAvatar, + show2dAvatar: this.show2dAvatarOnAvatar, }); // TODO: loadFunitureのものとある程度共通化 p.registerMeshes = (meshes) => { @@ -1568,14 +1573,25 @@ export class RoomEngine extends EngineBase<{ } public clearPlayers() { + this.sr.disableSnapshotRendering(); for (const playerContainer of this.playerContainers) { - this.sr.disableSnapshotRendering(); playerContainer.destroy(); - this.sr.enableSnapshotRendering(); } + this.sr.enableSnapshotRendering(); this.playerContainers = []; } + public updateAvatarDisplayOptions(options: { showUsername: boolean; show2dAvatar: boolean }) { + this.showUsernameOnAvatar = options.showUsername; + this.show2dAvatarOnAvatar = options.show2dAvatar; + + this.sr.disableSnapshotRendering(); + for (const playerContainer of this.playerContainers) { + playerContainer.updateUserInfoDisplayOptions(options); + } + this.sr.enableSnapshotRendering(); + } + public resize() { // 一旦snapshot renderingを無効にしておかないとエラーが出る // ~~...が、一旦無効にしたらしたで複数のマテリアルがそれぞれ入れ替わる(?)という謎の現象が発生するためコメントアウトしとく(エラー出てもレンダリングが止まったりするわけでもないし)~~ diff --git a/packages/frontend-misskey-world-engine/src/room/nonWorker.ts b/packages/frontend-misskey-world-engine/src/room/nonWorker.ts index 57ef4470b1..c254cc086d 100644 --- a/packages/frontend-misskey-world-engine/src/room/nonWorker.ts +++ b/packages/frontend-misskey-world-engine/src/room/nonWorker.ts @@ -11,7 +11,19 @@ import type { RoomState, RoomAttachments } from 'misskey-world/src/room/type.js' registerBabylonRuntime(); export async function createRoomEngine(params: { - roomState: RoomState; roomAttachments: RoomAttachments; canvas: HTMLCanvasElement; options: { antialias: boolean; resolution: number; fov: number; graphicsQuality: number; fps: number | null; useVirtualJoystick?: boolean; }; + roomState: RoomState; + roomAttachments: RoomAttachments; + canvas: HTMLCanvasElement; + options: { + antialias: boolean; + resolution: number; + fov: number; + graphicsQuality: number; + fps: number | null; + useVirtualJoystick?: boolean; + showUsernameOnAvatar: boolean; + show2dAvatarOnAvatar: boolean; + }; }) { const babylonEngine = new BABYLON.WebGPUEngine(params.canvas, { doNotHandleContextLost: true, powerPreference: 'high-performance', antialias: params.options.antialias }); babylonEngine.compatibilityMode = false; diff --git a/packages/frontend/src/pages/rooms/room.core.vue b/packages/frontend/src/pages/rooms/room.core.vue index 2af1adc06f..21610c92d6 100644 --- a/packages/frontend/src/pages/rooms/room.core.vue +++ b/packages/frontend/src/pages/rooms/room.core.vue @@ -240,6 +240,8 @@ const resolutionAutoValue = computed(() => deviceKind !== 'desktop' ? 0. const resolution = computed(() => resolutionRaw.value ?? resolutionAutoValue.value); const antialias = prefer.model('world.antialias'); +const showUsernameOnAvatar = prefer.model('world.showUsernameOnAvatar'); +const show2dAvatarOnAvatar = prefer.model('world.show2dAvatarOnAvatar'); const useVirtualJoystick = isTouchUsing && (deviceKind === 'smartphone' || deviceKind === 'tablet'); //const useVirtualJoystick = true; @@ -329,6 +331,8 @@ const roomControllerOptions = computed(() => ({ useVirtualJoystick, fov: prefer.s['world.fov'], workerMode: prefer.s['world.separateRenderingThread'], + showUsernameOnAvatar: showUsernameOnAvatar.value, + show2dAvatarOnAvatar: show2dAvatarOnAvatar.value, })); const controller = markRaw(new RoomController(deepClone(initialRoomState), roomControllerOptions.value)); @@ -362,6 +366,13 @@ watch([graphicsQuality, fps, resolution, antialias], () => { refresh(); }); +watch([showUsernameOnAvatar, show2dAvatarOnAvatar], () => { + controller.updateAvatarDisplayOptions({ + showUsername: showUsernameOnAvatar.value, + show2dAvatar: show2dAvatarOnAvatar.value, + }); +}); + controller.addListener('playerPointed', ({ playerId }) => { pointedPlayerInfo.value = multiplayer.playerProfiles[playerId] ?? null; isPlayerInfoOpen.value = true; @@ -650,6 +661,7 @@ function showCharacterMenu(ev: PointerEvent) { function showOnlineMenu(ev: PointerEvent) { os.popupMenu([{ text: multiplayer.isOnline.value ? i18n.ts._miWorld.disconnectToOnline : i18n.ts._miWorld.connectToOnline, + icon: multiplayer.isOnline.value ? 'ti ti-world-off' : 'ti ti-world', danger: multiplayer.isOnline.value, action: () => { if (multiplayer.isOnline.value) { @@ -658,6 +670,21 @@ function showOnlineMenu(ev: PointerEvent) { enterOnline(); } }, + }, { + type: 'divider', + }, { + type: 'parent', + text: i18n.ts.settings, + icon: 'ti ti-settings', + children: [{ + type: 'switch', + text: i18n.ts._miWorld.showUsernameOnAvatar, + ref: showUsernameOnAvatar, + }, { + type: 'switch', + text: i18n.ts._miWorld.show2dAvatarOnAvatar, + ref: show2dAvatarOnAvatar, + }], }], ev.currentTarget ?? ev.target); } diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index 0e71557d0e..f411344628 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -754,11 +754,18 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - - - + + + + + + + + + + + + @@ -839,6 +846,15 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + + + +
@@ -1060,6 +1076,8 @@ const worldFps = prefer.model('world.fps'); const worldResolution = prefer.model('world.resolution'); const worldAntialias = prefer.model('world.antialias'); const worldFov = prefer.model('world.fov'); +const worldShowUsernameOnAvatar = prefer.model('world.showUsernameOnAvatar'); +const worldShow2dAvatarOnAvatar = prefer.model('world.show2dAvatarOnAvatar'); const fontSize = ref(miLocalStorage.getItem('fontSize') as '1' | '2' | '3' | null); const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null); diff --git a/packages/frontend/src/world/room/controller.ts b/packages/frontend/src/world/room/controller.ts index f86662d5e8..5b3aea548c 100644 --- a/packages/frontend/src/world/room/controller.ts +++ b/packages/frontend/src/world/room/controller.ts @@ -23,6 +23,8 @@ export type RoomControllerOptions = { antialias: boolean; fov: number; useVirtualJoystick?: boolean; + showUsernameOnAvatar: boolean; + show2dAvatarOnAvatar: boolean; }; // 抽象化レイヤー @@ -245,4 +247,8 @@ export class RoomController extends EngineControllerBase