working on simManage
This commit is contained in:
+134
-8
@@ -9,6 +9,16 @@ export class Threetobus{
|
||||
this._curEventsMapping = []
|
||||
this._stagedEventsMapping = options.eventsMapping
|
||||
this.sceneSize = options.sceneSize
|
||||
this._observerConfig = {
|
||||
actionsChannel: 'system:requests:observer',
|
||||
subscribeFrequencyMs: 1000,
|
||||
cameraDebounceMs: 600,
|
||||
...options.observer,
|
||||
}
|
||||
this._frustumRenderEngine = null
|
||||
this._frustumDebounceTimer = null
|
||||
this._frustumCameraChangeHandler = null
|
||||
this._frustumWatching = false
|
||||
this.commitConfig()
|
||||
|
||||
this.cameras = {}
|
||||
@@ -19,8 +29,24 @@ export class Threetobus{
|
||||
}
|
||||
|
||||
busReconnect(){
|
||||
this.commitConfig() // To resubscribe...
|
||||
//TODO : Not ideal because if we're in the middle of non-commited changes...
|
||||
this.commitConfig()
|
||||
if(this._frustumWatching) this._scheduleFrustumResubscribe()
|
||||
}
|
||||
|
||||
resolveSubscriberChan(chanTemplate) {
|
||||
if(typeof(chanTemplate) !== 'string') return(null)
|
||||
const uid = app.User?.identity?.uuid
|
||||
if(!uid) return(null)
|
||||
return(chanTemplate.replace(/\[UID\]/g, uid).replace(/\{uid\}/g, uid))
|
||||
}
|
||||
|
||||
_resolvedEventsMapping() {
|
||||
if(!Array.isArray(this._stagedEventsMapping)) return([])
|
||||
return(this._stagedEventsMapping.map(chanObj => {
|
||||
const chan = this.resolveSubscriberChan(chanObj.chan)
|
||||
if(!chan) return(null)
|
||||
return({ ...chanObj, chan })
|
||||
}).filter(Boolean))
|
||||
}
|
||||
|
||||
get EventsMapping() { return this._stagedEventsMapping }
|
||||
@@ -28,15 +54,21 @@ export class Threetobus{
|
||||
set EventsMapping(newConfig) { this._stagedEventsMapping = newConfig }
|
||||
|
||||
async commitConfig(){
|
||||
const resolvedMapping = this._resolvedEventsMapping()
|
||||
const chansToAdd = []
|
||||
const chansToKeep = []
|
||||
for(const chanObj of this._stagedEventsMapping){
|
||||
for(const chanObj of resolvedMapping){
|
||||
if(this._curEventsMapping.map(item => item.chan).includes(chanObj.chan)) chansToKeep.push(chanObj)
|
||||
else chansToAdd.push(chanObj)
|
||||
}
|
||||
const chansToDel = this._curEventsMapping.filter(item => (!chansToKeep.map(c=>c.chan).includes(item.chan) && !chansToAdd.map(c=>c.chan).includes(item.chan)))
|
||||
await app.MessageBus.subscribe(chansToAdd.map(item => item.chan))
|
||||
await app.MessageBus.unSubscribe(chansToDel.map(item => item.chan))
|
||||
const chansToDel = this._curEventsMapping.filter(item => (
|
||||
!chansToKeep.map(c => c.chan).includes(item.chan)
|
||||
&& !chansToAdd.map(c => c.chan).includes(item.chan)
|
||||
))
|
||||
if(app.MessageBus?.connected) {
|
||||
if(chansToAdd.length) await app.MessageBus.subscribe(chansToAdd.map(item => item.chan))
|
||||
if(chansToDel.length) await app.MessageBus.unSubscribe(chansToDel.map(item => item.chan))
|
||||
}
|
||||
// console.log('subscribe:', chansToAdd.map(item => item.chan))
|
||||
// console.log('unSubscribe:', chansToDel)
|
||||
|
||||
@@ -59,7 +91,7 @@ export class Threetobus{
|
||||
app.MessageBus.removeBusListener(eventToDel.eventName, this.processBusEvent.bind(this, eventToDel.eventName), 'threetobus')
|
||||
}
|
||||
|
||||
this._curEventsMapping = this.deepClone(this._stagedEventsMapping)
|
||||
this._curEventsMapping = this.deepClone(resolvedMapping)
|
||||
}
|
||||
|
||||
deepClone(obj) { // Needed because structuredClone doesn't take functions (and we have transformers)
|
||||
@@ -88,7 +120,8 @@ export class Threetobus{
|
||||
// if yes : how to discriminate static value from event-mapping definition ?
|
||||
if(mapping.child) id += '_'+mapping.child
|
||||
if(id){
|
||||
const obj3D = this.scene.getObjectByName(id)
|
||||
let obj3D = this.scene.getObjectByName(id)
|
||||
if(!obj3D) obj3D = this._ensurePlaceholderAgent(id)
|
||||
if(obj3D){
|
||||
this.assignFromConfig(payload, mapping, obj3D)
|
||||
}
|
||||
@@ -161,6 +194,99 @@ export class Threetobus{
|
||||
return(path.split('.').reduce((acc, key) => acc?.[key], obj))
|
||||
}
|
||||
|
||||
watchCameraFrustum(renderEngine) {
|
||||
if(!renderEngine || renderEngine.mode !== '3D') return
|
||||
if(!app.MessageBus?.config?.enabled) {
|
||||
console.warn('[Threetobus] MessageBus disabled — camera frustum watch skipped')
|
||||
return
|
||||
}
|
||||
|
||||
this._frustumRenderEngine = renderEngine
|
||||
this._frustumWatching = true
|
||||
|
||||
if(!this._frustumCameraChangeHandler) {
|
||||
this._frustumCameraChangeHandler = () => this._scheduleFrustumResubscribe()
|
||||
renderEngine.controls.addEventListener('change', this._frustumCameraChangeHandler)
|
||||
}
|
||||
|
||||
app.MessageBus.whenConnected(() => {
|
||||
this.commitConfig()
|
||||
this._scheduleFrustumResubscribe()
|
||||
})
|
||||
}
|
||||
|
||||
stopWatchingCameraFrustum() {
|
||||
this._frustumWatching = false
|
||||
if(this._frustumDebounceTimer) {
|
||||
clearTimeout(this._frustumDebounceTimer)
|
||||
this._frustumDebounceTimer = null
|
||||
}
|
||||
if(this._frustumRenderEngine?.controls && this._frustumCameraChangeHandler) {
|
||||
this._frustumRenderEngine.controls.removeEventListener('change', this._frustumCameraChangeHandler)
|
||||
}
|
||||
this._frustumRenderEngine = null
|
||||
this._frustumCameraChangeHandler = null
|
||||
}
|
||||
|
||||
_scheduleFrustumResubscribe() {
|
||||
if(!this._frustumWatching) return
|
||||
if(this._frustumDebounceTimer) clearTimeout(this._frustumDebounceTimer)
|
||||
this._frustumDebounceTimer = setTimeout(() => {
|
||||
this._frustumDebounceTimer = null
|
||||
this._resubscribeCameraFrustum()
|
||||
}, this._observerConfig.cameraDebounceMs)
|
||||
}
|
||||
|
||||
async _resubscribeCameraFrustum() {
|
||||
if(!this._frustumWatching || !this._frustumRenderEngine) return
|
||||
if(!app.MessageBus?.connected) return
|
||||
|
||||
const camera = this._frustumRenderEngine.camera
|
||||
if(!camera?.isPerspectiveCamera) return
|
||||
|
||||
const planes = this._cameraFrustumPlanes(camera)
|
||||
const chan = this._observerConfig.actionsChannel
|
||||
|
||||
try {
|
||||
await app.MessageBus.requestBusAction(
|
||||
chan,
|
||||
'SUBSCRIBEFRUSTUM',
|
||||
{
|
||||
planes,
|
||||
frequency: this._observerConfig.subscribeFrequencyMs,
|
||||
},
|
||||
10000
|
||||
)
|
||||
} catch(err) {
|
||||
console.warn('[Threetobus] SUBSCRIBEFRUSTUM failed:', err)
|
||||
}
|
||||
}
|
||||
|
||||
_cameraFrustumPlanes(camera) {
|
||||
camera.updateMatrixWorld(true)
|
||||
const matrix = new THREE.Matrix4().multiplyMatrices(
|
||||
camera.projectionMatrix,
|
||||
camera.matrixWorldInverse
|
||||
)
|
||||
const frustum = new THREE.Frustum().setFromProjectionMatrix(matrix)
|
||||
return(frustum.planes.map(plane => ({
|
||||
nx: plane.normal.x,
|
||||
ny: plane.normal.y,
|
||||
nz: plane.normal.z,
|
||||
d: plane.constant,
|
||||
})))
|
||||
}
|
||||
|
||||
_ensurePlaceholderAgent(agentId) {
|
||||
const geo = new THREE.BoxGeometry(0.4, 0.4, 0.4)
|
||||
const mat = new THREE.MeshStandardMaterial({ color: 0x44aa88 })
|
||||
const obj3D = new THREE.Mesh(geo, mat)
|
||||
obj3D.name = agentId
|
||||
this.tweensRegistry[agentId] = { move: null, rotate: null }
|
||||
this.scene.add(obj3D)
|
||||
return(obj3D)
|
||||
}
|
||||
|
||||
initScene(options){
|
||||
// Scene
|
||||
this.scene = new THREE.Scene()
|
||||
|
||||
Reference in New Issue
Block a user