123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- import CoreBroadcastType from "./enum/CoreBroadcastType.js"
- import AvatarGroup from "./enum/AvatarGroup.js"
- import Broadcast from "./Broadcast.js"
- import {avatarLoader} from "./XAvatarLoader.js"
- import SyncEventType from "./enum/SyncEventType.js"
- import GetStateTypes from "./enum/GetStateTypes.js"
- import EAvatarRelationRank from "./enum/EAvatarRelationRank.js"
- import Person from "./enum/Person.js"
- import XverseAvatar from "./XverseAvatar.js"
- import MotionType from "./enum/MotionType.js"
- import TimeoutError from "./error/TimeoutError.js"
- import Logger from "./Logger.js"
- import QueueType from "./enum/QueueType.js"
- const logger = new Logger('4DMVS_CharacterManager')
- export default class XverseAvatarManager extends EventEmitter {
- constructor(room) {
- super();
- this.xAvatarManager = null
- this.avatars = new Map
- this.syncAvatarsLength = 0
- this._room = room;
- this._usersStatistics();
- this.broadcast = this.setupBroadcast();
- room.on("skinChanged", ()=>{
- this.avatars.forEach(t=>{
- avatar.disconnected && this.removeAvatar(avatar.userId, !0)
- })
- })
- }
- setupBroadcast() {
- return new Broadcast(this._room,async e=>{
- const {broadcastType: t, info: r} = e;
- if (t !== CoreBroadcastType.PlayAnimation)
- return;
- const {userId: n, animation: o, extra: a, loop: s=!1} = r
- , l = this.avatars.get(n);
- l && !l.isSelf && (l.emit("animationStart", {
- animationName: o,
- extra: decodeURIComponent(a)
- }),
- await (l == null ? void 0 : l._playAnimation(o, s)),
- l.emit("animationEnd", {
- animationName: o,
- extra: decodeURIComponent(a)
- }))
- }
- )
- }
- hideAll(e=!0) {
- this.xAvatarManager.hideAll(e)
- }
- showAll(e=!0) {
- this.xAvatarManager.showAll(e)
- }
- async init() {
- this.xAvatarManager = this._room.sceneManager.avatarComponent;
- try {
- const configList = await this._room.modelManager.getApplicationConfig()
- , {avatars} = configList;
- if (avatars) {
- await avatarLoader.parse(this._room.sceneManager, avatars);
- return
- }
- return Promise.reject("cannot find avatar config list")
- } catch (e) {
- return logger.error(e),
- Promise.reject("avatar mananger init error!")
- }
- }
- async handleAvatar(signal) {
- if (this._room.viewMode === "simple" || !this._room.joined || !signal.newUserStates)
- return;
- let newUserStates = signal.newUserStates;
- let userAvatar = this._room._userAvatar;
- if ((userAvatar == null ? void 0 : userAvatar.isMoving) && userAvatar.motionType === MotionType.Run)
- {
- const mainStates = newUserStates.filter(state => state.userId === this._room.userId)
- , o = newUserStates.filter(state => state.userId !== this._room.userId).slice(0, 2);
- newUserStates = mainStates.concat(o)
- }
- if (signal.getStateType === GetStateTypes.Event)
- {
- this.syncAvatarsLength = (newUserStates || []).length;
- const n = this._room.avatars.filter(avatar => avatar.group == AvatarGroup.User);
- n.filter(avatar =>
- !(newUserStates != null && newUserStates.find(state => state.userId == avatar.userId))
- ).forEach(avatar=>{
- this.removeAvatar(avatar.userId)
- });
- const a = newUserStates.filter(state => !n.find(avatar => avatar.userId == state.userId));
- this._handleAvatar(a)
- }
- this._handleAvatar(newUserStates)
- }
- async _handleAvatar(newUserStates) {
- newUserStates && newUserStates.forEach(state=>{
- const isMainAvatar = this._room.userId === state.userId;
- if (state.event && state.event.type === SyncEventType.ET_RemoveVisitor)
- {
- const removeVisitorEvent = state.event.removeVisitorEvent
- const event = removeVisitorEvent && removeVisitorEvent.removeVisitorEvent
- , extraInfo = JSON.parse(safeDecodeURIComponent((removeVisitorEvent && removeVisitorEvent.extraInfo) || ""))
- , { code, msg } = extraInfo;
- event === RemoveVisitorType.RVT_ChangeToObserver
- ? this._room.audienceViewModeHook()
- : event === RemoveVisitorType.RVT_MoveOutOfTheRoom && this._room.leave() // 这里会触发Actions.Exit
- this._room.emit("visitorStatusChanged", { code, msg })
- }
- if (state.event && [SyncEventType.Appear, SyncEventType.Reset].includes(state.event.type) || !state.event) {
- let avatar = this.avatars.get(state.userId);
- if(state.playerState.avatarId && avatar && avatar.avatarId !== state.playerState.avatarId) {
- avatar = void 0
- this.removeAvatar(state.userId)
- }
- if (avatar) {
- avatar.disconnected && avatar.setConnectionStatus(!1)
- state.event && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id) // 这里会触发Actions.ConfirmEvent
- state.playerState.nickName && (avatar && avatar._setNickname(state.playerState.nickName))
- if (state.playerState.avatarComponents && !avatar.isSelf && avatar.xAvatar) {
- const avatarComponents = safeParseComponents(state.playerState.avatarComponents);
- // 这里会触发Actions.SetPlayerState
- avatar._changeComponents({
- avatarComponents,
- mode: ChangeComponentsMode.Preview
- })
- }
- } else {
- const {position, angle} = state.playerState.player
- , avatarId = state.playerState.avatarId
- , prioritySync = state.playerState.prioritySync
- , extraInfo = safelyJsonParse(state.playerState.extra);
- if (!avatarId) return;
- const avatarComponents = safeParseComponents(state.playerState.avatarComponents)
- , nickname = safeDecodeURIComponent(state.playerState.nickName)
- , priority = this.calculatePriority(state.userId, extraInfo);
-
- this.addAvatar({
- userId: state.userId,
- isHost: state.playerState.isHost,
- nickname,
- avatarPosition: position,
- avatarRotation: angle,
- avatarScale: state.playerState.avatarSize,
- avatarId,
- avatarComponents: state.playerState.person === Person.First ? [] : avatarComponents,
- priority,
- group: AvatarGroup.User,
- prioritySync,
- extraInfo
- }).then(()=>{
- state.event && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id), // 这里会触发Actions.ConfirmEvent
- this.updateAvatarPositionAndRotation(state),
- isMainAvatar && (
- this.xAvatarManager.setMainAvatar(state.userId),
- this._room.emit("userAvatarLoaded"),
- logger.info("userAvatarLoaded")
- )
- }).catch(e=>{
- isMainAvatar && (
- this.xAvatarManager.setMainAvatar(state.userId),
- this._room.emit("userAvatarFailed", {error: e}),
- logger.error("userAvatarFailed", e)
- )
- })
- }
- }
- if(state.event && SyncEventType.Disappear === state.event.type) {
- state.event.id && this._room.actionsHandler.confirmEvent(state.event.id) // 这里会触发Actions.ConfirmEvent
- this.removeAvatar(state.userId)
- }
- if (state.event && [SyncEventType.Move, SyncEventType.ChangeRenderInfo].includes(state.event.type) || !state.event) {
- state.event && state.event.id && this._room.actionsHandler.confirmEvent(state.event.id); // 这里会触发Actions.ConfirmEvent
- const avatar = this.avatars.get(state.userId);
- avatar && avatar.withModel && !avatar.isLoading && this.updateAvatarPositionAndRotation(state)
- }
- if (!isMainAvatar && state.event && state.event.type === SyncEventType.Rotate) {
- const avatar = this.avatars.get(state.userId);
- avatar.statusSyncQueue.append({
- type: QueueType.Rotate,
- action: () => avatar.statusSync(state)
- })
- }
- })
- }
- calculatePriority(e, t) {
- var n;
- return e === this._room.userId ? EAvatarRelationRank.Self : (n = this._room.options.firends) != null && n.includes(e) ? EAvatarRelationRank.Friend : EAvatarRelationRank.Stranger
- }
- updateAvatarPositionAndRotation(userState)
- {
- if (userState.playerState && userState.playerState.player)
- {
- let {position, angle} = userState.playerState.player;
- const avatar = this.avatars.get(userState.userId);
- if (!avatar) return;
- position = positionPrecisionProtect(position)
- angle = rotationPrecisionProtect(angle)
- avatar.isSelf && !this._room.networkController.rtcp.workers.inPanoMode && (avatar.setPosition(position), avatar.setRotation(angle))
- userState.event && (userState.event.points.length || 0) > 1 && !avatar.isSelf && avatar.statusSyncQueue.append({
- type: QueueType.Move,
- action: () => avatar.statusSync(userState)
- })
- if (userState.renderInfo && avatar.isSelf) {
- const {isMoving, isRotating} = userState.renderInfo;
- this._updateAvatarMovingStatus({
- id: userState.userId,
- isMoving: !!isMoving,
- isRotating: !!isRotating
- })
- }
- }
- }
- async addAvatar({
- userId, isHost, avatarPosition, avatarId, avatarRotation, nickname, avatarComponents=[], priority, group=AvatarGroup.Npc,
- avatarScale=DEFAULT_AVATAR_SCALE, extraInfo, prioritySync
- }) {
- const isSelf = userId === this._room.userId;
- let avatar = this.avatars.get(userId);
- if (avatar) return Promise.resolve(avatar);
- avatar = new XverseAvatarManager.subAvatar({
- userId,
- isHost,
- isSelf,
- room: this._room,
- avatarComponents,
- avatarId,
- nickname,
- group
- });
- this.avatars.set(userId, avatar);
- if (!avatar.withModel) {
- avatar.isLoading = !1
- avatar.avatarLoadedHook()
- this._room.emit("avatarChanged", { avatars: this._room.avatars })
- return avatar;
- }
- const avatarData = (await this._room.modelManager.getAvatarModelList()).find(data => data.id === avatarId)
- , startTime = Date.now();
- if (!avatarData) {
- this._room.emit("avatarChanged", { avatars: this._room.avatars })
- this.avatars.delete(userId)
- return Promise.reject(`no such avatar model with id: ${avatarId}`);
- }
- try {
- let b = await avatarComponentsModify(avatarData, avatarComponents);
- b = b.filter(A=>A.type != "pendant");
-
- const assets = await avatarComponentsParser(avatarData, b)
- , xAvatar = await this.xAvatarManager.loadAvatar({
- id: userId,
- avatarType: avatarId,
- priority,
- avatarManager: this.xAvatarManager,
- assets,
- status: {
- avatarPosition,
- avatarRotation,
- avatarScale
- }
- })._timeout(8e3, new TimeoutError("loadAvatar timeout(8s)"));
- xAvatar.setPickBoxScale(userId === this._room.userId ? 0 : 1);
- avatar.xAvatar = xAvatar
- avatar.setScale(avatarScale)
- avatar.extraInfo = extraInfo
- avatar.priority = priority
- avatar.isLoading = !1
- avatar.prioritySync = !!prioritySync
- avatar._playAnimation("Idle", !0, !0)
- avatar.avatarLoadedHook()
- this._room.emit("avatarChanged", { avatars: this._room.avatars })
- nickname && avatar._setNickname(nickname)
- userId === this._room.userId && (
- logger.infoAndReportMeasurement({
- metric: "avatarLoadDuration",
- startTime,
- group: "costs"
- }),
- logger.infoAndReportMeasurement({
- metric: "avatarLoadAt",
- startTime: this._room._startTime,
- group: "costs"
- })
- )
-
- return avatar
- } catch (e) {
- return avatar.isLoading = !1,
- this._room.emit("avatarChanged", { avatars: this._room.avatars }),
- logger.error(e),
- Promise.reject(e)
- }
- }
- removeAvatar(userId, t=!1) {
- const avatar = this.avatars.get(userId);
- if (!!avatar) {
- if (avatar.removeWhenDisconnected || t) {
- avatar.xAvatar && this.xAvatarManager.deleteAvatar(avatar.xAvatar),
- this.avatars.delete(userId),
- this._room.emit("avatarChanged", {
- avatars: this._room.avatars
- });
- return
- }
- avatar.setConnectionStatus(!0)
- }
- }
- clearOtherUsers() {
- this.avatars.forEach(e=>{
- !e.isSelf && e.group === AvatarGroup.User && this.removeAvatar(e.userId)
- }
- )
- }
- async _updateAvatarMovingStatus(e) {
- const {id: t, isMoving: r, isRotating: n} = e
- , o = this.avatars.get(t);
- if (!!o) {
- if (o.isRotating !== n) {
- o.isRotating = n;
- let a = "Idle";
- n && (a = "Walking",
- o.motionType === MotionType.Run && (a = "Running")),
- o._playAnimation(a, !0, !0),
- logger.infoAndReportMeasurement({
- startTime: Date.now(),
- value: 0,
- metric: n ? "userAvatarStartRotating" : "userAvatarStopRotating",
- extra: {
- motionType: o.motionType,
- moveToExtra: this._room.moveToExtra
- }
- })
- }
- if (o.isMoving !== r) {
- o.isMoving = r;
- let a = "Idle";
- r && (a = "Walking",
- o.motionType === MotionType.Run && (a = "Running")),
- r ? (o.avatarStartMovingHook(),
- o.emit("startMoving", {
- target: o,
- extra: this._room.moveToExtra
- })) : (o.avatarStopMovingHook(),
- o.emit("stopMoving", {
- target: o,
- extra: this._room.moveToExtra
- })),
- o._playAnimation(a, !0, !0),
- logger.infoAndReportMeasurement({
- startTime: Date.now(),
- value: 0,
- metric: r ? "userAvatarStartMoving" : "userAvatarStopMoving",
- extra: {
- motionType: o.motionType,
- moveToExtra: this._room.moveToExtra
- }
- })
- }
- }
- }
- _usersStatistics() {
- this.on("userAvatarLoaded", ()=>{
- window.setInterval(()=>{
- const e = this._room.avatars.filter(r=>r.group === AvatarGroup.User).length || 0
- , t = this._room.avatars.filter(r=>r.group === AvatarGroup.User && r.isRender).length || 0;
- this._room.stats.assign({
- userNum: e,
- syncUserNum: this.syncAvatarsLength,
- renderedUserNum: t
- })
- }
- , 3e3)
- }
- )
- }
- };
- E(XverseAvatarManager, "subAvatar", XverseAvatar);
|