import XStaticMesh from "./XStaticMesh.js" import EMeshType from "./enum/EMeshType.js" import BreathPoint from "./BreathPoint.js" import Logger from "./Logger.js" import XBreathPointError from "./Error/XBreathPointError.js" const logger = new Logger('XBreathPointManager') export default class XBreathPointManager { constructor(e) { E(this, "_scene"); E(this, "materialMap", new Map); E(this, "breathPoints", new Map); E(this, "_sceneManager"); E(this, "_allIds", new Set); E(this, "_loopBPKeys", []); E(this, "addBreathPoint", async info=>{ const t = [{ // url: "https://static.xverse.cn/qqktv/texture.png" url: "./assets/textures/breathPoint/texture.png" }]; if (t.length <= 0) { logger.warn("[Engine] BreathPoint get texture list error: textureList.length <= 0"), new XBreathPointError("[Engine] BreathPoint get texture list error!"); return } const r = t[0] , { id, spriteSheet=r.url, spriteWidthNumber=20, spriteHeightNumber=1, position, rotation={ pitch: -90, yaw: 270, roll: 0 }, size=.6, width=-1, height=-1, fps=30, billboardMode=!1, forceLeaveGround=!1, type="default", lifeTime=-1, backfaceculling=!0, maxVisibleRegion=-1, skinInfo="default" } = info; if (this.breathPoints.get(id)) { logger.warn("[Engine] Cannot add breathPoint with an existing id: [" + id + "]"), new XBreathPointError("[Engine] Cannot add breathPoint with an existing id: [" + id + "]"); return } if (forceLeaveGround) { const I = this.castRay(new BABYLON.Vector3(position.x, position.y, position.z)) * scaleFromUE4toXverse; I != 0 ? position.z = position.z - I + 1 : position.z = position.z + 1 } let mat; if (this.materialMap.get(type)) { const I = this.materialMap.get(type); I.count = I.count + 1, mat = I.mat } else { const texture = new BABYLON.Texture(spriteSheet, this._scene, !0, !0, BABYLON.Texture.BILINEAR_SAMPLINGMODE, null, ()=>{ logger.error("[Engine] Breathpoint create texture error."), new XBreathPointError("[Engine] Breathpoint create texture error.") } ,null, !0); texture.name = "TexBreathPoint_" + id, mat = new BABYLON.StandardMaterial(`MaterialBreathPoint_${id}`,this._scene), mat.alpha = 1, mat.emissiveTexture = texture, mat.backFaceCulling = backfaceculling, mat.diffuseTexture = texture, mat.diffuseTexture.hasAlpha = !0, mat.useAlphaFromDiffuseTexture = !0, this.materialMap.set(type, { mat, count: 1, lastRenderTime: Date.now(), fps, spriteWidthNumber, spriteHeightNumber, spriteSheet, texture }) } const faceUV = new Array(6); for (let i = 0; i < 6; i++) faceUV[i] = new BABYLON.Vector4(0,0,0,0); faceUV[0] = new BABYLON.Vector4(0, 0, 1 / spriteWidthNumber, 1 / spriteHeightNumber), faceUV[1] = new BABYLON.Vector4(0, 0, 1 / spriteWidthNumber, 1 / spriteHeightNumber); let options = {}; width > 0 && height > 0 ? options = { width, height, depth: .01, faceUV } : options = { size, depth: .01, faceUV }; const mesh = BABYLON.MeshBuilder.CreateBox(id, options, this._scene); mesh.material = mat; const xMesh = new XStaticMesh({ id, mesh, xtype: EMeshType.XBreathPoint, skinInfo }); let rota = rotation; billboardMode && ( mesh.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL, xMesh.allowMove(), rota = { pitch: 0, yaw: 270, roll: 0 } ); const breathPoint = new BreathPoint({ type, mesh: xMesh, id, position, rotation: rota, mat, maxVisibleRegion, scene: this._scene, skinInfo }); this.breathPoints.set(id, breathPoint), this._allIds.add(id), lifeTime > 0 && setTimeout(()=>{ this.clearBreathPoints(id) }, lifeTime * 1e3) }); E(this, "reg_breathpoint_update", ()=>{ const e = new Date().getTime(); if (this.materialMap != null) for (const [t,r] of this.materialMap) e - r.lastRenderTime > 1e3 / r.fps && (r.lastRenderTime = e, Math.abs(r.mat.diffuseTexture.uOffset - (1 - 1 / r.spriteWidthNumber)) < 1e-6 ? (r.mat.diffuseTexture.uOffset = 0, Math.abs(r.mat.diffuseTexture.vOffset - (1 - 1 / r.spriteHeightNumber)) < 1e-6 ? r.mat.diffuseTexture.vOffset = 0 : r.mat.diffuseTexture.vOffset += 1 / r.spriteHeightNumber) : r.mat.diffuseTexture.uOffset += 1 / r.spriteWidthNumber) } ); E(this, "reg_breathpoint_autovisible", ()=>{ if (this._scene.getFrameId() % 2 == 0) if (this._loopBPKeys.length == 0) this._loopBPKeys = Array.from(this._allIds); else { const e = this._getMainPlayerPosition(); for (let t = 0; t < 5 && this._loopBPKeys.length > 0; ++t) { const r = this._loopBPKeys.pop(); if (r != null) { const n = this.getBreathPoint(r); if (n != null && n.maxvisibleregion >= 0 && n.mesh.visibility == 1) { const o = n.mesh.position; calcDistance3DVector(e, o) >= n.maxvisibleregion ? n == null || n.removeFromScene() : n == null || n.addToScene() } } } } } ); this._sceneManager = e, this._scene = e.Scene, this._scene.registerBeforeRender(this.reg_breathpoint_update), this._scene.registerBeforeRender(this.reg_breathpoint_autovisible) } setAllBreathPointVisibility(e) { for (const [t,r] of this.breathPoints.entries()) r.toggleVisibility(e) } toggleBPVisibilityBySkinInfo(e, t) { for (const [r,n] of this.breathPoints.entries()) n.skinInfo == e && n.toggleVisibility(t) } toggleBPVisibilityById(e, t) { const r = this.getBreathPoint(e); r != null && r.toggleVisibility(t) } getBreathPointBySkinInfo(e) { const t = []; for (const [r,n] of this.breathPoints.entries()) n.skinInfo == e && t.push(n); return t } getAllBreathPoint() { return this.breathPoints } getBreathPoint(e) { return this.breathPoints.get(e) } delete(e) { const t = this.breathPoints.get(e); if (t != null) { t.dispose(), this._allIds.delete(e); const r = this.materialMap.get(t._type); r != null && (r.count = r.count - 1, r.count <= 0 && (r.count = 0, r.texture.dispose(), r.mat.dispose(!0, !0), this.materialMap.delete(t._type))), this.breathPoints.delete(e) } } castRay(e) { var s; e = ue4Position2Xverse({ x: e.x, y: e.y, z: e.z }); const t = new BABYLON.Vector3(0,-1,0) , r = new BABYLON.Ray(e,t,length) , n = [] , o = (s = this._sceneManager) == null ? void 0 : s.getGround({ x: e.x, y: e.y, z: e.z }); let a = r.intersectsMeshes(o); if (a.length > 0) { const l = a[0]; if (l && l.pickedMesh) { const u = l.distance; t.y = 1; const c = r.intersectsMeshes(n); let h = 1e8; if (c.length > 0) { const f = c[0]; return f && f.pickedMesh && (h = -f.distance), h == 1e8 ? u : Math.abs(h) < Math.abs(u) ? h : u } } } else if (t.y = 1, a = r.intersectsMeshes(n), a.length > 0) { const l = a[0]; if (l && l.pickedMesh) return l.distance } return 0 } changePickable(e) { for (const [t,r] of this.breathPoints.entries()) r.changePickable(e) } clearBreathPoints(e) { logger.info(`[Engine] clearBreathPoints: ${e}`); for (const [t,r] of this.breathPoints.entries()) (r._type == e || r._id == e) && this.delete(r._id) } clearBreathPointsBySkinInfo(e) { logger.info(`[Engine] clearBreathPointsBySkinInfo: ${e}`); for (const [t,r] of this.breathPoints.entries()) r.skinInfo == e && this.delete(r._id) } clearAllBreathPoints() { logger.info("[Engine] ClearAllBreathPoints"); for (const [e,t] of this.breathPoints.entries()) this.delete(t._id) } _getMainPlayerPosition() { var r; const e = this._sceneManager.cameraComponent.MainCamera.position , t = this._sceneManager.avatarComponent.getMainAvatar(); if (t != null && t != null) { const n = (r = t == null ? void 0 : t.rootNode) == null ? void 0 : r.position; if (n != null) return n } return e } changeBreathPointPose(e, t, r) { const n = new BABYLON.Vector3(e.position.x,e.position.y,e.position.z); if (this.breathPoints.get(r) != null) { logger.info(`[Engine] changeBreathPointPose, id:${r}`); const o = this.breathPoints.get(r) , a = o.mesh.position; let s = a.subtract(n); s = BABYLON.Vector3.Normalize(s); const l = BABYLON.Vector3.Distance(a, n) , u = new Ray(n,s,l) , c = this._scene.multiPickWithRay(u); if (c) { for (let h = 0; h < c.length; h++) if (c[h].pickedMesh != null && t.mesh.name.indexOf(c[h].pickedMesh.name) >= 0) { const f = c[h].pickedPoint; o.mesh.position = n.add(f.subtract(n).scale(.99)), this.breathPoints.set(r, o) } } } else logger.warn(`[Engine] changeBreathPointPose, id:${r} is not existing!`) } }