123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- import util from "./util.js"
- import InternalError from "./error/InternalError.js"
- import EAvatarRelationRank from "./enum/EAvatarRelationRank.js"
- import AvatarGroup from "./enum/AvatarGroup.js"
- import MotionType from "./enum/MotionType.js"
- import MotionAnimtion from "./enum/MotionAnimtion.js"
- import Queue from "./Queue.js"
- import Logger from "./Logger.js"
- import CoreBroadcastType from "./enum/CoreBroadcastType.js"
- import {tracker} from "./Tracker.js"
- import {xverseAvatarTools} from "./XverseAvatarTools.js"
- import ComponentItemType from "./enum/ComponentItemType.js"
- const logger = new Logger('xverse-avatar')
- export default class XverseAvatar extends EventEmitter {
- constructor({userId: s, isHost: c, room: _, avatarId: b, isSelf: k, group: j=AvatarGroup.Npc}) {
- super();
- this.xAvatar = null;
- this._isHost = !1;
- this._room = null;
- this._withModel = !1;
- this._userId = null;
- this.group = AvatarGroup.User;
- this.state = "idle";
- this.isLoading = !0;
- this._isMoving = !1;
- this._isRotating = !1;
- this._failed = !1;
- this.disconnected = !1;
- this._avatarId = null;
- this.prioritySync = !1;
- this.priority = EAvatarRelationRank.Stranger;
- this.micStatus = 0;
- this._avatarModel = null;
- this._motionType = MotionType.Walk;
- this.isSelf = !1;
- this._lastAnimTraceId = "";
- this.statusSyncQueue = new Queue(this);
- this.extraInfo = {};
- this.attachedEffects = new Set;
- this.currentPathName = "";
- this.setPosition = s=>{
- var c, _;
- !this._room.signal.isUpdatedYUV || (_ = (c = this.xAvatar) == null ? void 0 : c.movementComponent) == null || _.updatePosition(xverseAvatarTools.positionPrecisionProtect(s), !0)
- }
- this.setRotation = s=>{
- var c;
- !this._room.signal.isUpdatedYUV || (c = this.xAvatar) == null || c.setRotation(xverseAvatarTools.rotationPrecisionProtect(s))
- };
- this.stopAnimation = ()=>{
- var s, c;
- (c = (s = this.xAvatar) == null ? void 0 : s.controller) == null || c.stopAnimation()
- };
- this.avatarComponentsSync = s=>{
- s = s.map(c=>({
- type: c.type,
- id: c.id
- })),
- this._room.actionsHandler.avatarComponentsSync(s)
- };
- (this, "hide", ()=>{
- var s;
- if ((s = this.xAvatar) != null && s.hide())
- return Promise.resolve(`avatar: ${this.userId} hide success`);
- {
- const c = `avatar: ${this.userId} hide failed ${!this.xAvatar && "without instance: xAvatar"}`;
- return logger.warn(c),
- Promise.reject(c)
- }
- }
- );
- this.show = async()=>{
- var s;
- return (s = this.xAvatar) == null ? void 0 : s.show()
- };
- this.sayTimer = null;
- this._userId = s,
- this._room = _,
- this.isSelf = k || !1,
- this._withModel = !!b,
- this._isHost = c || !1,
- this._avatarId = b,
- this.group = j,
- this._room.modelManager.getAvatarModel(b).then($=>{
- $ && (this._avatarModel = $)
- }
- ),
- k && this._room.pathManager.currentAttitude && (this._motionType = this._room.pathManager.currentAttitude)
- }
- get avatarId() {
- return this._avatarId
- }
- get isRender() {
- var s;
- return !!((s = this.xAvatar) != null && s.isRender)
- }
- get isHidden() {
- var s;
- return !!((s = this.xAvatar) != null && s.isHide)
- }
- get motionType() {
- return this._motionType
- }
- set motionType(s) {
- this._motionType = s
- }
- get nickname() {
- var s;
- return (s = this.xAvatar) == null ? void 0 : s.nickName
- }
- get words() {
- var s;
- return (s = this.xAvatar) == null ? void 0 : s.words
- }
- get isHost() {
- return this._isHost
- }
- get failed() {
- return this._failed
- }
- get scale() {
- var s;
- return (s = this.xAvatar) == null ? void 0 : s.scale
- }
- get animations() {
- return this.animationList.map(c=>c.name)
- }
- get animationList() {
- const s = this._avatarModel.componentList.find(c=>c.type === ComponentItemType.ANIMATION);
- return s ? s == null ? void 0 : s.unitList : []
- }
- get pandentList() {
- const s = this._avatarModel.componentList.find(c=>c.type === ComponentItemType.PENDANT);
- return s ? s == null ? void 0 : s.unitList : []
- }
- _getAnimationIdByName(s) {
- var _;
- const c = (_ = this.animationList) == null ? void 0 : _.find(b=>b.name === s);
- return c ? c.id : ""
- }
- _getPandentIdByName(s) {
- var _;
- const c = (_ = this.pandentList) == null ? void 0 : _.find(b=>b.name === s);
- return c ? c.id : ""
- }
- get position() {
- var s;
- return (s = this.xAvatar) == null ? void 0 : s.position
- }
- get rotation() {
- var s;
- return (s = this.xAvatar) == null ? void 0 : s.rotation
- }
- get pose() {
- return {
- position: this.position,
- angle: this.rotation
- }
- }
- get id() {
- return this.userId
- }
- get isMoving() {
- return this._isMoving
- }
- set isMoving(s) {
- this._isMoving = s,
- this.state = s ? "moving" : "idle"
- }
- get isRotating() {
- return this._isRotating
- }
- set isRotating(s) {
- this._isRotating = s,
- this.state = s ? "rotating" : "idle"
- }
- get withModel() {
- return this._withModel
- }
- get avatarComponents() {
- var s;
- return JSON.parse(JSON.stringify(((s = this.xAvatar) == null ? void 0 : s.clothesList) || []))
- }
- get userId() {
- return this._userId
- }
- get removeWhenDisconnected() {
- return this.extraInfo && this.extraInfo.removeWhenDisconnected !== void 0 ? this.extraInfo.removeWhenDisconnected : !0
- }
- setConnectionStatus(s) {
- this.disconnected !== s && (this.disconnected = s,
- s ? this.emit("disconnected") : this.emit("reconnected"),
- logger.warn(`avatar ${this.userId} status changed, disconnected:`, s))
- }
- setScale(s) {
- var c;
- this.scale !== s && ((c = this.xAvatar) == null || c.setScale(s > 0 ? s : 1))
- }
- async playAnimation(s) {
- const {animationName: c, loop: _, extra: b, noSync: k=!1} = s || {};
- if (this.isSelf) {
- if (this.isMoving)
- try {
- await this.stopMoving()
- } catch (j) {
- return logger.error(`stopMoving error before playAnimation ${c}`, j),
- Promise.reject(`stopMoving error before playAnimation ${c}`)
- }
- if (!k) {
- const j = {
- info: {
- userId: this.userId,
- animation: c,
- loop: _,
- extra: encodeURIComponent(b || "")
- },
- broadcastType: CoreBroadcastType.PlayAnimation
- };
- this._room.avatarManager.broadcast.broadcast({
- data: j
- })
- }
- }
- return this.isSelf && (this.emit("animationStart", {
- animationName: c,
- extra: safeDecodeURIComponent(b || "")
- }),
- tracker.trackEvent("playAnimation", {
- animation: c
- })),
- this._playAnimation(c, _).then(()=>{
- this.isSelf && this.emit("animationEnd", {
- animationName: c,
- extra: safeDecodeURIComponent(b || "")
- })
- }
- )
- }
- async _playAnimation(s, c=!0, _=!1, b="Idle") {
- var $;
- const k = this._getAnimationIdByName(s);
- if (!this._room.signal.isUpdatedYUV)
- return;
- if (this.state !== "idle" && !_)
- return logger.warn(this.userId, "_playAnimation", s, "failed, state is not idle"),
- Promise.resolve();
- const j = Date.now();
- try {
- if (!(($ = this.xAvatar) != null && $.controller))
- return Promise.reject(new InternalError(`[avatar: ${this.userId}] Play animation failed: ${s}, no controller`));
- this.isSelf && setTimeout(()=>{
- logger.infoAndReportMeasurement({
- tag: s,
- startTime: j,
- value: 0,
- metric: "playAnimationStart"
- })
- }
- );
- const _e = util.uuid();
- if (this._lastAnimTraceId = _e,
- await this.xAvatar.controller.playAnimation(k, c),
- _e === this._lastAnimTraceId && !this.isMoving && !c && s !== b) {
- const et = this._getAnimationIdByName(b);
- this.xAvatar.controller.playAnimation(et, c).catch(tt=>{
- logger.error(`[avatar: ${this.userId}] Play animation failed [force idle]`, tt)
- }
- )
- }
- return this.isSelf && logger.infoAndReportMeasurement({
- tag: s,
- startTime: j,
- extra: {
- loop: c
- },
- metric: "playAnimationEnd"
- }),
- Promise.resolve(_e)
- } catch (_e) {
- return logger.error(`[avatar: ${this.userId}] Play animation failed: ${s}`, _e),
- this.isSelf && logger.infoAndReportMeasurement({
- tag: s,
- startTime: j,
- metric: "playAnimationEnd",
- error: _e,
- extra: {
- loop: c
- }
- }),
- Promise.reject(_e)
- }
- }
- async changeComponents(s) {
- var _e;
- const {mode: c, endAnimation: _=""} = s || {}
- , b = Date.now()
- , k = JSON.parse(JSON.stringify(s.avatarComponents));
- let j = avatarComponentsValidate(k, this._avatarModel);
- const $ = Date.now();
- return (_e = this._room) == null || _e.stats.functionTimeConsumingAdd("avatarComponentsValidate", $ - b),
- !ChangeComponentsMode[c] && !j && (j = new ParamError(`changeComponents failed, mode: ${c} is invalid`)),
- j ? (logger.error(j),
- Promise.reject(j)) : this._changeComponents({
- avatarComponents: k,
- mode: c,
- endAnimation: _
- }).then(()=>{
- this.isSelf && c !== ChangeComponentsMode.Preview && this.avatarComponentsSync(this.avatarComponents)
- }
- )
- }
- async _changeComponents(s) {
- var k;
- const {avatarComponents: c=[], mode: _} = s || {}
- , b = Date.now();
- try {
- if (!this.xAvatar)
- return Promise.reject(new InternalError("changeComponents failed, without instance: xAvatar"));
- const j = await xverseAvatarTools.avatarComponentsModify(this._avatarModel, c, this._room)
- , $ = []
- , _e = await xverseAvatarTools.avatarComponentsParser(this._avatarModel, j, this.avatarComponents, this._room);
- if (_e.length === 0)
- return this.avatarComponents;
- await this.beforeChangeComponentsHook(s);
- for (const et of _e) {
- const {id: tt, type: rt} = et;
- rt !== ComponentItemType.ANIMATION && $.push((k = this.xAvatar) == null ? void 0 : k.addComponent(tt, rt))
- }
- return await Promise.all($),
- this.emit("componentsChanged", {
- components: this.avatarComponents,
- mode: _
- }),
- this.isSelf && (logger.infoAndReportMeasurement({
- tag: "changeComponents",
- startTime: b,
- metric: "changeComponents",
- extra: {
- inputComponents: c,
- finalComponents: this.avatarComponents,
- mode: ChangeComponentsMode[_]
- }
- }),
- tracker.trackEvent("changeComponents", {
- code: Codes.Success,
- components: _e.map(({id: et, type: tt})=>({
- id: et,
- type: tt
- })),
- mode: ChangeComponentsMode[_]
- })),
- this.avatarComponents
- } catch (j) {
- return this.isSelf && (logger.infoAndReportMeasurement({
- tag: "changeComponents",
- startTime: b,
- metric: "changeComponents",
- error: j,
- extra: {
- inputComponents: c,
- finalComponents: this.avatarComponents,
- mode: ChangeComponentsMode[_]
- }
- }),
- tracker.trackEvent("changeComponents", {
- code: -1,
- components: c,
- mode: ChangeComponentsMode[_]
- })),
- Promise.reject(j)
- }
- }
- async beforeChangeComponentsHook(s) {}
- turnTo(s) {
- if (this._room.viewMode === "observer") {
- this._room.sceneManager.cameraComponent.MainCamera.setTarget(ue4Position2Xverse(s.point));
- return
- }
- return this._room.actionsHandler.turnTo(s).then(()=>{
- this.emit("viewChanged", {
- extra: (s == null ? void 0 : s.extra) || ""
- })
- }
- )
- }
- async moveTo(s) {
- const {point: c, extra: _=""} = s || {};
- if (!this.position)
- return Promise.reject(new ParamError("avatar position is empty"));
- if (typeof _ != "string" || typeof _ == "string" && _.length > 64) {
- const j = "extra shoud be string which length less than 64";
- return logger.warn(j),
- Promise.reject(new ParamError(j))
- }
- const k = getDistance(this.position, c) / 100 > 100 ? MotionType.Run : MotionType.Walk;
- return this._room.actionsHandler.moveTo({
- point: c,
- motionType: k,
- extra: _
- })
- }
- async stopMoving() {
- if (!!this.isMoving)
- return this._room.actionsHandler.stopMoving()
- }
- rotateTo(s) {
- return this._room.actionsHandler.rotateTo(s)
- }
- setRayCast(s) {
- this.xAvatar && (this.xAvatar.isRayCastEnable = s)
- }
- say(s, c, _) {
- logger.debug("invoke avatar say", s, c, _);
- let b, k, j, $;
- if (typeof c == "object" ? (b = c.duration,
- k = c.background,
- j = c.fontSize,
- $ = c.fontColor) : typeof c == "number" && (b = c),
- this.sayTimer && window.clearTimeout(this.sayTimer),
- !this.xAvatar) {
- logger.error("say failed, without instance: xAvatar");
- return
- }
- const _e = Object.assign({
- scale: this.xAvatar.scale,
- isUser: this.group === AvatarGroup.User,
- background: k,
- fontsize: j,
- fontcolor: $
- }, _ || {});
- this.xAvatar.say(s, _e),
- !(b === void 0 || b <= 0) && (this.sayTimer = window.setTimeout(()=>{
- this.silent()
- }
- , b))
- }
- silent() {
- var s;
- if (!this.xAvatar) {
- logger.error("silent failed, without instance: xAvatar");
- return
- }
- (s = this.xAvatar) == null || s.silent()
- }
- setNickname(s) {
- return this._room.actionsHandler.setNickName(encodeURIComponent(s))
- }
- _setNickname(s, c={}) {
- var b, k;
- if (!s)
- return;
- const _ = safeDecodeURIComponent(s);
- ((b = this.xAvatar) == null ? void 0 : b.nickName) !== _ && (this.isSelf && (this._room.updateCurrentNetworkOptions({
- nickname: _
- }),
- this._room.options.nickname = _),
- (k = this.xAvatar) == null || k.setNickName(_, {
- scale: this.xAvatar.scale,
- ...c
- }))
- }
- _move(s) {
- var rt;
- const c = this.getMotionAnimtion("walk")
- , _ = this._getAnimationIdByName(c)
- , {start: b, end: k, walkSpeed: j, moveAnimation: $=_, inter: _e=[], enforceRaycast: et, backToIdle: tt} = s || {};
- return (rt = this.xAvatar) == null ? void 0 : rt.move(b, k, j, $, _e, et, tt).then(()=>{
- this.isMoving = !1
- }
- )
- }
- moveHermite(s) {
- var et;
- const {start: c, end: _, moveAnimation: b=this.getMotionAnimtion("walk"), duration: k, tension: j, enforceRaycast: $, backToIdle: _e} = s || {};
- return (et = this.xAvatar) == null ? void 0 : et.moveHermite(c, _, k, j, b, $, _e)
- }
- move(s) {
- return this._move(s)
- }
- setPickBoxScale(s=1) {
- return this.xAvatar ? (this.xAvatar.setPickBoxScale(s),
- !0) : (logger.error("setPickBoxScale failed, without instance: xAvatar"),
- !1)
- }
- transfer(s) {
- const {player: c, camera: _, pathId: b} = s;
- return this._room.actionsHandler.transfer({
- renderType: RenderType.RotationVideo,
- player: c,
- camera: _,
- pathId: b,
- tag: "transfer"
- })
- }
- avatarLoadedHook() {}
- avatarStartMovingHook() {}
- avatarStopMovingHook() {}
- async statusSync(s) {
- var c, _, b, k, j;
- try {
- if ((c = s.event) != null && c.rotateEvent) {
- const {angle: $} = s.event.rotateEvent
- , _e = this.motionType === MotionType.Run ? "Running" : "Walking";
- this.rotation && (this.rotation.yaw = this.rotation.yaw % 360,
- $.yaw - this.rotation.yaw > 180 && ($.yaw = 180 - $.yaw),
- this.isRotating = !0,
- await this.xAvatar.rotateTo($, this.rotation, _e).then(()=>{
- this._playAnimation("Idle", !0),
- this.isRotating = !1
- }
- ))
- }
- if (((k = (b = (_ = s.event) == null ? void 0 : _.points) == null ? void 0 : b.length) != null ? k : 0) > 1) {
- this.isMoving = !0,
- s.playerState.attitude && (this._motionType = s.playerState.attitude);
- const $ = this.getMotionAnimtion(this.motionType === MotionType.Run ? "run" : "walk")
- , _e = this._room.skin.pathList.find(tt=>tt.id === this.currentPathName)
- , et = ((_e == null ? void 0 : _e.step) || 7.5) * 25;
- this.position && await this._move({
- start: this.position,
- end: s.event.points[s.event.points.length - 1],
- walkSpeed: et,
- moveAnimation: $,
- inter: (j = s.event) == null ? void 0 : j.points.slice(0, -1)
- }).then(()=>{
- this.avatarStopMovingHook()
- }
- )
- }
- } catch {
- return
- }
- }
- removeAttachedEffects() {
- this.attachedEffects.forEach((s,c)=>{
- this._room.effectManager.removeEffect(c)
- }
- ),
- this.attachedEffects.clear()
- }
- removeAttachedEffect(s) {
- this.attachedEffects.delete(s),
- this._room.effectManager.removeEffect(s)
- }
- getMotionAnimtion(s) {
- return MotionAnimtion[s] || MotionAnimtion.idle
- }
- faceTo({point: s, rotateSpeed: c=.1}) {
- return this.xAvatar.faceTo(s, c)
- }
- }
|