update Tue 07/14/2026 11:38:16.92
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
/* Seed/live persistence.
|
||||
* data/scene.json — committed seed (survives in git)
|
||||
* data/live/scene.live.json — runtime edits, volume-mounted in Docker, survives redeploys
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DATA = path.join(__dirname, '..', 'data');
|
||||
const LIVE_DIR = process.env.LIVE_DIR || path.join(DATA, 'live');
|
||||
const SEED = path.join(DATA, 'scene.json');
|
||||
const LIVE = path.join(LIVE_DIR, 'scene.live.json');
|
||||
const PLAYLIST_LIVE = path.join(LIVE_DIR, 'playlist.live.json');
|
||||
const MODELS_LIVE = path.join(LIVE_DIR, 'models.live.json');
|
||||
const MODELS_SEED = path.join(DATA, 'models.json');
|
||||
|
||||
fs.mkdirSync(LIVE_DIR, { recursive: true });
|
||||
|
||||
function readJSON(p, fallback) {
|
||||
try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return fallback; }
|
||||
}
|
||||
function writeJSON(p, obj) {
|
||||
fs.writeFileSync(p, JSON.stringify(obj, null, 2));
|
||||
}
|
||||
|
||||
let scene = readJSON(LIVE, null) || readJSON(SEED, { anchors: [], buildings: [], spawns: [], world: { units: 'm' } });
|
||||
let ghosts = readJSON(path.join(DATA, 'ghosts.json'), []);
|
||||
let gradients = readJSON(path.join(DATA, 'gradients.json'), {});
|
||||
let models = readJSON(MODELS_LIVE, null) || readJSON(MODELS_SEED, { models: [] });
|
||||
|
||||
const listeners = [];
|
||||
|
||||
function validateScene(s) {
|
||||
if (!s || typeof s !== 'object') throw new Error('scene must be object');
|
||||
for (const k of ['anchors', 'buildings', 'spawns']) {
|
||||
if (!Array.isArray(s[k])) throw new Error(`scene.${k} must be array`);
|
||||
}
|
||||
for (const a of s.anchors) {
|
||||
if (typeof a.markerId !== 'number') throw new Error('anchor.markerId required');
|
||||
if (!Array.isArray(a.position) || a.position.length !== 3) throw new Error('anchor.position [x,y,z] required');
|
||||
a.mount = a.mount || 'flat'; // 'flat' | 'wall' | 'custom'
|
||||
a.yawDeg = Number(a.yawDeg || 0);
|
||||
a.pitchDeg = Number(a.pitchDeg || 0);
|
||||
a.rollDeg = Number(a.rollDeg || 0);
|
||||
a.sizeMM = Number(a.sizeMM || 60); // printed marker size
|
||||
a.enabled = a.enabled !== false;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getScene: () => scene,
|
||||
putScene(s) {
|
||||
scene = validateScene(s);
|
||||
writeJSON(LIVE, scene);
|
||||
listeners.forEach(f => f());
|
||||
return scene;
|
||||
},
|
||||
resetToSeed() {
|
||||
scene = readJSON(SEED, scene);
|
||||
writeJSON(LIVE, scene);
|
||||
listeners.forEach(f => f());
|
||||
return scene;
|
||||
},
|
||||
getGhosts: () => ({ ghosts, gradients }),
|
||||
getModels: () => models,
|
||||
putModels(m) {
|
||||
if (!m || !Array.isArray(m.models)) throw new Error('models.models must be array');
|
||||
models = m; writeJSON(MODELS_LIVE, models); return models;
|
||||
},
|
||||
getPlaylistConfig: (fallback) => readJSON(PLAYLIST_LIVE, null) || readJSON(path.join(DATA, 'playlist.json'), fallback),
|
||||
putPlaylistConfig(cfg) { writeJSON(PLAYLIST_LIVE, cfg); return cfg; },
|
||||
onChange: (f) => listeners.push(f),
|
||||
};
|
||||
Reference in New Issue
Block a user