XverseAvatar.js 19 KB

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