This commit is contained in:
syuilo 2026-05-28 15:03:06 +09:00
commit 9a91170839
4 changed files with 31 additions and 4 deletions

View file

@ -176,6 +176,7 @@ export interface ChatEventTypes {
export interface WorldRoomEventTypes {
enter: {
user: Packed<'UserLite'>;
avatar: Packed<'WorldAvatarLite'>['def'] | null;
};
left: {
userId: MiUser['id'];

View file

@ -35,6 +35,24 @@ export class WorldAvatarService {
) {
}
public defaultAvatar = {
type: 'default',
body: {
color: [0.8, 0.8, 0.8],
roughness: 1,
metallic: 0,
},
eyes: {
type: 'a',
color: [0, 0, 0],
},
mouth: {
type: 'a',
color: [0, 0, 0],
},
accessories: [],
} satisfies MiWorldAvatar['def'];
@bindThis
public async validateDef(
me: MiUser,

View file

@ -10,7 +10,7 @@ import { DI } from '@/di-symbols.js';
import {
MiWorldRoom,
} from '@/models/_.js';
import type { WorldRoomsRepository } from '@/models/_.js';
import type { MiWorldAvatar, WorldRoomsRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { IdService } from '@/core/IdService.js';
@ -20,6 +20,8 @@ import { QueryService } from '@/core/QueryService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import type { Packed } from '@/misc/json-schema.js';
import { WorldAvatarService } from '@/core/WorldAvatarService.js';
import { WorldAvatarEntityService } from '@/core/entities/WorldAvatarEntityService.js';
type PlayerState = {
position: [number, number, number],
@ -44,6 +46,8 @@ export class WorldRoomMultiplayService {
private idService: IdService,
private globalEventService: GlobalEventService,
private userEntityService: UserEntityService,
private worldAvatarService: WorldAvatarService,
private worldAvatarEntityService: WorldAvatarEntityService,
) {
}
@ -63,8 +67,10 @@ export class WorldRoomMultiplayService {
}
// TODO: 既に入っていたらスキップ
const avatar = await this.worldAvatarService.getActiveAvatarOfUser(userId);
this.globalEventService.publishWorldRoomStream(roomId, 'enter', {
user: await this.userEntityService.pack(userId),
avatar: avatar?.def,
});
}
@ -117,11 +123,12 @@ export class WorldRoomMultiplayService {
}
@bindThis
public packPlayerProfile(user: Packed<'UserLite'>) {
public packPlayerProfile(user: Packed<'UserLite'>, avatar: Packed<'WorldAvatarLite'>['def'] | null) {
return {
name: user.name,
username: user.username,
avatarUrl: user.avatarUrl,
worldAvatar: avatar ?? this.worldAvatarService.defaultAvatar,
};
}
@ -131,12 +138,13 @@ export class WorldRoomMultiplayService {
playerIds = playerIds.filter(id => id !== userId);
const packedUsers = await this.userEntityService.packMany(playerIds);
const avatars = await this.worldAvatarService.getActiveAvatarOfUsers(playerIds);
const profiles: Record<string, any> = {};
for (const playerId of playerIds) {
const packedUser = packedUsers.find(u => u.id === playerId);
if (packedUser == null) continue;
profiles[playerId] = this.packPlayerProfile(packedUser);
profiles[playerId] = this.packPlayerProfile(packedUser, avatars.find(a => a.userId === playerId)?.def ?? null);
}
return profiles;
}

View file

@ -80,7 +80,7 @@ export class WorldRoomChannel extends Channel {
if (data.body.user.id === this.user!.id) return; // 自分の入室は無視
this.send('playerEntered', {
id: data.body.user.id,
profile: this.worldRoomMultiplayService.packPlayerProfile(data.body.user),
profile: this.worldRoomMultiplayService.packPlayerProfile(data.body.user, data.body.avatar),
});
break;
}