一键换装内嵌 gmweb:取消独立 exe 启动并支持页面热键
This commit is contained in:
1 parent
ab778e9e4c
commit
1e936bfb84
3 files changed
+153
-19
No files matched your search
@@ -151,6 +151,11 @@
|
||||
<div class="row">
|
||||
<button id="lo-save" class="btn pri">保存当前装备为方案</button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button id="lo-scheme-add" class="btn sm">新增方案</button>
|
||||
<button id="lo-scheme-ren" class="btn sm">重命名</button>
|
||||
<button id="lo-scheme-del" class="btn sm">删除</button>
|
||||
</div>
|
||||
<div class="hint">保存后会给当前角色创建一套换装方案。</div>
|
||||
<div id="lo-hotkeys" class="hint"></div>
|
||||
</div>
|
||||
@@ -158,6 +163,11 @@
|
||||
<div class="sec">方案详情</div>
|
||||
<div id="lo-detail" class="cur">未选择方案</div>
|
||||
<div id="lo-slots" class="lo-slots"></div>
|
||||
<div class="row">
|
||||
<button id="lo-hotkey" class="btn">设置快捷键</button>
|
||||
<button id="lo-hotkey-clear" class="btn sm">清除</button>
|
||||
<span id="lo-hotkey-text" class="dim"></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button id="lo-apply" class="btn pri">应用方案</button>
|
||||
<span id="lo-cooldown" class="dim"></span>
|
||||
|
||||
@@ -200,10 +200,14 @@
|
||||
if (!sc) {
|
||||
detail.innerHTML = '未选择方案';
|
||||
slotsBox.innerHTML = '';
|
||||
var emptyHotkey = $('lo-hotkey-text');
|
||||
if (emptyHotkey) { emptyHotkey.innerHTML = ''; }
|
||||
return;
|
||||
}
|
||||
detail.innerHTML = '<b>' + esc(sc.Name || '') + '</b>' +
|
||||
'<span class="lo-scheme-meta">' + esc(sc.CharacterName || '未绑定角色') + '</span>';
|
||||
var hotkeyTextEl = $('lo-hotkey-text');
|
||||
if (hotkeyTextEl) { hotkeyTextEl.innerHTML = '快捷键:' + esc(hotkeyText(sc)); }
|
||||
var slots = sc.Slots || [];
|
||||
if (!slots.length) {
|
||||
slotsBox.innerHTML = '<div class="lo-empty">该方案没有保存装备</div>';
|
||||
@@ -217,6 +221,123 @@
|
||||
slotsBox.innerHTML = h.join('');
|
||||
}
|
||||
|
||||
function hotkeyText(sc) {
|
||||
if (!sc || !sc.KeyCode) { return '未设置'; }
|
||||
var parts = modText(sc.Modifiers || 0);
|
||||
parts.push(keyText(sc.KeyCode));
|
||||
return parts.join('+');
|
||||
}
|
||||
|
||||
function currentScheme() {
|
||||
var page = currentPage();
|
||||
var schemes = (page && page.Schemes) || [];
|
||||
return schemes[S.scheme] || null;
|
||||
}
|
||||
|
||||
function setHotkey() {
|
||||
var sc = currentScheme();
|
||||
if (!sc) { msg('请先选择方案'); return; }
|
||||
S.capture = true;
|
||||
msg('请按下快捷键,Esc 取消');
|
||||
var handler = function (ev) {
|
||||
ev = ev || window.event;
|
||||
var code = ev.keyCode || ev.which;
|
||||
if (code === 27) {
|
||||
S.capture = false;
|
||||
document.removeEventListener('keydown', handler, true);
|
||||
msg('已取消设置快捷键');
|
||||
return false;
|
||||
}
|
||||
if (!code || code === 16 || code === 17 || code === 18) {
|
||||
return false;
|
||||
}
|
||||
var mods = 0;
|
||||
if (ev.ctrlKey) { mods |= 2; }
|
||||
if (ev.altKey) { mods |= 1; }
|
||||
if (ev.shiftKey) { mods |= 4; }
|
||||
sc.KeyCode = code;
|
||||
sc.Modifiers = mods;
|
||||
S.capture = false;
|
||||
document.removeEventListener('keydown', handler, true);
|
||||
saveConfig(function (ok) {
|
||||
if (ok) {
|
||||
renderDetail();
|
||||
loadHotkeys();
|
||||
msg('快捷键已保存:' + hotkeyText(sc));
|
||||
}
|
||||
});
|
||||
if (ev.preventDefault) { ev.preventDefault(); }
|
||||
return false;
|
||||
};
|
||||
document.addEventListener('keydown', handler, true);
|
||||
}
|
||||
|
||||
function clearHotkey() {
|
||||
var sc = currentScheme();
|
||||
if (!sc) { msg('请先选择方案'); return; }
|
||||
sc.KeyCode = 0;
|
||||
sc.Modifiers = 0;
|
||||
saveConfig(function (ok) {
|
||||
if (ok) {
|
||||
renderDetail();
|
||||
loadHotkeys();
|
||||
msg('快捷键已清除');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addScheme() {
|
||||
var page = currentPage();
|
||||
if (!page) { return; }
|
||||
var name = window.prompt('方案名称', '方案' + ((page.Schemes || []).length + 1));
|
||||
if (!name) { return; }
|
||||
var character = window.prompt('绑定角色游戏内名称', S.charName || '') || '';
|
||||
page.Schemes = page.Schemes || [];
|
||||
page.Schemes.push({
|
||||
Name: String(name),
|
||||
CharacterName: String(character),
|
||||
Modifiers: 0,
|
||||
KeyCode: 0,
|
||||
Slots: []
|
||||
});
|
||||
S.scheme = page.Schemes.length - 1;
|
||||
saveConfig(function (ok) {
|
||||
if (ok) {
|
||||
renderSchemes();
|
||||
msg('已新增方案:' + name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renameScheme() {
|
||||
var sc = currentScheme();
|
||||
if (!sc) { msg('请先选择方案'); return; }
|
||||
var name = window.prompt('重命名方案', sc.Name || '');
|
||||
if (!name) { return; }
|
||||
sc.Name = String(name);
|
||||
saveConfig(function (ok) {
|
||||
if (ok) {
|
||||
renderSchemes();
|
||||
msg('方案已重命名');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteScheme() {
|
||||
var page = currentPage();
|
||||
var sc = currentScheme();
|
||||
if (!page || !sc) { msg('请先选择方案'); return; }
|
||||
if (!window.confirm('删除方案“' + (sc.Name || '') + '”?')) { return; }
|
||||
page.Schemes.splice(S.scheme, 1);
|
||||
S.scheme = -1;
|
||||
saveConfig(function (ok) {
|
||||
if (ok) {
|
||||
renderSchemes();
|
||||
msg('方案已删除');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadChars() {
|
||||
api('/loadout/characters', 'GET', null, function (d) {
|
||||
if (!d) { msg('角色读取失败,确认服务端已启动'); return; }
|
||||
@@ -347,8 +468,15 @@
|
||||
sel.onchange = function () {
|
||||
S.page = parseInt(this.value, 10) || 0;
|
||||
S.scheme = -1;
|
||||
if (S.cfg) { S.cfg.ActivePage = S.page; }
|
||||
renderSchemes();
|
||||
loadHotkeys();
|
||||
// The launcher hotkey worker reads ActivePage from config.json. Persist
|
||||
// the page switch here, otherwise a hotkey assigned on this page never
|
||||
// becomes the active page's hotkey.
|
||||
saveConfig(function (ok) {
|
||||
if (ok) { loadHotkeys(); }
|
||||
});
|
||||
};
|
||||
}
|
||||
var ch = $('lo-char');
|
||||
@@ -360,6 +488,11 @@
|
||||
if ((b = $('lo-page-add'))) { b.onclick = addPage; }
|
||||
if ((b = $('lo-page-ren'))) { b.onclick = renamePage; }
|
||||
if ((b = $('lo-page-del'))) { b.onclick = deletePage; }
|
||||
if ((b = $('lo-scheme-add'))) { b.onclick = addScheme; }
|
||||
if ((b = $('lo-scheme-ren'))) { b.onclick = renameScheme; }
|
||||
if ((b = $('lo-scheme-del'))) { b.onclick = deleteScheme; }
|
||||
if ((b = $('lo-hotkey'))) { b.onclick = setHotkey; }
|
||||
if ((b = $('lo-hotkey-clear'))) { b.onclick = clearHotkey; }
|
||||
}
|
||||
|
||||
function loadTab() {
|
||||
|
||||
+10
-19
@@ -134,9 +134,6 @@ PVF_PATH = os.path.join(CLIENT_DIR, "Script.pvf")
|
||||
|
||||
# 一键换装工具(独立工具,放在服务端根目录的 LoadoutTool 文件夹下)
|
||||
LOADOUT_DIR = os.path.join(SERVER_ROOT, "LoadoutTool")
|
||||
LOADOUT_EXE = os.path.join(LOADOUT_DIR, "换装工具.exe")
|
||||
if not os.path.exists(LOADOUT_EXE):
|
||||
LOADOUT_EXE = os.path.join(LOADOUT_DIR, "DNFLoadout.exe")
|
||||
|
||||
# 一键换装的持久化配置路径
|
||||
LOADOUT_CONFIG = os.path.join(LOADOUT_DIR, "config.json")
|
||||
@@ -767,25 +764,19 @@ def flow_stop_server():
|
||||
|
||||
|
||||
def flow_launch_loadout():
|
||||
"""一键换装:启动 DNFLoadout.exe。"""
|
||||
log("== 一键换装 ==")
|
||||
if not os.path.exists(LOADOUT_EXE):
|
||||
log("[错误] 找不到换装工具:%s" % LOADOUT_EXE)
|
||||
return
|
||||
"""One-click loadout: open the embedded gmweb loadout page."""
|
||||
log("== One-click loadout ==")
|
||||
if not server_running():
|
||||
log("[提示] 服务端未运行,换装工具可能无法连接。建议先「开始游戏」。")
|
||||
log("正在启动换装工具…")
|
||||
log("[hint] server is not running; loadout may not read characters/equipment")
|
||||
url = "http://127.0.0.1:%d/#loadout" % GM_WEB_PORT
|
||||
log("opening loadout page: %s" % url)
|
||||
try:
|
||||
subprocess.Popen(
|
||||
[LOADOUT_EXE], cwd=LOADOUT_DIR,
|
||||
creationflags=DETACHED_PROCESS | CREATE_NO_WINDOW,
|
||||
close_fds=True)
|
||||
log("换装工具已启动。")
|
||||
webbrowser.open(url)
|
||||
log("loadout page opened; the in-game GM window has the same tab")
|
||||
except Exception as e:
|
||||
log("[错误] 启动失败:%s" % repr(e))
|
||||
log("[error] open failed: %s" % repr(e))
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ 数据库 / Native 客户端初始化
|
||||
# ------------------------------------------------------------------ Database / Native client initialization
|
||||
def load_instance(path):
|
||||
if not path or not os.path.exists(path):
|
||||
return {}
|
||||
@@ -1074,7 +1065,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||
"client_dir_exists": os.path.isdir(client_dir),
|
||||
"control_exists": os.path.exists(CONTROL),
|
||||
"sponsor_exists": os.path.exists(SPONSOR_IMG),
|
||||
"loadout_exists": os.path.exists(LOADOUT_EXE),
|
||||
"loadout_exists": True,
|
||||
"db": DB_PATH,
|
||||
"db_exists": bool(DB_PATH) and os.path.exists(DB_PATH),
|
||||
"native_available": NATIVE is not None,
|
||||
|
||||
Reference in new issue
Block a user