diff --git a/wwwroot/workbench/workbench.html b/wwwroot/workbench/workbench.html index 54a1b1a..cbde91e 100644 --- a/wwwroot/workbench/workbench.html +++ b/wwwroot/workbench/workbench.html @@ -32,6 +32,8 @@

🎮 游戏工作台

+ + diff --git a/wwwroot/workbench/workbench.js b/wwwroot/workbench/workbench.js index 3cf8314..c537f24 100644 --- a/wwwroot/workbench/workbench.js +++ b/wwwroot/workbench/workbench.js @@ -1,4 +1,4 @@ -/* 元景游戏工作台:game 聚合根单页编辑器 */ +/* 元景游戏工作台 v2:game 聚合根单页编辑器(内联输入,无 prompt) */ (function () { function api(path, params) { return fetch(path, { @@ -9,7 +9,7 @@ } function base() { return '/scense_game'; } - var state = { game: null, data: null, sel: null }; // sel: {type, id, name} + var state = { game: null, data: null, sel: null, games: [], cur_script: null, inline: null }; function msg(t, ok) { var el = document.getElementById('msg'); @@ -17,31 +17,54 @@ el.className = ok ? 'ok' : 'err'; } + function newGame() { + state.game = null; state.data = null; state.sel = null; state.cur_script = null; + document.getElementById('game_name').value = ''; + document.getElementById('game_sel').value = ''; + renderTree(null); + document.getElementById('cur_obj').textContent = '未选择对象'; + document.getElementById('code').value = ''; + msg('填写名称后点保存游戏(将自动创建 1:1 世界)', true); + } + function saveGame() { var name = document.getElementById('game_name').value.trim(); - if (state.game) { msg('游戏已存在: ' + state.game.id, true); return; } + if (state.game) { msg('当前游戏: ' + state.game.name + '(' + state.game.id + ')', true); return; } if (!name) { msg('先填游戏名称', false); return; } api(base() + '/game/api/game_create.dspy', {name: name, description: document.getElementById('game_shared').checked ? 'shared' : 'independent'}) .then(function (r) { - if (r.success) { msg('游戏创建成功,世界已自动建立', true); reload(); } + if (r.success) { msg('游戏创建成功,世界已自动建立', true); reload(r.data.game_id); } else msg(r.message || '创建失败', false); }); } - function reload() { - // 列表取第一个 game 或新建后带入 + function switchGame(gid) { + if (!gid) return; + state.game = null; state.sel = null; + reload(gid); + } + + function reload(forceGid) { api(base() + '/game/api/game_list.dspy', {}).then(function (r) { - var games = (r.data && r.data.games) || []; - if (!games.length) { state.game = null; renderTree(null); return; } - var gid = games[0].game_id || games[0].id; + var games = (r.data && r.data.games) || r || []; + if (!Array.isArray(games)) games = []; + state.games = games; + var sel = document.getElementById('game_sel'); + sel.innerHTML = '' + + games.map(function (g) { + var gid = g.game_id || g.id; + return ''; + }).join(''); + var gid = forceGid || (state.game && state.game.id) || (games[0] && (games[0].game_id || games[0].id)); + if (!gid) { state.game = null; renderTree(null); return; } + sel.value = gid; api(base() + '/game/api/game_workbench.dspy', {game_id: gid}).then(function (w) { if (!w.success) { msg(w.message, false); return; } state.game = w.data.game; state.data = w.data; document.getElementById('game_name').value = (w.data.game && w.data.game.name) || ''; renderTree(w.data); - if (!state.sel) selectWorld(); - else loadSel(); + if (state.sel) loadSelKeep(); else selectWorld(); }); }); } @@ -50,28 +73,68 @@ var el = document.getElementById('tree_body'); if (!d || !d.world) { el.innerHTML = '
尚无游戏,先填名称保存
'; return; } var h = ''; - h += '
🌍 ' + esc(d.world.name) + '
'; + h += node('world', d.world.id, '🌍 ' + esc(d.world.name)); (d.scenes || []).forEach(function (s) { - h += '
🎬 ' + esc(s.name) + '
'; + h += node('scene', s.id, '🎬 ' + esc(s.name), 12); }); - h += '
+ 场景
'; + h += addRow('scene', '+ 场景', 12); (d.entities || []).forEach(function (e) { - h += '
📦 ' + esc(e.name) + (e.scene_id ? '' : '(世界级)') + '
'; + h += node('entity', e.id, '📦 ' + esc(e.name) + (e.scene_id ? '' : '(世界级)'), 24); }); - h += '
+ 实体
'; + h += addRow('entity', '+ 实体', 24); el.innerHTML = h; } - function esc(s) { return String(s || '').replace(/'/g, "\\'").replace(/' + label + ''; + } + function addRow(type, label, ml) { + if (state.inline === type) { + return '
' + + '' + + '
' + + '
'; + } + return '
' + label + '
'; + } + function esc(s) { return String(s || '').replace(/