KF Editor => Reset KF button

This commit is contained in:
STEINNI
2026-06-05 08:33:06 +00:00
parent ea9b3d06cf
commit d301b78ea7
3 changed files with 219 additions and 14 deletions
+33 -13
View File
@@ -71,11 +71,20 @@ class KeyframeView extends WindozDomContent {
this.outputs.btnAddAgent.disabled = true
this.outputs.btnRemoveAgent.disabled = true
this.outputs.btnSaveKF.disabled = true
this.outputs.btnSaveKF.disabled = true
this.outputs.btnResetKF.disabled = true
this.outputs.kfName.addEventListener('keyup', this.updateKfButtons.bind(this))
this.currentlySelectedAid = null
}
deselectSceneAgent(){
if(!this.currentlySelectedAid) return
const obj3D = this.kfArena.scene.getObjectByName(this.currentlySelectedAid)
if(obj3D) this.kfArena.clearHighlight3DObj(obj3D, this.kfArena.scene)
this.currentlySelectedAid = null
this.outputs.btnRemoveAgent.disabled = true
}
async onChangeAgent(event){
if(this.outputs.agentsSelector.value) this.agentPreview.setAgent(this.outputs.agentsSelector.value)
if(!this.outputs.agentsSelector.value) return
@@ -85,36 +94,41 @@ class KeyframeView extends WindozDomContent {
} else {
this.currentAgentType = await this.models.agents.getProperties(this.outputs.agentsSelector.value)
this.fillAgentProperties('', this.currentAgentType)
// Deselect any on-scene selection
if(this.currentlySelectedAid){
this.kfArena.clearHighlight3DObj(this.kfArena.scene.getObjectByName(this.currentlySelectedAid), this.kfArena.scene)
}
this.currentlySelectedAid = null
this.deselectSceneAgent()
}
}
async onChangeKeyframe(event){
if(!this.outputs.keyframesSelector.value) return
let kfData = await this.models.keyframes.getKeyframe(this.outputs.keyframesSelector.value).then(data => data.payload)
await this.loadKeyframe(this.outputs.keyframesSelector.value)
}
async onResetKF(evt){
if(!this.currentKeyframe.kfId) return
await this.loadKeyframe(this.currentKeyframe.kfId)
}
async loadKeyframe(kfId){
let kfData = await this.models.keyframes.getKeyframe(kfId).then(data => data.payload)
this.currentKeyframe = {
kfId: kfData.info.ekf_uuid,
kfName: kfData.info.ekf_name,
prevKfId: kfData.info.ekf_prev_uuid,
}
this.outputs.kfName.value = kfData.info.ekf_name
this.deselectSceneAgent()
this.kfArena.reloadAgents(kfData.agents)
this.outputs.agentProperties.innerHTML = ''
this.outputs.btnAddAgent.disabled = true
this.updateKfButtons()
}
onclickAgent(obj3D){
const aid = obj3D.name
if(this.currentlySelectedAid == aid){ // Deselect
this.kfArena.clearHighlight3DObj(obj3D, this.kfArena.scene)
this.currentlySelectedAid = null
this.outputs.btnRemoveAgent.disabled = true
this.deselectSceneAgent()
} else { // Select
if(this.currentlySelectedAid){
this.kfArena.clearHighlight3DObj(this.kfArena.scene.getObjectByName(this.currentlySelectedAid), this.kfArena.scene)
}
this.deselectSceneAgent()
this.currentlySelectedAid = aid
this.outputs.btnRemoveAgent.disabled = false
if(this.kfArena.agents[aid]) {
@@ -139,6 +153,10 @@ class KeyframeView extends WindozDomContent {
onRemoveAgent(event){
if(!this.currentlySelectedAid) return
this.kfArena.removeAgent(this.currentlySelectedAid)
this.currentlySelectedAid = null
this.outputs.btnRemoveAgent.disabled = true
if(this.currentAgentType) this.fillAgentProperties('', this.currentAgentType)
this.updateKfButtons()
}
async newAgent(aType, AgentValues){
@@ -151,6 +169,7 @@ class KeyframeView extends WindozDomContent {
updateKfButtons(){
if((Object.keys(this.kfArena.agents).length > 0) && (this.outputs.kfName.value.length > 5)) { this.outputs.btnSaveKF.disabled = false }
else { this.outputs.btnSaveKF.disabled = true }
this.outputs.btnResetKF.disabled = !this.currentKeyframe.kfId
}
onPropsChanged(evt, comp){
@@ -230,6 +249,7 @@ class KeyframeView extends WindozDomContent {
await this.models.keyframes.save(this.currentKeyframe.kfId, this.kfArena.agents)
this.outputs.btnSaveKF.disabled = true
this.updateKfButtons()
ui.growl.append('Keyframe saved!','success',3000)
setTimeout(() => { this.outputs.btnSaveKF.disabled = false}, 3000)
}
+185
View File
@@ -0,0 +1,185 @@
{
"nodes": [
{
"id": "concept.p42",
"name": "P42",
"type": "concept",
"scope": "project",
"userDoc": {
"statements": [
"Project 42 (or P42 for short) is a general purpose simulation engine",
"Its goal is to provide a flexible and powerful tool for simulating and analyzing the widest possible range of complex systems",
"It is a platform for building and running simulations, for analyzing the results of those simulations",
"It aims at allowing users to easily create and spot emerging phenomenons in complex systems"
],
"humor": [
"Why 42 ? Well, the author hopes this project will help answering non-obvious questions, and you should know 42 is the answer to THE BIGGEST question."
]
},
"developperDoc": {
}
},
{
"id": "concept.godProcess",
"name": "God process",
"type": "concept",
"scope": "platform",
"userDoc": {
"statements": [
"A god-process is a process that is responsible for a specific part of the overall management of the simulation",
"Contrary to agents, it is not part of the simulation per-se, as it remains neutral to what happens in the arena of the simulation",
"Contrary to agents, it has access to everything that happens in the arena of the simulation in order to perform its tasks, and is therefore in a \"god-like\" position."
],
"humor": [
"Ironically, the author of P42 is a firm non-believer",
"In the unix world, a background process is called a \"daemon\", and therefore, you can call a god-process a \"god-daemon\""
]
},
"developperDoc": {
"constraints": [
"All god-daemons are kept in separated folders, in /op/p42GodDaemons",
"All god-daemons should depend on the same Redis P42 library that standardizes accesses to Redis Pub/Sub and Redis database",
"God-daemons can have access to the arena bus, the management bus or (generally) both.",
"God-daemons can fire events on the arena bus that will be received by agents",
"God-daemons can fire events on the management bus that will be received by the interface",
"God-daemons can fire events on the management bus that will be received by other god-daemons",
"God-daemons can fire events on the arena bus that will be received by other god-daemons",
"God-daemons must never update agents data directly (that's the agent's job)",
"Agents can make requests to God-daemons via the arena bus, and god-daemon should always reply with a valid response (even if empty or error)"
]
},
"relations": [
{ "type": "uses", "target": "concept.arenaBus" },
{ "type": "uses", "target": "concept.managementBus" }
]
},
{
"id": "concept.arenaBus",
"name": "Arena Bus",
"type": "concept",
"scope": "platform",
"userDoc": {
"statements": [
"The Arena Bus is a message bus that is used to communicate between agents and god-processes",
"It is a Redis backed PUB/SUB message bus, and is used to provide communications between agents, between agents and god-processes, and between god-processes",
"For agents, this bus represents their sole window to the simulation's world (arena)",
"For God-daemons, the bus allows to receive agent events (monitoring), send world-state change events to interested agents, and to provide agents with request-reply services"
]
},
"developperDoc": {
"constraints": [
"For scalability, the arena bus can use several different Redis daemons, each one representing a shard of the Arena (bus and agents storages)",
"To respect arena isolation, events on the arena bus shall not cary any information which is not directly related to the arena (agents, god-processes, etc.)"
]
}
},
{
"id": "concept.managementBus",
"name": "Management Bus",
"type": "concept",
"scope": "platform",
"userDoc": {
"statements": [
"The Management Bus is a message bus that is used to communicate between god-processes, and between god-processes and the interface",
"It is a Redis backed PUB/SUB message bus"
]
},
"developperDoc": {
"constraints": [
"For simplicity, the management bus only uses a single Redis daemon",
"In order to keep the arena bus as little loaded as possible, inter-god-daemons events shall use the management bus instead of the arena bus"
]
}
},
{
"id": "concept.PRNGs",
"name": "PRNGs",
"type": "concept",
"scope": "agent api",
"userDoc": {
"statements": [
"PRNGs (Pseudo-Random Number Generator) are provided to agents needing random numbers",
"Agents cannot use any other random number generator than the PRNGs provided to them by the PRGN God-Daemon",
"This ensures reproducibility of the simulation, and prevents agents from using non-reproductible randomness"
]
},
"developperDoc": {
"constraints": [
"Random numbers are provided to agents upon request to the God-Daemon PRNG service",
"Seed based PRNGs (Pseudo-Random Number Generator) are used to generate random numbers for agents",
"PRNGs must ensure a high enough entropy for each agent",
"PRNGs must ensure reproducibility from one run to the next, by storing all seeds with the arena state",
"Agents shall never have access to seeds, nor to any other information that could be used to reproduce the same random numbers",
"PRNGs must be thread-safe, and must be able to handle concurrent requests from multiple agents"
]
}
},
{
"id": "feature.horizontal-scaling",
"name": "horizontal scaling",
"type": "feature",
"scope": "performance",
"userDoc": {
"statements": [
"Horizontally scalable by design, allowing users to easily scale their simulations to handle large amounts of data and agents",
"The limit is only the computing power users are ready top pay for"
]
},
"developperDoc": {
"constraints": [
"All runners are containerized, and are executed by a dedicated container orchestrator, which uses a dedicated Redis that represents a shard of the Arena (bus and agents storages)"
],
"statements": [
"Uses a distributed architecture that uses any number of containerized runners that execute agents code, as well as the code of god-processes",
"Communication between agents, god-processes and interface is handled by two REDIS backed PUB/SUB message buses"
]
}
},
{
"id": "feature.strongArenaIsolation",
"name": "Strong arena isolation",
"type": "feature",
"scope": "simulation",
"userDoc": {
"statements": [
"Designed to maintain strong isolation between the arena of the simulation and the rest of the system",
"Agents are isolated from each other, and from the rest of the system to ensure no unwanted data contamination could tamper the agent's behavior"
]
},
"developperDoc": {
"constraints": [
"No event shall be ported bewteen arena and management busses",
"No reply to an agent request and no payload of an arena event should leak any \"overview\" of the simulation state to the agent, neither any management data of the system"
],
"statements": [
"Uses two different busses: one for letting agents communicate with each other, or with the god-processes, and a second isolated one for managing the simulation state",
"Likewise, agents internal states and properties belong to the arena, and are stored in a dedicated REDIS database, isolated from the general system databases"
]
},
"relations": [
{ "type": "uses", "target": "concept.arenaBus" },
{ "type": "uses", "target": "concept.managementBus" }
]
},
{
"id": "feature.reproductibility",
"name": "Reproductibility",
"type": "feature",
"scope": "simulation",
"userDoc": {
"statements": [
"Designed to ensure that the simulation can be reproduced exactly the same way, from one run to the next",
"Same initial conditions should lead to the same final state, unless the simulation is voluntarily stochastic (agents use non-reproductible randomness)"
]
},
"developperDoc": {
"constraints": [ ],
"statements": [ ]
},
"relations": [
{ "type": "uses", "target": "concept.PRNGs" },
{ "type": "uses", "target": "concept.managementBus" }
]
}
]
}