144 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 元景游戏工作台game 聚合根单页编辑器 */
(function () {
function api(path, params) {
return fetch(path, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(params || {})
}).then(function (r) { return r.json(); });
}
function base() { return '/scense_game'; }
var state = { game: null, data: null, sel: null }; // sel: {type, id, name}
function msg(t, ok) {
var el = document.getElementById('msg');
el.textContent = t;
el.className = ok ? 'ok' : 'err';
}
function saveGame() {
var name = document.getElementById('game_name').value.trim();
if (state.game) { msg('游戏已存在: ' + 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(); }
else msg(r.message || '创建失败', false);
});
}
function reload() {
// 列表取第一个 game 或新建后带入
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;
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();
});
});
}
function renderTree(d) {
var el = document.getElementById('tree_body');
if (!d || !d.world) { el.innerHTML = '<div style="color:#9CA3AF">尚无游戏,先填名称保存</div>'; return; }
var h = '';
h += '<div class="node' + (state.sel && state.sel.type === 'world' ? ' sel' : '') + '" onclick="wb.selObj(\'world\',\'' + d.world.id + '\',\'' + esc(d.world.name) + '\')">🌍 ' + esc(d.world.name) + '</div>';
(d.scenes || []).forEach(function (s) {
h += '<div class="node' + (state.sel && state.sel.id === s.id ? ' sel' : '') + '" style="margin-left:12px" onclick="wb.selObj(\'scene\',\'' + s.id + '\',\'' + esc(s.name) + '\')">🎬 ' + esc(s.name) + '</div>';
});
h += '<div class="node" style="margin-left:12px;color:#2563EB" onclick="wb.addScene()"> 场景</div>';
(d.entities || []).forEach(function (e) {
h += '<div class="node' + (state.sel && state.sel.id === e.id ? ' sel' : '') + '" style="margin-left:24px" onclick="wb.selObj(\'entity\',\'' + e.id + '\',\'' + esc(e.name) + '\')">📦 ' + esc(e.name) + (e.scene_id ? '' : '(世界级)') + '</div>';
});
h += '<div class="node" style="margin-left:24px;color:#2563EB" onclick="wb.addEntity()"> 实体</div>';
el.innerHTML = h;
}
function esc(s) { return String(s || '').replace(/'/g, "\\'").replace(/</g, '&lt;'); }
function selectWorld() { if (state.data && state.data.world) selObj('world', state.data.world.id, state.data.world.name); }
function selObj(type, id, name) {
state.sel = {type: type, id: id, name: name};
document.getElementById('cur_obj').textContent =
({world: '🌍 世界', scene: '🎬 场景', entity: '📦 实体'})[type] + ' · ' + name;
renderTree(state.data);
loadScript();
}
function bindParams() {
var s = state.sel;
if (!s) return null;
var p = {game_id: state.game.id, trigger_event: document.getElementById('event_sel').value};
if (s.type === 'world') p.world_id = s.id;
if (s.type === 'scene') p.scene_id = s.id;
if (s.type === 'entity') p.entity_id = s.id;
return p;
}
function loadScript() {
var p = bindParams();
if (!p) return;
var sc = (state.data.scripts || []).find(function (x) {
return (state.sel.type === 'world' && x.world_id === state.sel.id && x.trigger_event === p.trigger_event) ||
(state.sel.type === 'scene' && x.scene_id === state.sel.id && x.trigger_event === p.trigger_event) ||
(state.sel.type === 'entity' && x.entity_id === state.sel.id && x.trigger_event === p.trigger_event);
});
document.getElementById('code').value = sc ? (sc.content || '') : '';
state.cur_script = sc || null;
}
function saveScript() {
var p = bindParams();
if (!p) { msg('先选择对象', false); return; }
p.name = state.sel.name + '_' + p.trigger_event;
p.code = 'SC_' + (state.cur_script ? state.cur_script.code : (state.sel.id.slice(0, 8) + '_' + p.trigger_event));
p.content = document.getElementById('code').value;
p.script_type = '0';
if (state.cur_script) p.id = state.cur_script.id;
var url = state.cur_script ? '/script_engine/api/script_engine_update.dspy' : '/script_engine/api/script_engine_create.dspy';
api(url, p).then(function (r) {
if (r && r.success === false) { msg(r.error || r.message || '保存失败', false); return; }
msg(state.cur_script ? '脚本已更新' : '脚本已保存', true);
reload();
}).catch(function (e) { msg('保存失败: ' + e, false); });
}
function validate() {
api('/script_engine/api/validate_script.dspy', {content: document.getElementById('code').value})
.then(function (r) { msg(JSON.stringify(r).slice(0, 200), true); });
}
function addScene() {
var name = prompt('场景名称');
if (!name) return;
api(base() + '/game/api/scene_add.dspy', {game_id: state.game.id, name: name})
.then(function (r) { r.success ? (msg('场景已加', true), reload()) : msg(r.message, false); });
}
function addEntity() {
var name = prompt('实体名称留空场景ID=世界级实体)');
if (!name) return;
var sceneId = state.sel && state.sel.type === 'scene' ? state.sel.id : '';
api(base() + '/game/api/entity_add.dspy', {game_id: state.game.id, scene_id: sceneId, name: name})
.then(function (r) { r.success ? (msg('实体已加', true), reload()) : msg(r.message, false); });
}
function test() {
if (!state.game) { msg('先保存游戏', false); return; }
var wid = state.data && state.data.world ? state.data.world.id : '';
window.open('/scense_demo/demo_viewer.ui?world_id=' + wid + '&game_id=' + state.game.id, '_blank');
}
window.wb = {saveGame: saveGame, reload: reload, selObj: selObj, addScene: addScene,
addEntity: addEntity, saveScript: saveScript, validate: validate, test: test};
reload();
})();