@@ -27,6 +27,12 @@ class SceneManager {
2727 void restoreSnapshot () {
2828 if (sceneSnapshot == null ) return ;
2929
30+ // v1.1: Preserve blueprints before restoring snapshot
31+ HashMap<Integer , Blueprint > savedBlueprints = new HashMap<Integer , Blueprint > ();
32+ for (Entity e : entities) {
33+ savedBlueprints. put(e. id, e. blueprint);
34+ }
35+
3036 entities. clear();
3137 selectedEntities. clear();
3238 nextEntityId = snapshotNextId;
@@ -37,6 +43,13 @@ class SceneManager {
3743 JSONObject json = sceneSnapshot. getJSONObject(i);
3844 Entity e = new Entity (json. getInt(" id" ), json. getString(" name" ), json. getString(" type" ));
3945 e. fromJSON(json);
46+
47+ // v1.1: Restore saved blueprint
48+ if (savedBlueprints. containsKey(e. id)) {
49+ e. blueprint = savedBlueprints. get(e. id);
50+ e. blueprint. owner = e; // Update owner reference
51+ }
52+
4053 entities. add(e);
4154 idMap. put(e. id, e);
4255 }
@@ -51,23 +64,51 @@ class SceneManager {
5164 }
5265 }
5366
54- println (" Scene Snapshot Restored" );
67+ println (" Scene Snapshot Restored (Blueprints preserved) " );
5568 }
5669
5770 Entity findEntityById (int id ) {
5871 for (Entity e : entities) if (e. id == id) return e;
5972 return null ;
6073 }
6174
62- void addEntity (String name , String type ) {
75+ Entity addEntity (String name , String type ) {
6376 Entity e = new Entity (nextEntityId++ , name, type);
6477 entities. add(e);
6578 selectEntity(e, false );
6679 undoManager. push(new AddEntityCommand (this , e));
80+ return e;
6781 }
6882
6983 void triggerEvent (Entity e , String type ) {
7084 if (e == null ) return ;
85+
86+ // v1.3: Multi-event Blueprint PDES support
87+ // Map runtime event names to Blueprint event keys
88+ String vlbKey = null ;
89+ if (type. equals(" Start" )) vlbKey = " OnStart" ;
90+ else if (type. equals(" Update" )) vlbKey = " OnUpdate" ;
91+ else if (type. equals(" onClick" )) vlbKey = " OnMouseClick" ;
92+ else if (type. equals(" OnKeyPress" )) vlbKey = " OnKeyPress" ;
93+ else if (type. equals(" OnBeginOverlap" )) vlbKey = " OnBeginOverlap" ;
94+ else if (type. equals(" OnEndOverlap" )) vlbKey = " OnEndOverlap" ;
95+
96+ if (vlbKey != null && e. blueprintEventPDES. containsKey(vlbKey)) {
97+ String pdes = e. blueprintEventPDES. get(vlbKey);
98+ if (pdes != null && ! pdes. isEmpty()) {
99+ if (! type. equals(" Update" )) {
100+ p3deditor. this . ui. debugConsole. addLog(" > Event [" + vlbKey + " ] on '" + e. name + " ' running VLB Logic" , 2 );
101+ }
102+ p3deditor. this . scriptManager. runScript(" VLB_" + vlbKey + " _" + e. name, pdes, e);
103+ }
104+ }
105+
106+ // Legacy: Also support old single-PDES field for Start
107+ if (type. equals(" Start" ) && ! e. blueprintEventPDES. containsKey(" OnStart" ) && e. blueprintPDES != null && ! e. blueprintPDES. isEmpty()) {
108+ p3deditor. this . ui. debugConsole. addLog(" > Event [Start] on '" + e. name + " ' running VLB Logic (legacy)" , 2 );
109+ p3deditor. this . scriptManager. runScript(" VLB_" + e. name, e. blueprintPDES, e);
110+ }
111+
71112 ArrayList<String > scripts = e. eventHandlers. get(type);
72113 if (scripts != null ) {
73114 for (String scriptPath : scripts) {
@@ -91,7 +132,7 @@ class SceneManager {
91132
92133 ArrayList<Entity > lights = new ArrayList<Entity > ();
93134 for (Entity e : entities) {
94- if (e. type. equals(" PointLight" )) lights. add(e);
135+ if (e. type. equals(" PointLight" ) && e . visible ) lights. add(e);
95136 if (lights. size() >= 5 ) break ;
96137 }
97138
@@ -214,6 +255,51 @@ class SceneManager {
214255 t. setFloat(" sz" , e. transform. scale. z);
215256 ej. setJSONObject(" transform" , t);
216257
258+ // v1.1: Serialize Blueprint
259+ JSONObject bpj = new JSONObject ();
260+ JSONArray nodesArr = new JSONArray ();
261+ for (int ni = 0 ; ni < e. blueprint. nodes. size(); ni++ ) {
262+ VLBNode nd = e. blueprint. nodes. get(ni);
263+ JSONObject nj = new JSONObject ();
264+ nj. setInt(" id" , nd. id);
265+ nj. setString(" title" , nd. title);
266+ nj. setString(" type" , nd. type);
267+ nj. setFloat(" x" , nd. x);
268+ nj. setFloat(" y" , nd. y);
269+ // Serialize pin default values
270+ JSONArray pinsArr = new JSONArray ();
271+ ArrayList<VLBPin > allPins = new ArrayList<VLBPin > ();
272+ allPins. addAll(nd. inputs); allPins. addAll(nd. outputs);
273+ for (int pi = 0 ; pi < allPins. size(); pi++ ) {
274+ VLBPin pin = allPins. get(pi);
275+ JSONObject pj = new JSONObject ();
276+ pj. setString(" label" , pin. label);
277+ pj. setBoolean(" isInput" , pin. isInput);
278+ pj. setFloat(" val" , pin. val);
279+ pj. setString(" sVal" , pin. sVal);
280+ pinsArr. setJSONObject(pi, pj);
281+ }
282+ nj. setJSONArray(" pins" , pinsArr);
283+ nodesArr. setJSONObject(ni, nj);
284+ }
285+ bpj. setJSONArray(" nodes" , nodesArr);
286+
287+ // Serialize connections
288+ JSONArray connsArr = new JSONArray ();
289+ for (int ci = 0 ; ci < e. blueprint. connections. size(); ci++ ) {
290+ VLBConnection conn = e. blueprint. connections. get(ci);
291+ JSONObject cj = new JSONObject ();
292+ cj. setInt(" fromNodeId" , conn. from. parent. id);
293+ cj. setString(" fromPinLabel" , conn. from. label);
294+ cj. setBoolean(" fromIsInput" , conn. from. isInput);
295+ cj. setInt(" toNodeId" , conn. pinTo. parent. id);
296+ cj. setString(" toPinLabel" , conn. pinTo. label);
297+ cj. setBoolean(" toIsInput" , conn. pinTo. isInput);
298+ connsArr. setJSONObject(ci, cj);
299+ }
300+ bpj. setJSONArray(" connections" , connsArr);
301+ ej. setJSONObject(" blueprint" , bpj);
302+
217303 entArr. setJSONObject(i, ej);
218304 }
219305 root. setJSONArray(" entities" , entArr);
@@ -252,6 +338,84 @@ class SceneManager {
252338 e. transform. rotation. set(t. getFloat(" rx" ), t. getFloat(" ry" ), t. getFloat(" rz" ));
253339 e. transform. scale. set(t. getFloat(" sx" ), t. getFloat(" sy" ), t. getFloat(" sz" ));
254340
341+ // v1.1: Deserialize Blueprint
342+ if (! ej. isNull(" blueprint" )) {
343+ JSONObject bpj = ej. getJSONObject(" blueprint" );
344+ e. blueprint. nodes. clear();
345+ e. blueprint. connections. clear();
346+
347+ // Build a mapping from node factory type names to recreate nodes
348+ JSONArray nodesArr = bpj. getJSONArray(" nodes" );
349+ for (int ni = 0 ; ni < nodesArr. size(); ni++ ) {
350+ JSONObject nj = nodesArr. getJSONObject(ni);
351+ String nTitle = nj. getString(" title" );
352+ String nType = nj. getString(" type" );
353+ int nId = nj. getInt(" id" );
354+ float nx = nj. getFloat(" x" );
355+ float ny = nj. getFloat(" y" );
356+
357+ // Try factory first
358+ String factoryKey = nType + " : " + nTitle;
359+ VLBNode nd = createVLBNode(factoryKey, nId, nx, ny);
360+ if (nd == null ) {
361+ // Fallback: create manually (e.g. Event: OnStart)
362+ nd = new VLBNode (nId, nTitle, nType, nx, ny);
363+ // Rebuild pins from saved data
364+ if (nj. hasKey(" pins" )) {
365+ JSONArray pinsArr = nj. getJSONArray(" pins" );
366+ for (int pi = 0 ; pi < pinsArr. size(); pi++ ) {
367+ JSONObject pj = pinsArr. getJSONObject(pi);
368+ boolean isInput = pj. getBoolean(" isInput" );
369+ VLBPin pin = nd. addPin(pj. getString(" label" ), isInput, true , " flow" );
370+ pin. val = pj. getFloat(" val" );
371+ pin. sVal = pj. getString(" sVal" );
372+ }
373+ }
374+ }
375+
376+ // Restore pin values from saved data
377+ if (nj. hasKey(" pins" )) {
378+ JSONArray pinsArr = nj. getJSONArray(" pins" );
379+ for (int pi = 0 ; pi < pinsArr. size(); pi++ ) {
380+ JSONObject pj = pinsArr. getJSONObject(pi);
381+ String pLabel = pj. getString(" label" );
382+ boolean pIsInput = pj. getBoolean(" isInput" );
383+ VLBPin matchPin = nd. findPin(pLabel, pIsInput);
384+ if (matchPin != null ) {
385+ matchPin. val = pj. getFloat(" val" );
386+ matchPin. sVal = pj. getString(" sVal" );
387+ }
388+ }
389+ }
390+ e. blueprint. nodes. add(nd);
391+ }
392+
393+ // Restore connections
394+ if (bpj. hasKey(" connections" )) {
395+ JSONArray connsArr = bpj. getJSONArray(" connections" );
396+ for (int ci = 0 ; ci < connsArr. size(); ci++ ) {
397+ JSONObject cj = connsArr. getJSONObject(ci);
398+ int fromNodeId = cj. getInt(" fromNodeId" );
399+ String fromPinLabel = cj. getString(" fromPinLabel" );
400+ boolean fromIsInput = cj. getBoolean(" fromIsInput" );
401+ int toNodeId = cj. getInt(" toNodeId" );
402+ String toPinLabel = cj. getString(" toPinLabel" );
403+ boolean toIsInput = cj. getBoolean(" toIsInput" );
404+
405+ VLBPin fromPin = null , toPin = null ;
406+ for (VLBNode nd : e. blueprint. nodes) {
407+ if (nd. id == fromNodeId) fromPin = nd. findPin(fromPinLabel, fromIsInput);
408+ if (nd. id == toNodeId) toPin = nd. findPin(toPinLabel, toIsInput);
409+ }
410+ if (fromPin != null && toPin != null ) {
411+ e. blueprint. connections. add(new VLBConnection (fromPin, toPin));
412+ fromPin. connectedTo = toPin;
413+ toPin. connectedTo = fromPin;
414+ }
415+ }
416+ }
417+ }
418+
255419 entities. add(e);
256420 parentIds. add(ej. isNull(" parentId" ) ? - 1 : ej. getInt(" parentId" ));
257421 }
0 commit comments