Observer embryo, Maestro done

This commit is contained in:
STEINNI
2026-06-13 13:47:46 +00:00
parent 932b6e4752
commit 26aefd3fe2
45 changed files with 1889 additions and 143 deletions
+25 -1
View File
@@ -1,6 +1,7 @@
export const construct = (redisCnx) => {
const tickMs = redisCnx.gpsSrv?.getGpsSettings().collisionTickMs ?? 100
// Interval always runs; tickArena no-ops until LIVE (see gpsServer.tickArena)
setInterval(() => {
redisCnx.gpsSrv?.tickArena()
}, tickMs)
@@ -8,6 +9,24 @@ export const construct = (redisCnx) => {
export const methods = {
handleLifecycleEvent(msg) {
const srv = this.gpsSrv
if(!srv) return
if(msg.eventType === 'onYourMarks') {
srv.onYourMarks(msg.payload ?? {}).catch(err => {
console.error(`[${this.redisId}] onYourMarks failed:`, err)
srv.publishReadyToStart({ success: false, err: err.message ?? 'onYourMarks failed' })
})
return
}
if(msg.eventType === 'bigBang') {
srv.onBigBang(msg.payload ?? {})
return
}
},
handleAgentEvent(msg) {
const agentId = msg.sender
if(!agentId || typeof(agentId) !== 'string') {
@@ -34,7 +53,12 @@ export const methods = {
dispatchArenaMessage(msg, chan) {
const gps = this.config.gps
if(!gps || !this.gpsSrv) return false
if(!gps || !this.gpsSrv) return(false)
if(this.matchesChan(chan, gps.lifecycle?.arenaChannel ?? 'arena:lifecycle')) {
this.handleLifecycleEvent(msg)
return(true)
}
if(this.matchesChan(chan, gps.agentVectorChangeChannel)) {
this.handleAgentEvent(msg)
+5
View File
@@ -0,0 +1,5 @@
export function dispatchMessage(redisCnx, msg, chan) {
if(!redisCnx.config.gps || typeof(redisCnx.dispatchArenaMessage) !== 'function') return
redisCnx.dispatchArenaMessage(msg, chan)
}
+2
View File
@@ -1,4 +1,5 @@
import { methods as arenaMethods, construct as arenaConstruct } from './arenaHandlers.js'
import { dispatchMessage } from './dispatch.js'
export const afterLoginMethods = [
arenaConstruct,
@@ -7,3 +8,4 @@ export const afterLoginMethods = [
export const meshActions = {
...arenaMethods,
}
export { dispatchMessage }
+28
View File
@@ -0,0 +1,28 @@
export function dispatchMessage(redisCnx, msg, chan) {
const gps = redisCnx.config.gps
if(!gps?.gpsActionsChannel) return
const actionsChan = redisCnx.fullChan(gps.gpsActionsChannel)
if(chan != actionsChan) return
const action = msg.action
if(!action || typeof(action) !== 'string') {
console.warn(`[${redisCnx.redisId}] Ignoring message without action on ${chan}`)
return
}
const handler = redisCnx['action_'+action]
if(typeof(handler) != 'function') {
if(redisCnx.debug) console.warn(`[${redisCnx.redisId}] Unknown action ${action} on ${chan}`)
return
}
const payload = ('payload' in msg) ? msg.payload : null
const reqid = ('reqid' in msg) ? msg.reqid.substr(0, 50) : null
const sender = msg.sender || null
const roles = Array.isArray(msg.roles) ? msg.roles : ['*']
if(redisCnx.debug) console.log(`[${redisCnx.redisId}] Dispatching action ${action} from ${sender}`)
handler.call(redisCnx, action, payload, reqid, sender, roles)
}
+2
View File
@@ -1,5 +1,6 @@
import { methods as utilities, construct as utilitiesConstruct } from './utilities.js'
import { methods as positions } from './positions.js'
import { dispatchMessage } from './dispatch.js'
export const afterLoginMethods = [
utilitiesConstruct,
@@ -8,3 +9,4 @@ export const meshActions = {
...utilities,
...positions,
}
export { dispatchMessage }
+26 -20
View File
@@ -1,4 +1,4 @@
import { publishActionReply, parseAt } from '../../actionsHelper.js'
import { publishActionReply, parseSimTime } from '../../actionsHelper.js'
export const methods = {
@@ -8,7 +8,7 @@ export const methods = {
"reqid": "6az5e4r6a",
"payload": {
"agentId": "agent42",
"at": "2026-06-07T12:00:00.000Z"
"t": 12.5
}
}
Event-Tx:
@@ -21,9 +21,9 @@ export const methods = {
"id": "agent42",
"position": { "x": 1, "y": 2, "z": 3 },
"vector": { "x": 0, "y": 0, "z": 0 },
"since": 1717750800,
"since": 0,
"generation": 2,
"at": "2026-06-07T12:00:00.000Z"
"t": 12.5
}
}
}
@@ -43,6 +43,14 @@ export const methods = {
return
}
if(!this.gpsSrv.isLive()) {
publishActionReply(this, { ...replyOpts, reply: {
success: false,
err: 'Simulation not live',
} })
return
}
const agentId = payload?.agentId
if(!agentId || typeof(agentId) !== 'string') {
publishActionReply(this, { ...replyOpts, reply: {
@@ -52,11 +60,11 @@ export const methods = {
return
}
const at = parseAt(payload, () => this.gpsSrv.now())
const at = parseSimTime(payload, () => this.gpsSrv.now())
if(at === null) {
publishActionReply(this, { ...replyOpts, reply: {
success: false,
err: 'Invalid at timestamp',
err: 'Invalid simulation time',
} })
return
}
@@ -86,17 +94,7 @@ export const methods = {
"yMin": -10, "yMax": 10,
"zMin": 0, "zMax": 5
},
"at": "2026-06-07T12:00:00.000Z"
}
}
Event-Tx:
{
"action": "GETAGENTSINPRISM",
"success": true,
"reqid": "6az5e4r6a",
"payload": {
"agents": [ ... ],
"at": "2026-06-07T12:00:00.000Z"
"t": 0
}
}
*/
@@ -115,6 +113,14 @@ export const methods = {
return
}
if(!this.gpsSrv.isLive()) {
publishActionReply(this, { ...replyOpts, reply: {
success: false,
err: 'Simulation not live',
} })
return
}
const prism = payload?.prism
if(!this.gpsSrv.isValidPrism(prism)) {
publishActionReply(this, { ...replyOpts, reply: {
@@ -124,11 +130,11 @@ export const methods = {
return
}
const at = parseAt(payload, () => this.gpsSrv.now())
const at = parseSimTime(payload, () => this.gpsSrv.now())
if(at === null) {
publishActionReply(this, { ...replyOpts, reply: {
success: false,
err: 'Invalid at timestamp',
err: 'Invalid simulation time',
} })
return
}
@@ -138,7 +144,7 @@ export const methods = {
success: true,
payload: {
agents,
at: new Date(at * 1000).toISOString(),
t: at,
},
} })
},