XverseAvatar.js 19 KB

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