XverseAvatarManager.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. import CoreBroadcastType from "./enum/CoreBroadcastType.js"
  2. import AvatarGroup from "./enum/AvatarGroup.js"
  3. import Broadcast from "./Broadcast.js"
  4. import {avatarLoader} from "./XAvatarLoader.js"
  5. import SyncEventType from "./enum/SyncEventType.js"
  6. import GetStateTypes from "./enum/GetStateTypes.js"
  7. import EAvatarRelationRank from "./enum/EAvatarRelationRank.js"
  8. import Person from "./enum/Person.js"
  9. import XverseAvatar from "./XverseAvatar.js"
  10. import MotionType from "./enum/MotionType.js"
  11. import TimeoutError from "./error/TimeoutError.js"
  12. import Logger from "./Logger.js"
  13. const logger = new Logger('xverse-avatar-manager')
  14. export default class XverseAvatarManager extends EventEmitter {
  15. constructor(e) {
  16. super();
  17. this.xAvatarManager = null
  18. this.avatars = new Map
  19. this.syncAvatarsLength = 0
  20. this._room = e;
  21. this._usersStatistics();
  22. this.broadcast = this.setupBroadcast();
  23. e.on("skinChanged", ()=>{
  24. this.avatars.forEach(t=>{
  25. t.disconnected && this.removeAvatar(t.userId, !0)
  26. }
  27. )
  28. }
  29. )
  30. }
  31. setupBroadcast() {
  32. return new Broadcast(this._room,async e=>{
  33. const {broadcastType: t, info: r} = e;
  34. if (t !== CoreBroadcastType.PlayAnimation)
  35. return;
  36. const {userId: n, animation: o, extra: a, loop: s=!1} = r
  37. , l = this.avatars.get(n);
  38. l && !l.isSelf && (l.emit("animationStart", {
  39. animationName: o,
  40. extra: decodeURIComponent(a)
  41. }),
  42. await (l == null ? void 0 : l._playAnimation(o, s)),
  43. l.emit("animationEnd", {
  44. animationName: o,
  45. extra: decodeURIComponent(a)
  46. }))
  47. }
  48. )
  49. }
  50. hideAll(e=!0) {
  51. this.xAvatarManager.hideAll(e)
  52. }
  53. showAll(e=!0) {
  54. this.xAvatarManager.showAll(e)
  55. }
  56. async init() {
  57. this.xAvatarManager = this._room.sceneManager.avatarComponent;
  58. try {
  59. const e = await this._room.modelManager.getApplicationConfig()
  60. , {avatars: t} = e;
  61. if (t) {
  62. await avatarLoader.parse(this._room.sceneManager, t);
  63. return
  64. }
  65. return Promise.reject("cannot find avatar config list")
  66. } catch (e) {
  67. return logger.error(e),
  68. Promise.reject("avatar mananger init error!")
  69. }
  70. }
  71. async handleAvatar(e) {
  72. var r;
  73. if (this._room.viewMode === "simple" || !this._room.joined || !e.newUserStates)
  74. return;
  75. let t = e.newUserStates;
  76. if (((r = this._room._userAvatar) == null ? void 0 : r.isMoving) && this._room._userAvatar.motionType === MotionType.Run) {
  77. const n = t.filter(a=>a.userId === this._room.userId)
  78. , o = t.filter(a=>a.userId !== this._room.userId).slice(0, 2);
  79. t = n.concat(o)
  80. }
  81. if (e.getStateType === GetStateTypes.Event) {
  82. this.syncAvatarsLength = (t || []).length;
  83. const n = this._room.avatars.filter(s=>s.group == AvatarGroup.User);
  84. n.filter(s=>!(t != null && t.find(l=>l.userId == s.userId))).forEach(s=>{
  85. this.removeAvatar(s.userId)
  86. }
  87. );
  88. const a = t.filter(s=>!n.find(l=>l.userId == s.userId));
  89. this._handleAvatar(a)
  90. }
  91. this._handleAvatar(t)
  92. }
  93. async _handleAvatar(e) {
  94. e == null || e.forEach(t=>{
  95. var n, o, a, s, l, u, c, h, f;
  96. const r = this._room.userId === t.userId;
  97. if (((n = t.event) == null ? void 0 : n.type) === SyncEventType.ET_RemoveVisitor) {
  98. const d = (a = (o = t.event) == null ? void 0 : o.removeVisitorEvent) == null ? void 0 : a.removeVisitorEvent
  99. , _ = JSON.parse(safeDecodeURIComponent(((l = (s = t.event) == null ? void 0 : s.removeVisitorEvent) == null ? void 0 : l.extraInfo) || ""))
  100. , {code: g, msg: m} = _;
  101. d === RemoveVisitorType.RVT_ChangeToObserver ? this._room.audienceViewModeHook() : d === RemoveVisitorType.RVT_MoveOutOfTheRoom && this._room.leave(),
  102. this._room.emit("visitorStatusChanged", {
  103. code: g,
  104. msg: m
  105. })
  106. }
  107. if (t.event && [SyncEventType.Appear, SyncEventType.Reset].includes(t.event.type) || !t.event) {
  108. let d = this.avatars.get(t.userId);
  109. t.playerState.avatarId && (d == null ? void 0 : d.avatarId) !== t.playerState.avatarId && (d = void 0,this.removeAvatar(t.userId));
  110. if (d) {
  111. if (d.disconnected && d.setConnectionStatus(!1),
  112. (u = t.event) != null && u.id && this._room.actionsHandler.confirmEvent(t.event.id),
  113. t.playerState.nickName && (d == null || d._setNickname(t.playerState.nickName)),
  114. t.playerState.avatarComponents && !d.isSelf && d.xAvatar) {
  115. const _ = safeParseComponents(t.playerState.avatarComponents);
  116. d._changeComponents({
  117. avatarComponents: _,
  118. mode: ChangeComponentsMode.Preview
  119. })
  120. }
  121. } else {
  122. const {position: _, angle: g} = t.playerState.player
  123. , m = t.playerState.avatarId
  124. , v = t.playerState.prioritySync
  125. , y = safelyJsonParse(t.playerState.extra);
  126. if (!m)
  127. return;
  128. const b = safeParseComponents(t.playerState.avatarComponents)
  129. , T = safeDecodeURIComponent(t.playerState.nickName)
  130. , C = this.calculatePriority(t.userId, y);
  131. this.addAvatar({
  132. userId: t.userId,
  133. isHost: t.playerState.isHost,
  134. nickname: T,
  135. avatarPosition: _,
  136. avatarRotation: g,
  137. avatarScale: t.playerState.avatarSize,
  138. avatarId: m,
  139. avatarComponents: t.playerState.person === Person.First ? [] : b,
  140. priority: C,
  141. group: AvatarGroup.User,
  142. prioritySync: v,
  143. extraInfo: y
  144. }).then(()=>{
  145. var A;
  146. (A = t.event) != null && A.id && this._room.actionsHandler.confirmEvent(t.event.id),
  147. this.updateAvatarPositionAndRotation(t),
  148. r && (this.xAvatarManager.setMainAvatar(t.userId),
  149. this._room.emit("userAvatarLoaded"),
  150. logger.info("userAvatarLoaded"))
  151. }
  152. ).catch(A=>{
  153. r && (this.xAvatarManager.setMainAvatar(t.userId),
  154. this._room.emit("userAvatarFailed", {
  155. error: A
  156. }),
  157. logger.error("userAvatarFailed", A))
  158. }
  159. )
  160. }
  161. }
  162. if (t.event && SyncEventType.Disappear === t.event.type && ((c = t == null ? void 0 : t.event) != null && c.id && this._room.actionsHandler.confirmEvent(t.event.id),
  163. this.removeAvatar(t.userId)),
  164. t.event && [SyncEventType.Move, SyncEventType.ChangeRenderInfo].includes(t.event.type) || !t.event) {
  165. (h = t == null ? void 0 : t.event) != null && h.id && this._room.actionsHandler.confirmEvent(t.event.id);
  166. const d = this.avatars.get(t.userId);
  167. d && d.withModel && !d.isLoading && this.updateAvatarPositionAndRotation(t)
  168. }
  169. if (!r && ((f = t.event) == null ? void 0 : f.type) === SyncEventType.Rotate) {
  170. const d = this.avatars.get(t.userId);
  171. d.statusSyncQueue.append({
  172. type: QueueType.Rotate,
  173. action: ()=>d.statusSync(t)
  174. })
  175. }
  176. }
  177. )
  178. }
  179. calculatePriority(e, t) {
  180. var n;
  181. return e === this._room.userId ? EAvatarRelationRank.Self : (n = this._room.options.firends) != null && n.includes(e) ? EAvatarRelationRank.Friend : EAvatarRelationRank.Stranger
  182. }
  183. updateAvatarPositionAndRotation(e) {
  184. var t, r;
  185. if ((t = e == null ? void 0 : e.playerState) != null && t.player) {
  186. let {position: n, angle: o} = e.playerState.player;
  187. const a = this.avatars.get(e.userId);
  188. if (!a)
  189. return;
  190. if (n = positionPrecisionProtect(n),
  191. o = rotationPrecisionProtect(o),
  192. a.isSelf && !this._room.networkController.rtcp.workers.inPanoMode && (a.setPosition(n),
  193. a.setRotation(o)),
  194. e.event && (((r = e.event) == null ? void 0 : r.points.length) || 0) > 1 && !a.isSelf && a.statusSyncQueue.append({
  195. type: QueueType.Move,
  196. action: ()=>a.statusSync(e)
  197. }),
  198. e.renderInfo && a.isSelf) {
  199. const {isMoving: s, isRotating: l} = e.renderInfo;
  200. this._updateAvatarMovingStatus({
  201. id: e.userId,
  202. isMoving: !!s,
  203. isRotating: !!l
  204. })
  205. }
  206. }
  207. }
  208. async addAvatar(e) {
  209. const {userId: t, isHost: r, avatarPosition: n, avatarId: o, avatarRotation: a, nickname: s, avatarComponents: l=[], priority: u, group: c=AvatarGroup.Npc, avatarScale: h=DEFAULT_AVATAR_SCALE, extraInfo: f, prioritySync: d} = e
  210. , _ = t === this._room.userId;
  211. let g = this.avatars.get(t);
  212. if (g)
  213. {
  214. return Promise.resolve(g);
  215. }
  216. g = new XverseAvatarManager.subAvatar({
  217. userId: t,
  218. isHost: r,
  219. isSelf: _,
  220. room: this._room,
  221. avatarComponents: l,
  222. avatarId: o,
  223. nickname: s,
  224. group: c
  225. });
  226. this.avatars.set(t, g);
  227. if (!g.withModel)
  228. return g.isLoading = !1,
  229. g.avatarLoadedHook(),
  230. this._room.emit("avatarChanged", {
  231. avatars: this._room.avatars
  232. }),
  233. g;
  234. const v = (await this._room.modelManager.getAvatarModelList()).find(b=>b.id === o)
  235. , y = Date.now();
  236. if (!v)
  237. return this._room.emit("avatarChanged", {
  238. avatars: this._room.avatars
  239. }),
  240. this.avatars.delete(t),
  241. Promise.reject(`no such avatar model with id: ${o}`);
  242. try {
  243. let b = await avatarComponentsModify(v, l);
  244. b = b.filter(A=>A.type != "pendant");
  245. const T = await avatarComponentsParser(v, b)
  246. , C = await this.xAvatarManager.loadAvatar({
  247. id: t,
  248. avatarType: o,
  249. priority: u,
  250. avatarManager: this.xAvatarManager,
  251. assets: T,
  252. status: {
  253. avatarPosition: n,
  254. avatarRotation: a,
  255. avatarScale: h
  256. }
  257. })._timeout(8e3, new TimeoutError("loadAvatar timeout(8s)"));
  258. return C.setPickBoxScale(t === this._room.userId ? 0 : 1),
  259. g.xAvatar = C,
  260. g.setScale(h),
  261. g.extraInfo = f,
  262. g.priority = u,
  263. g.isLoading = !1,
  264. g.prioritySync = !!d,
  265. g._playAnimation("Idle", !0, !0),
  266. g.avatarLoadedHook(),
  267. this._room.emit("avatarChanged", {
  268. avatars: this._room.avatars
  269. }),
  270. s && g._setNickname(s),
  271. t === this._room.userId && (logger.infoAndReportMeasurement({
  272. metric: "avatarLoadDuration",
  273. startTime: y,
  274. group: "costs"
  275. }),
  276. logger.infoAndReportMeasurement({
  277. metric: "avatarLoadAt",
  278. startTime: this._room._startTime,
  279. group: "costs"
  280. })),
  281. g
  282. } catch (b) {
  283. return g.isLoading = !1,
  284. this._room.emit("avatarChanged", {
  285. avatars: this._room.avatars
  286. }),
  287. logger.error(b),
  288. Promise.reject(b)
  289. }
  290. }
  291. removeAvatar(e, t=!1) {
  292. const r = this.avatars.get(e);
  293. if (!!r) {
  294. if (r.removeWhenDisconnected || t) {
  295. r.xAvatar && this.xAvatarManager.deleteAvatar(r.xAvatar),
  296. this.avatars.delete(e),
  297. this._room.emit("avatarChanged", {
  298. avatars: this._room.avatars
  299. });
  300. return
  301. }
  302. r.setConnectionStatus(!0)
  303. }
  304. }
  305. clearOtherUsers() {
  306. this.avatars.forEach(e=>{
  307. !e.isSelf && e.group === AvatarGroup.User && this.removeAvatar(e.userId)
  308. }
  309. )
  310. }
  311. async _updateAvatarMovingStatus(e) {
  312. const {id: t, isMoving: r, isRotating: n} = e
  313. , o = this.avatars.get(t);
  314. if (!!o) {
  315. if (o.isRotating !== n) {
  316. o.isRotating = n;
  317. let a = "Idle";
  318. n && (a = "Walking",
  319. o.motionType === MotionType.Run && (a = "Running")),
  320. o._playAnimation(a, !0, !0),
  321. logger.infoAndReportMeasurement({
  322. startTime: Date.now(),
  323. value: 0,
  324. metric: n ? "userAvatarStartRotating" : "userAvatarStopRotating",
  325. extra: {
  326. motionType: o.motionType,
  327. moveToExtra: this._room.moveToExtra
  328. }
  329. })
  330. }
  331. if (o.isMoving !== r) {
  332. o.isMoving = r;
  333. let a = "Idle";
  334. r && (a = "Walking",
  335. o.motionType === MotionType.Run && (a = "Running")),
  336. r ? (o.avatarStartMovingHook(),
  337. o.emit("startMoving", {
  338. target: o,
  339. extra: this._room.moveToExtra
  340. })) : (o.avatarStopMovingHook(),
  341. o.emit("stopMoving", {
  342. target: o,
  343. extra: this._room.moveToExtra
  344. })),
  345. o._playAnimation(a, !0, !0),
  346. logger.infoAndReportMeasurement({
  347. startTime: Date.now(),
  348. value: 0,
  349. metric: r ? "userAvatarStartMoving" : "userAvatarStopMoving",
  350. extra: {
  351. motionType: o.motionType,
  352. moveToExtra: this._room.moveToExtra
  353. }
  354. })
  355. }
  356. }
  357. }
  358. _usersStatistics() {
  359. this.on("userAvatarLoaded", ()=>{
  360. window.setInterval(()=>{
  361. const e = this._room.avatars.filter(r=>r.group === AvatarGroup.User).length || 0
  362. , t = this._room.avatars.filter(r=>r.group === AvatarGroup.User && r.isRender).length || 0;
  363. this._room.stats.assign({
  364. userNum: e,
  365. syncUserNum: this.syncAvatarsLength,
  366. renderedUserNum: t
  367. })
  368. }
  369. , 3e3)
  370. }
  371. )
  372. }
  373. };
  374. E(XverseAvatarManager, "subAvatar", XverseAvatar);