XverseAvatar.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. import util from "./util.js"
  2. import InternalError from "./error/InternalError.js"
  3. import EAvatarRelationRank from "./enum/EAvatarRelationRank.js"
  4. import AvatarGroup from "./enum/AvatarGroup.js"
  5. import MotionType from "./enum/MotionType.js"
  6. import Queue from "./Queue.js"
  7. import Logger from "./Logger.js"
  8. const logger = new Logger('xverse-avatar')
  9. export default class XverseAvatar extends EventEmitter {
  10. constructor({userId: e, isHost: t, room: r, avatarId: n, isSelf: o, group: a=AvatarGroup.Npc}) {
  11. super();
  12. E(this, "xAvatar");
  13. E(this, "_isHost", !1);
  14. E(this, "_room");
  15. E(this, "_withModel", !1);
  16. E(this, "_userId");
  17. E(this, "group", AvatarGroup.User);
  18. E(this, "state", "idle");
  19. E(this, "isLoading", !0);
  20. E(this, "_isMoving", !1);
  21. E(this, "_isRotating", !1);
  22. E(this, "_failed", !1);
  23. E(this, "disconnected", !1);
  24. E(this, "_avatarId");
  25. E(this, "prioritySync", !1);
  26. E(this, "priority", EAvatarRelationRank.Stranger);
  27. E(this, "_avatarModel");
  28. E(this, "_motionType", MotionType.Walk);
  29. E(this, "isSelf", !1);
  30. E(this, "_lastAnimTraceId", "");
  31. E(this, "statusSyncQueue", new Queue);
  32. E(this, "extraInfo", {});
  33. E(this, "setPosition", e=>{
  34. var t;
  35. !this._room.signal.isUpdatedYUV || (t = this.xAvatar) == null || t.setPosition(positionPrecisionProtect(e))
  36. }
  37. );
  38. E(this, "setRotation", e=>{
  39. var t;
  40. !this._room.signal.isUpdatedYUV || (t = this.xAvatar) == null || t.setRotation(rotationPrecisionProtect(e))
  41. }
  42. );
  43. E(this, "stopAnimation", ()=>{
  44. var e, t;
  45. (t = (e = this.xAvatar) == null ? void 0 : e.controller) == null || t.stopAnimation()
  46. }
  47. );
  48. E(this, "_playAnimation", async(e,t=!0,r=!1)=>{
  49. var o;
  50. if (!this._room.signal.isUpdatedYUV)
  51. return;
  52. if (this.state !== "idle" && !r)
  53. return logger.debug("_playAnimation", "state is not idle"),
  54. Promise.resolve("_playAnimation, state is not idle");
  55. const n = Date.now();
  56. try {
  57. if (!((o = this.xAvatar) != null && o.controller))
  58. return Promise.reject(new InternalError(`[avatar: ${this.userId}] Play animation failed: ${e}, no controller`));
  59. this.isSelf && setTimeout(()=>{
  60. logger.infoAndReportMeasurement({
  61. tag: e,
  62. startTime: n,
  63. value: 0,
  64. metric: "playAnimationStart"
  65. })
  66. }
  67. );
  68. const a = util.uuid();
  69. this._lastAnimTraceId = a,
  70. await this.xAvatar.controller.playAnimation(e, t),
  71. a === this._lastAnimTraceId && !this.isMoving && !t && e !== "Idle" && this.xAvatar.controller.playAnimation("Idle", t).catch(s=>{
  72. logger.error(`[avatar: ${this.userId}] Play animation failed [force idle]`, s)
  73. }
  74. ),
  75. this.isSelf && logger.infoAndReportMeasurement({
  76. tag: e,
  77. startTime: n,
  78. extra: {
  79. loop: t
  80. },
  81. metric: "playAnimationEnd"
  82. })
  83. } catch (a) {
  84. return logger.error(`[avatar: ${this.userId}] Play animation failed: ${e}`, a),
  85. this.isSelf && logger.infoAndReportMeasurement({
  86. tag: e,
  87. startTime: n,
  88. metric: "playAnimationEnd",
  89. error: a,
  90. extra: {
  91. loop: t
  92. }
  93. }),
  94. Promise.reject(a)
  95. }
  96. }
  97. );
  98. E(this, "changeComponents", async e=>{
  99. const {mode: t, endAnimation: r=""} = e || {}
  100. , n = JSON.parse(JSON.stringify(e.avatarComponents));
  101. let o = avatarComponentsValidate(n, this._avatarModel);
  102. return !ChangeComponentsMode[t] && !o && (o = new ParamError(`changeComponents failed, mode: ${t} is invalid`)),
  103. o ? (logger.error(o),
  104. Promise.reject(o)) : this._changeComponents({
  105. avatarComponents: n,
  106. mode: t,
  107. endAnimation: r
  108. }).then(()=>{
  109. this.isSelf && t !== ChangeComponentsMode.Preview && this.avatarComponentsSync(this.avatarComponents)
  110. }
  111. )
  112. }
  113. );
  114. E(this, "_changeComponents", async e=>{
  115. var o;
  116. const {avatarComponents: t=[], mode: r} = e || {}
  117. , n = Date.now();
  118. try {
  119. if (!this.xAvatar)
  120. return Promise.reject(new InternalError("changeComponents failed, without instance: xAvatar"));
  121. const a = await avatarComponentsModify(this._avatarModel, t)
  122. , s = []
  123. , l = await avatarComponentsParser(this._avatarModel, a, this.avatarComponents);
  124. if (l.length === 0)
  125. return this.avatarComponents;
  126. await this.beforeChangeComponentsHook(e);
  127. for (const u of l) {
  128. const {id: c, type: h, url: f, suitComb: d} = u;
  129. s.push((o = this.xAvatar) == null ? void 0 : o.addComponent(c, h, f, d))
  130. }
  131. return await Promise.all(s),
  132. this.emit("componentsChanged", {
  133. components: this.avatarComponents,
  134. mode: r
  135. }),
  136. this.isSelf && logger.infoAndReportMeasurement({
  137. tag: "changeComponents",
  138. startTime: n,
  139. metric: "changeComponents",
  140. extra: {
  141. inputComponents: t,
  142. finalComponents: this.avatarComponents,
  143. mode: ChangeComponentsMode[r]
  144. }
  145. }),
  146. this.avatarComponents
  147. } catch (a) {
  148. return this.isSelf && logger.infoAndReportMeasurement({
  149. tag: "changeComponents",
  150. startTime: n,
  151. metric: "changeComponents",
  152. error: a,
  153. extra: {
  154. inputComponents: t,
  155. finalComponents: this.avatarComponents,
  156. mode: ChangeComponentsMode[r]
  157. }
  158. }),
  159. Promise.reject(a)
  160. }
  161. }
  162. );
  163. E(this, "avatarComponentsSync", e=>{
  164. e = e.map(t=>({
  165. type: t.type,
  166. id: t.id
  167. })),
  168. this._room.actionsHandler.avatarComponentsSync(e)
  169. }
  170. );
  171. E(this, "hide", ()=>{
  172. var e;
  173. if ((e = this.xAvatar) != null && e.hide())
  174. return Promise.resolve(`avatar: ${this.userId} hide success`);
  175. {
  176. const t = `avatar: ${this.userId} hide failed ${!this.xAvatar && "without instance: xAvatar"}`;
  177. return logger.warn(t),
  178. Promise.reject(t)
  179. }
  180. }
  181. );
  182. E(this, "show", ()=>{
  183. var e;
  184. if ((e = this.xAvatar) != null && e.show())
  185. return Promise.resolve(`avatar: ${this.userId} show success`);
  186. {
  187. const t = `avatar: ${this.userId} show failed ${!this.xAvatar && "without instance: xAvatar"}`;
  188. return logger.warn(t),
  189. Promise.reject(t)
  190. }
  191. }
  192. );
  193. E(this, "sayTimer");
  194. this._userId = e,
  195. this._room = r,
  196. this.isSelf = o || !1,
  197. this._withModel = !!n,
  198. this._isHost = t || !1,
  199. this._avatarId = n,
  200. this.group = a,
  201. this._room.modelManager.getAvatarModelList().then(s=>{
  202. const l = s.find(u=>u.id === n);
  203. l && (this._avatarModel = l)
  204. }
  205. )
  206. }
  207. get avatarId() {
  208. return this._avatarId
  209. }
  210. get isRender() {
  211. var e;
  212. return !!((e = this.xAvatar) != null && e.isRender)
  213. }
  214. get isHidden() {
  215. var e;
  216. return !!((e = this.xAvatar) != null && e.isHide)
  217. }
  218. get motionType() {
  219. return this._motionType
  220. }
  221. set motionType(e) {
  222. this._motionType = e
  223. }
  224. get nickname() {
  225. var e;
  226. return (e = this.xAvatar) == null ? void 0 : e.nickName
  227. }
  228. get words() {
  229. var e;
  230. return (e = this.xAvatar) == null ? void 0 : e.words
  231. }
  232. get isHost() {
  233. return this._isHost
  234. }
  235. get failed() {
  236. return this._failed
  237. }
  238. get scale() {
  239. var e;
  240. return (e = this.xAvatar) == null ? void 0 : e.scale
  241. }
  242. get animations() {
  243. var e;
  244. return !this.xAvatar || !this.xAvatar.controller ? [] : ((e = this.xAvatar) == null ? void 0 : e.getAvaliableAnimations()) || []
  245. }
  246. get position() {
  247. var e;
  248. return (e = this.xAvatar) == null ? void 0 : e.position
  249. }
  250. get rotation() {
  251. var e;
  252. return (e = this.xAvatar) == null ? void 0 : e.rotation
  253. }
  254. get pose() {
  255. return {
  256. position: this.position,
  257. angle: this.rotation
  258. }
  259. }
  260. get id() {
  261. return this.userId
  262. }
  263. get isMoving() {
  264. return this._isMoving
  265. }
  266. set isMoving(e) {
  267. this._isMoving = e,
  268. this.state = e ? "moving" : "idle"
  269. }
  270. get isRotating() {
  271. return this._isRotating
  272. }
  273. set isRotating(e) {
  274. this._isRotating = e,
  275. this.state = e ? "rotating" : "idle"
  276. }
  277. get withModel() {
  278. return this._withModel
  279. }
  280. get avatarComponents() {
  281. var e;
  282. return JSON.parse(JSON.stringify(((e = this.xAvatar) == null ? void 0 : e.clothesList) || []))
  283. }
  284. get userId() {
  285. return this._userId
  286. }
  287. get removeWhenDisconnected() {
  288. return this.extraInfo && this.extraInfo.removeWhenDisconnected !== void 0 ? this.extraInfo.removeWhenDisconnected : !0
  289. }
  290. setConnectionStatus(e) {
  291. this.disconnected !== e && (this.disconnected = e,
  292. e ? this.emit("disconnected") : this.emit("reconnected"),
  293. logger.warn(`avatar ${this.userId} status changed, disconnected:`, e))
  294. }
  295. setScale(e) {
  296. var t;
  297. (t = this.xAvatar) == null || t.setScale(e > 0 ? e : 1)
  298. }
  299. async playAnimation(e) {
  300. const {animationName: t, loop: r, extra: n} = e || {};
  301. if (this.isSelf) {
  302. if (this.isMoving)
  303. try {
  304. await this.stopMoving()
  305. } catch (a) {
  306. return logger.error(`stopMoving error before playAnimation ${t}`, a),
  307. Promise.reject(`stopMoving error before playAnimation ${t}`)
  308. }
  309. const o = {
  310. info: {
  311. userId: this.userId,
  312. animation: t,
  313. loop: r,
  314. extra: encodeURIComponent(n || "")
  315. },
  316. broadcastType: CoreBroadcastType.PlayAnimation
  317. };
  318. this._room.avatarManager.broadcast.broadcast({
  319. data: o
  320. })
  321. }
  322. return this.emit("animationStart", {
  323. animationName: t,
  324. extra: safeDecodeURIComponent(n || "")
  325. }),
  326. this._playAnimation(t, r).then(()=>{
  327. this.emit("animationEnd", {
  328. animationName: t,
  329. extra: safeDecodeURIComponent(n || "")
  330. })
  331. }
  332. )
  333. }
  334. async beforeChangeComponentsHook(e) {}
  335. turnTo(e) {
  336. if (this._room.viewMode === "observer") {
  337. this._room.sceneManager.cameraComponent.MainCamera.setTarget(ue4Position2Xverse(e.point));
  338. return
  339. }
  340. return this._room.actionsHandler.turnTo(e).then(()=>{
  341. this.emit("viewChanged", {
  342. extra: (e == null ? void 0 : e.extra) || ""
  343. })
  344. }
  345. )
  346. }
  347. async moveTo(e) {
  348. const {point: t, extra: r=""} = e || {};
  349. if (!this.position)
  350. return Promise.reject(new ParamError("avatar position is empty"));
  351. if (typeof r != "string" || typeof r == "string" && r.length > 64) {
  352. const a = "extra shoud be string which length less than 64";
  353. return logger.warn(a),
  354. Promise.reject(new ParamError(a))
  355. }
  356. const o = util.getDistance(this.position, t) / 100 > 100 ? MotionType.Run : MotionType.Walk;
  357. return this._room.actionsHandler.moveTo({
  358. point: t,
  359. motionType: o,
  360. extra: r
  361. })
  362. }
  363. async stopMoving() {
  364. return this._room.actionsHandler.stopMoving()
  365. }
  366. rotateTo(e) {
  367. return this._room.actionsHandler.rotateTo(e)
  368. }
  369. setRayCast(e) {
  370. this.xAvatar && (this.xAvatar.isRayCastEnable = e)
  371. }
  372. say(e, t) {
  373. if (this.sayTimer && window.clearTimeout(this.sayTimer),
  374. !this.xAvatar) {
  375. logger.error("say failed, without instance: xAvatar");
  376. return
  377. }
  378. this.xAvatar.say(e, {
  379. scale: this.xAvatar.scale,
  380. isUser: this.group === AvatarGroup.User
  381. }),
  382. !(t === void 0 || t <= 0) && (this.sayTimer = window.setTimeout(()=>{
  383. this.silent()
  384. }
  385. , t))
  386. }
  387. silent() {
  388. var e;
  389. if (!this.xAvatar) {
  390. logger.error("silent failed, without instance: xAvatar");
  391. return
  392. }
  393. (e = this.xAvatar) == null || e.silent()
  394. }
  395. setMotionType({type: e=MotionType.Walk}) {
  396. return this.motionType === e ? Promise.resolve() : this._room.actionsHandler.setMotionType(e).then(()=>{
  397. this._motionType = e
  398. }
  399. )
  400. }
  401. setNickname(e) {
  402. return this._room.actionsHandler.setNickName(encodeURIComponent(e))
  403. }
  404. _setNickname(e) {
  405. var r, n;
  406. if (!e)
  407. return;
  408. const t = safeDecodeURIComponent(e);
  409. ((r = this.xAvatar) == null ? void 0 : r.nickName) !== t && (this.isSelf && (this._room.updateCurrentNetworkOptions({
  410. nickname: t
  411. }),
  412. this._room.options.nickname = t),
  413. (n = this.xAvatar) == null || n.setNickName(t, {
  414. scale: this.xAvatar.scale
  415. }))
  416. }
  417. _move(e) {
  418. var s;
  419. const {start: t, end: r, walkSpeed: n, moveAnimation: o="Walking", inter: a=[]} = e || {};
  420. return (s = this.xAvatar) == null ? void 0 : s.move(t, r, n, o, a)
  421. }
  422. setPickBoxScale(e=1) {
  423. return this.xAvatar ? (this.xAvatar.setPickBoxScale(e),
  424. !0) : (logger.error("setPickBoxScale failed, without instance: xAvatar"),
  425. !1)
  426. }
  427. transfer(e) {
  428. const {player: t, camera: r, areaName: n, attitude: o, pathName: a} = e;
  429. return this._room.actionsHandler.transfer({
  430. renderType: RenderType.RotationVideo,
  431. player: t,
  432. camera: r,
  433. areaName: n,
  434. attitude: o,
  435. pathName: a,
  436. tag: "transfer"
  437. })
  438. }
  439. avatarLoadedHook() {}
  440. avatarStartMovingHook() {}
  441. avatarStopMovingHook() {}
  442. async statusSync(e) {
  443. var t, r, n;
  444. try {
  445. if ((t = e.event) != null && t.rotateEvent) {
  446. const {angle: o, speed: a} = e.event.rotateEvent
  447. , s = this.motionType === MotionType.Run ? "Running" : "Walking";
  448. this.rotation && (this.rotation.yaw = this.rotation.yaw % 360,
  449. o.yaw - this.rotation.yaw > 180 && (o.yaw = 180 - o.yaw),
  450. this.isRotating = !0,
  451. await this.xAvatar.rotateTo(o, this.rotation, s).then(()=>{
  452. this._playAnimation("Idle", !0),
  453. this.isRotating = !1
  454. }
  455. ))
  456. }
  457. if (e.event && (((r = e.event) == null ? void 0 : r.points.length) || 0) > 1 && !this.isSelf) {
  458. this.isMoving = !0,
  459. e.playerState.attitude && (this._motionType = e.playerState.attitude);
  460. const o = this.motionType === MotionType.Run ? "Running" : "Walking"
  461. , a = this._room.skin.routeList.find(l=>l.areaName === this._room.currentState.areaName)
  462. , s = ((a == null ? void 0 : a.step) || 7.5) * 30 * (25 / 30);
  463. this.position && await this._move({
  464. start: this.position,
  465. end: e.event.points[e.event.points.length - 1],
  466. walkSpeed: s,
  467. moveAnimation: o,
  468. inter: (n = e.event) == null ? void 0 : n.points.slice(0, -1)
  469. }).then(()=>{
  470. this.isMoving = !1
  471. }
  472. )
  473. }
  474. } catch {
  475. return
  476. }
  477. }
  478. }