小井盖改为自绘 GM 窗口(WebView2)+ 背包可见 + 启动器互斥

- 90CN.dll:新增 90CN_gm_window.cpp,自绘标题栏/边框的置顶窗口,内嵌 WebView2 承载 gmweb 页面
- 点小井盖时隐藏游戏内嵌 IE 面板、弹出控制台;关掉后还原,独占全屏压不住时可选 minimize_game
- 窗口每轮确认置顶,避免游戏抢窗口栈后消失
- gmweb:新增背包页,发放后自动跳转并高亮新入包的行(GET /local/dnf-gm/inventory/list)
- 启动器:新增 /console-status,控制台运行时置灰 GM 工具入口并阻止进入
- 服务端指纹回绑新 DLL(1258496 / 7A179B1B…)
This commit is contained in:
hanfuit committed 2026-11-05 13:16:52 +08:00
1 parent e9a3952a9d
commit b22579658e
10 files changed
+1246 -97

No files matched your search

+75 -2
View File
@@ -4,7 +4,7 @@
'use strict';
var S = {
charId: '', charName: '', chars: [],
charId: '', charName: '', chars: [], bagRows: [],
itemId: 0, itemName: '', picked: null, items: [],
page: 1, pageSize: 20, total: 0
};
@@ -66,6 +66,7 @@
for (var j = 0; j < panes.length; j++) {
panes[j].className = 'pane' + (panes[j].id === 'pane-' + name ? ' on' : '');
}
if (name === 'bag') { loadBag(0); }
}
function bindTabs() {
@@ -383,6 +384,10 @@
var data = d.data || {};
log('已发 ' + S.itemName + ' ×' + n + optText(o) +
(data.slot != null ? ',格位 ' + data.list_type + ':' + data.slot : ''), 'ok');
// 发完立刻切到背包页并高亮这一行:到底有没有进包,玩家要看得见
switchTab('bag');
loadBag(S.itemId);
setTimeout(function () { loadBag(S.itemId); }, 600);
});
}
@@ -401,6 +406,64 @@
});
}
/* ---------------------------------------------------------------- 背包 */
/* 背包 / 穿戴的实时快照。GM 发完东西,玩家第一件事就是看它到底进没进包,
所以这里按服务端实际存的行来列,不做任何本地猜测。 */
function loadBag(highlightItemId) {
if (!S.charId) {
$('bag-list').innerHTML = '<div class="empty">先在「角色」页选一个角色</div>';
$('bag-info').innerHTML = '-';
return;
}
api('/local/dnf-gm/inventory/list?character_id=' + encodeURIComponent(S.charId),
'GET', null, function (d) {
if (!d) { return; }
var data = d.data || {};
S.bagRows = data.rows || [];
renderBag(highlightItemId || 0);
});
}
function renderBag(highlightItemId) {
var box = $('bag-list');
var rows = S.bagRows || [];
var bagCount = 0, wearCount = 0, i;
for (i = 0; i < rows.length; i++) {
if (rows[i].collection === 'wear') { wearCount++; } else { bagCount++; }
}
$('bag-info').innerHTML = '背包 ' + bagCount + ' 件 · 穿戴 ' + wearCount + ' 件';
if (!rows.length) {
box.innerHTML = '<div class="empty">背包是空的</div>';
return;
}
// 刚发进去的排在最前面,其余保持服务端顺序
var ordered = [];
if (highlightItemId) {
for (i = 0; i < rows.length; i++) {
if (rows[i].item_id === highlightItemId) { ordered.push(rows[i]); }
}
}
for (i = 0; i < rows.length; i++) {
if (!highlightItemId || rows[i].item_id !== highlightItemId) { ordered.push(rows[i]); }
}
var h = [];
for (i = 0; i < ordered.length; i++) {
var r = ordered[i];
var isNew = highlightItemId && r.item_id === highlightItemId;
h.push('<div class="li' + (isNew ? ' on' : '') + '">' +
'<span class="nm">' + esc(r.item_name || ('物品 ' + r.item_id)) +
(isNew ? ' <em class="new">新</em>' : '') + '</span>' +
'<span class="meta">' + (r.collection === 'wear' ? '穿戴' : '背包') +
' · ' + esc(r.entry_key) + ' · id ' + esc(r.item_id) +
(r.count > 1 ? ' ×' + esc(r.count) : '') + '</span></div>');
}
box.innerHTML = h.join('');
}
/* ---------------------------------------------------------------- 邮件 */
function sendMail() {
@@ -452,6 +515,7 @@
bind('btn-prev', function () { if (S.page > 1) { loadItems(S.page - 1); } });
bind('btn-next', function () { loadItems(S.page + 1); });
bind('btn-grant', grantItem);
bind('btn-bag', function () { loadBag(0); });
bind('btn-mailitem', mailItem);
bind('btn-mail', sendMail);
@@ -473,7 +537,16 @@
}
$('q-char').onkeydown = function (e) { if ((e || window.event).keyCode === 13) { loadChars(); } };
$('q-item').onkeydown = function (e) { if ((e || window.event).keyCode === 13) { loadItems(1); } };
$('q-item').onkeydown = function (e) {
e = e || window.event;
// 229 是输入法组合中的键码,这时候的回车是上屏,不能抢。
if (e.keyCode === 229) { return; }
if (e.keyCode === 13) {
if (e.preventDefault) { e.preventDefault(); }
loadItems(1);
return false;
}
};
fillTypeOptions();