ActionsHandler.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. import Actions from "./enum/Actions.js"
  2. import {eventsManager} from "./EventsManager.js"
  3. import util from "./util.js"
  4. import Person from "./enum/Person.js"
  5. import ClickType from "./enum/ClickType.js"
  6. import Logger from "./Logger.js"
  7. import MessageHandleType from "./enum/MessageHandleType.js"
  8. import FrequencyLimitError from "./error/FrequencyLimitError.js"
  9. import ParamError from "./error/ParamError.js"
  10. const logger = new Logger('Action')
  11. const QueueActions = [Actions.Transfer, Actions.ChangeSkin, Actions.GetOnVehicle, Actions.GetOffVehicle];
  12. export default class ActionsHandler {
  13. constructor(room) {
  14. this.currentActiveAction = null
  15. this.room = room
  16. }
  17. // 在_handleAvatar时调用
  18. async avatarComponentsSync(avatarComponents) {
  19. this.sendData({
  20. data: {
  21. action_type: Actions.SetPlayerState,
  22. set_player_state_action: {
  23. player_state: {
  24. avatar_components: JSON.stringify(avatarComponents)
  25. }
  26. }
  27. }
  28. })
  29. }
  30. async sendData(actionData)
  31. {
  32. // console.error("[Action]", Actions[actionData.data.action_type])
  33. //console.log('发送数据:'+JSON.stringify(actionData))
  34. await this.beforeSend(actionData);
  35. const traceId = util.uuid();
  36. // 向后端发送action_type信息,获取signal和stream
  37. this.room.networkController.sendRtcData(le(oe({}, actionData.data), {
  38. trace_id: traceId,
  39. user_id: this.room.options.userId
  40. }));
  41. if (actionData.track === !1) {
  42. return Promise.resolve(null);
  43. }
  44. const { sampleRate=1, timeout=2e3, tag, data, special } = actionData;
  45. return eventsManager.track({
  46. timeout,
  47. traceId,
  48. event: data.action_type,
  49. tag,
  50. extra: data
  51. }, {
  52. special,
  53. sampleRate,
  54. noReport: this.room.viewMode === "serverless" || this.room.options.viewMode === "serverless"
  55. }).finally(()=>{
  56. QueueActions.includes(actionData.data.action_type) && (this.currentActiveAction = void 0)
  57. })
  58. }
  59. async beforeSend(e)
  60. {
  61. var o;
  62. const t = (o = this.room._userAvatar) == null ? void 0 : o.isMoving
  63. , r = e.data.action_type;
  64. if (QueueActions.includes(r)) {
  65. if (this.currentActiveAction)
  66. return logger.error(`${Actions[this.currentActiveAction]} still pending, reject ${Actions[r]}`),
  67. Promise.reject(new FrequencyLimitError(`${Actions[r]} action request frequency limit`));
  68. this.currentActiveAction = r
  69. }
  70. if (t && QueueActions.includes(e.data.action_type))
  71. try {
  72. await this.stopMoving()
  73. } catch (a) {
  74. this.currentActiveAction = void 0,
  75. logger.error("before action stopMoving failed", a)
  76. }
  77. }
  78. // 点击行走至某一点时执行
  79. async moveTo({point, extra="", motionType})
  80. {
  81. return this.sendData({
  82. data: {
  83. action_type: Actions.Clicking,
  84. clicking_action: {
  85. clicking_point: point,
  86. clicking_type: ClickType.IgnoreView,
  87. extra: encodeURIComponent(extra),
  88. attitude: motionType
  89. },
  90. clicking_state: this.room._currentClickingState
  91. }
  92. })
  93. }
  94. transfer({renderType, player, camera, areaName, attitude, pathName, person:personType, noMedia, timeout, tag, special})
  95. {
  96. return this.sendData({
  97. data: {
  98. action_type: Actions.Transfer,
  99. transfer_action: {
  100. render_type: renderType,
  101. player,
  102. camera,
  103. areaName,
  104. attitude,
  105. pathName,
  106. person: {
  107. type: personType
  108. },
  109. noMedia,
  110. tiles: [0, 1, 2, 4]
  111. }
  112. },
  113. special,
  114. timeout: timeout || 4e3,
  115. tag
  116. }).then(_ => (
  117. typeof personType != "undefined" && this.room.updateCurrentNetworkOptions({
  118. person: personType,
  119. rotationRenderType: renderType
  120. }),
  121. _
  122. ))
  123. }
  124. // 用于Panorama.exit()
  125. changeRotationRenderType({renderType, player, camera, areaName, attitude, pathName})
  126. {
  127. return this.transfer({
  128. renderType,
  129. player,
  130. camera,
  131. areaName,
  132. attitude,
  133. pathName,
  134. tag: "changeToRotationVideo"
  135. })
  136. }
  137. // 用于请求第一人称视角下的pano数据
  138. requestPanorama({camera, player, areaName, attitude, pathName, tag}, noMedia, timeout)
  139. {
  140. return this.transfer({
  141. renderType: RenderType.ClientRotationPano,
  142. player,
  143. camera,
  144. person: Person.First,
  145. areaName,
  146. attitude,
  147. pathName,
  148. noMedia: noMedia,
  149. timeout: timeout,
  150. tag: tag || "requestPanorama",
  151. special: !noMedia
  152. })
  153. }
  154. // 用于XverseAvatar.setMotionType()。方法未执行
  155. setMotionType(type)
  156. {
  157. return this.transfer({
  158. attitude: type,
  159. tag: "setMotionType"
  160. })
  161. }
  162. // 设置角色昵称。用于XverseAvatar.setNickname()
  163. setNickName(nickname)
  164. {
  165. return this.sendData({
  166. data: {
  167. action_type: Actions.ChangeNickname,
  168. change_nickname_action: {
  169. nickname
  170. }
  171. }
  172. })
  173. }
  174. // 方法未执行
  175. getReserveSeat({routeId, name})
  176. {
  177. return this.sendData({
  178. data: {
  179. action_type: Actions.ReserveSeat,
  180. reserve_seat_action: {
  181. route_id: routeId,
  182. name
  183. }
  184. }
  185. })
  186. }
  187. // 方法未执行
  188. getReserveStatus({routeId, name, need_detail})
  189. {
  190. return this.sendData({
  191. data: {
  192. action_type: Actions.GetReserveStatus,
  193. get_reserve_status_action: {
  194. route_id: routeId,
  195. name,
  196. need_detail
  197. }
  198. },
  199. timeout: 2e3
  200. }).then(o=>o.reserveDetail)
  201. }
  202. // 停止移动。在playAnimation时调用
  203. stopMoving()
  204. {
  205. return this.sendData({
  206. data: {
  207. action_type: Actions.StopMoving,
  208. stop_move_action: {}
  209. }
  210. })
  211. }
  212. // 方法未执行
  213. getOnVehicle({routeId, name, camera})
  214. {
  215. return this.sendData({
  216. data: {
  217. action_type: Actions.GetOnVehicle,
  218. get_on_vehicle_action: {
  219. route_id: routeId,
  220. name,
  221. camera
  222. }
  223. }
  224. })
  225. }
  226. // 方法未执行
  227. getOffVehicle({renderType, player, camera})
  228. {
  229. return this.sendData({
  230. data: {
  231. action_type: Actions.GetOffVehicle,
  232. get_off_vehicle_action: {
  233. render_type: renderType,
  234. player,
  235. camera
  236. }
  237. }
  238. })
  239. }
  240. // 在_handleAvatar时调用
  241. confirmEvent(id)
  242. {
  243. return this.sendData({
  244. data: {
  245. action_type: Actions.ConfirmEvent,
  246. confirm_event_action: {
  247. id
  248. }
  249. },
  250. track: !1
  251. })
  252. }
  253. // 心跳
  254. echo(echoMsg)
  255. {
  256. return this.sendData({
  257. data: {
  258. action_type: Actions.Echo,
  259. echo_msg: {
  260. echoMsg
  261. }
  262. },
  263. track: !1
  264. })
  265. }
  266. // 方法未执行
  267. async changeSkin(skinData)
  268. {
  269. const { skinId, mode, landingType=LandingType.Stay, landingPoint, landingCamera, renderType, areaName, attitude, pathName, person, noMedia, timeout,
  270. roomTypeId="", special } = skinData
  271. const newSkin = this.room.skinList.filter(skin => skin.id === skinId)[0];
  272. if (!newSkin) {
  273. const y = `skin ${skinId} is invalid`;
  274. return logger.error(y),
  275. Promise.reject(new ParamError(y))
  276. }
  277. return this.sendData({
  278. data: {
  279. action_type: Actions.ChangeSkin,
  280. change_skin_action: {
  281. skinID: skinId,
  282. mode: mode === ChangeMode.Preview ? ChangeMode.Preview : ChangeMode.Confirm,
  283. skin_data_version: skinId + newSkin.versionId,
  284. landing_type: landingType,
  285. landing_point: landingPoint,
  286. landing_camera: landingCamera,
  287. render_wrapper: {
  288. render_type: renderType
  289. },
  290. areaName,
  291. attitude,
  292. noMedia,
  293. person,
  294. pathName,
  295. roomTypeId
  296. }
  297. },
  298. timeout: timeout || 6e3,
  299. special: special === void 0 ? renderType === RenderType.ClientRotationPano : special
  300. })
  301. .then(async y=>{
  302. if (renderType === RenderType.ClientRotationPano && y) {
  303. const route = await this.room.modelManager.findRoute(skinId, pathName)
  304. , {camera} = util.getRandomItem(route.birthPointList) || {};
  305. await this.room.panorama.handleReceivePanorama(y, camera)
  306. }
  307. return this.handleChangeSkin(skinData)
  308. })
  309. .catch(e => noMedia ? this.handleChangeSkin(skinData) : Promise.reject(e))
  310. }
  311. handleChangeSkin({skinId, mode, renderType, areaName, attitude, pathName})
  312. {
  313. return this.room.sceneManager.staticmeshComponent.getCgMesh().show(),
  314. this.room.sceneManager.cameraComponent.switchToCgCamera(),
  315. this.room.engineProxy._updateSkinAssets(skinId).then(()=>{
  316. this.room.sceneManager.staticmeshComponent.getCgMesh().hide(),
  317. this.room.sceneManager.cameraComponent.switchToMainCamera(),
  318. this.room.pathManager.currentArea = areaName,
  319. logger.info("changeSkin _updateSkinAssets susccss"),
  320. this.room.updateCurrentNetworkOptions({ pathName, attitude, areaName }),
  321. this.room.skinChangedHook(),
  322. this.room.emit("skinChanged", { skin: { id: skinId }, mode }),
  323. renderType === RenderType.ClientRotationPano && this.room.sceneManager.cameraComponent.allowMainCameraController()
  324. })
  325. }
  326. // 相机旋转
  327. rotate({pitch, yaw})
  328. {
  329. if (
  330. this.room.disableRotate ||
  331. this.room.isPano ||
  332. (this.room._userAvatar && this.room._userAvatar._isChangingComponentsMode)
  333. ) return;
  334. this.sendData({
  335. data: {
  336. action_type: Actions.Rotation,
  337. rotation_action: {
  338. vertical_move: pitch,
  339. horizontal_move: -yaw
  340. },
  341. sampleRate: .02
  342. },
  343. sampleRate: .02
  344. })
  345. }
  346. // 用于XverseAvatar.turnTo()。方法未执行
  347. turnTo({point, timeout=2e3, offset=8} = {})
  348. {
  349. return this.sendData({
  350. data: {
  351. action_type: Actions.TurnTo,
  352. turn_to_action: {
  353. turn_to_point: point,
  354. offset
  355. }
  356. },
  357. timeout
  358. })
  359. }
  360. // 用于XverseAvatar.rotateTo()。方法未执行
  361. rotateTo({point, offset=0, speed=3} = {})
  362. {
  363. return this.sendData({
  364. data: {
  365. action_type: Actions.RotateTo,
  366. rotate_to_action: {
  367. rotate_to_point: point,
  368. offset,
  369. speed
  370. }
  371. }
  372. })
  373. }
  374. broadcast({data, msgType=MessageHandleType.MHT_FollowListMulticast, targetUserIds})
  375. {
  376. if (msgType === MessageHandleType.MHT_CustomTargetSync && !Array.isArray(targetUserIds))
  377. return Promise.reject(new ParamError(`param targetUserIds is required when msgType is ${MessageHandleType[msgType]}`));
  378. let sendData = {
  379. action_type: Actions.Broadcast,
  380. broadcast_action: {
  381. data: JSON.stringify(data),
  382. user_id: this.room.options.userId,
  383. msgType
  384. }
  385. }
  386. if (msgType === MessageHandleType.MHT_CustomTargetSync && Array.isArray(targetUserIds)) {
  387. sendData.broadcast_action.target_user_ids = targetUserIds
  388. }
  389. return this.room.actionsHandler.sendData({
  390. data: sendData,
  391. tag: data.broadcastType
  392. })
  393. }
  394. // 显示呼吸点。用于Debug.getPointsAndRender()
  395. getNeighborPoints({point, containSelf=!1, searchRange=500})
  396. {
  397. return this.sendData({
  398. data: {
  399. action_type: Actions.GetNeighborPoints,
  400. get_neighbor_points_action: {
  401. point,
  402. level: 1,
  403. containSelf,
  404. searchRange
  405. }
  406. }
  407. }).then(a=>a.nps)
  408. }
  409. // 方法未执行
  410. playCG(cgName)
  411. {
  412. return this.sendData({
  413. data: {
  414. action_type: Actions.PlayCG,
  415. play_cg_action: {
  416. cg_name: cgName
  417. }
  418. }
  419. })
  420. }
  421. // 方法未执行
  422. audienceToVisitor({avatarId, avatarComponents, player, camera})
  423. {
  424. return logger.debug("send data: audience to visitor"),
  425. this.sendData({
  426. data: {
  427. action_type: Actions.AudienceChangeToVisitor,
  428. audienceChangeToVisitorAction: {
  429. avatarID: avatarId,
  430. avatarComponents,
  431. player,
  432. camera
  433. }
  434. }
  435. })
  436. }
  437. // 方法未执行
  438. visitorToAudience({renderType, player, camera, areaName, attitude, pathName, person:personType, noMedia})
  439. {
  440. return logger.debug("send data: visitor to audience"),
  441. this.sendData({
  442. data: {
  443. action_type: Actions.VisitorChangeToAudience,
  444. visitorChangeToAudienceAction: {
  445. transferAction: {
  446. render_type: renderType,
  447. player,
  448. camera,
  449. areaName,
  450. attitude,
  451. pathName,
  452. person: {
  453. type: personType
  454. },
  455. noMedia,
  456. tiles: [0, 1, 2, 4]
  457. }
  458. }
  459. }
  460. })
  461. }
  462. // 方法未执行
  463. removeVisitor({removeType, userIDList, extraInfo=""})
  464. {
  465. return logger.debug("send data: remove visitor"),
  466. this.sendData({
  467. data: {
  468. action_type: Actions.RemoveVisitor,
  469. removeVisitorAction: {
  470. removeVisitorEvent: removeType,
  471. userIDList,
  472. extraInfo: encodeURIComponent(extraInfo)
  473. }
  474. }
  475. })
  476. }
  477. // 方法未执行
  478. getUserWithAvatar(userType, roomID)
  479. {
  480. return logger.debug("send data: get user with avatar"),
  481. this.sendData({
  482. data: {
  483. action_type: Actions.GetUserWithAvatar,
  484. getUserWithAvatarAction: {
  485. userType,
  486. roomID
  487. }
  488. }
  489. }).then(n=>n.userWithAvatarList)
  490. }
  491. // 每2秒获取一次新数据。在Xverse_Room.afterJoinRoom()中调用
  492. getNewUserState(userType)
  493. {
  494. return this.sendData({
  495. data: {
  496. action_type: Actions.GetNewUserState,
  497. getNewUserStateAction: {
  498. userType
  499. }
  500. },
  501. sampleRate: 0
  502. }).then(o => o)
  503. }
  504. // 方法未执行
  505. setSyncPolicy({syncPolicy})
  506. {
  507. return this.sendData({
  508. data: {
  509. action_type: Actions.SetSyncPolicy,
  510. setSyncPolicyAction: {
  511. syncPolicy
  512. }
  513. }
  514. })
  515. }
  516. // 拖动手柄
  517. joystick({degree, level=1})
  518. {
  519. const uuid = util.uuid();
  520. let angle = -degree + 90 + 360;
  521. angle >= 360 && (angle -= 360);
  522. return this.sendData({
  523. data: {
  524. action_type: Actions.Joystick,
  525. dir_action: {
  526. move_angle: angle,
  527. speed_level: level
  528. },
  529. trace_id: uuid,
  530. user_id: this.room.options.userId,
  531. packet_id: uuid
  532. },
  533. track: !1
  534. })
  535. }
  536. }