1.18更新

This commit is contained in:
RT15548
2026-01-18 20:04:43 +08:00
committed by GitHub
parent be142640c0
commit 03ba508a31
62 changed files with 18838 additions and 7264 deletions

View File

@@ -69,11 +69,6 @@ function extractPathFromArgs(namedArgs, unnamedArgs) {
}
}
function hasTopLevelRuleKey(obj) {
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return false;
return Object.keys(obj).some(k => String(k).trim().startsWith('$'));
}
function ensureAbsTargetPath(basePath, token) {
const t = String(token || '').trim();
if (!t) return String(basePath || '');
@@ -1012,4 +1007,4 @@ export function cleanupVarCommands() {
export {
MODULE_ID,
};
};

View File

@@ -3,10 +3,9 @@
* @description 条件规则编辑器与 varevent 运行时(常驻模块)
*/
import { getContext, extension_settings } from "../../../../../extensions.js";
import { getContext } from "../../../../../extensions.js";
import { getLocalVariable } from "../../../../../variables.js";
import { createModuleEvents, event_types } from "../../core/event-manager.js";
import { normalizePath, lwbSplitPathWithBrackets } from "../../core/variable-path.js";
import { createModuleEvents } from "../../core/event-manager.js";
import { replaceXbGetVarInString } from "./var-commands.js";
const MODULE_ID = 'vareventEditor';
@@ -48,13 +47,6 @@ function stripYamlInlineComment(s) {
return text;
}
function getActiveCharacter() {
try {
const ctx = getContext(); const id = ctx?.characterId ?? ctx?.this_chid; if (id == null) return null;
return (ctx?.getCharacter?.(id) ?? (Array.isArray(ctx?.characters) ? ctx.characters[id] : null)) || null;
} catch { return null; }
}
function readCharExtBumpAliases() {
try {
const ctx = getContext(); const id = ctx?.characterId ?? ctx?.this_chid; if (id == null) return {};
@@ -134,7 +126,7 @@ export function preprocessBumpAliases(innerText) {
const num = matchAlias(key, rhs) ?? matchAlias(currentVarRoot, rhs) ?? matchAlias('', rhs);
out.push(num !== null && Number.isFinite(num) ? raw.replace(/:\s*.*$/, `: ${num}`) : raw); continue;
}
const mArr = t.match(/^\-\s*(.+)$/);
const mArr = t.match(/^-\s*(.+)$/);
if (mArr) {
let rhs = String(stripYamlInlineComment(mArr[1])).trim().replace(/^["']|["']$/g, '');
const leafKey = stack.length ? stack[stack.length - 1].path.split('.').pop() : '';
@@ -174,6 +166,8 @@ export function parseVareventEvents(innerText) {
export function evaluateCondition(expr) {
const isNumericLike = (v) => v != null && /^-?\d+(?:\.\d+)?$/.test(String(v).trim());
// Used by eval() expression; keep in scope.
// eslint-disable-next-line no-unused-vars
function VAR(path) {
try {
const p = String(path ?? '').replace(/\[(\d+)\]/g, '.$1'), seg = p.split('.').map(s => s.trim()).filter(Boolean);
@@ -184,7 +178,11 @@ export function evaluateCondition(expr) {
return cur == null ? '' : typeof cur === 'object' ? JSON.stringify(cur) : String(cur);
} catch { return undefined; }
}
// Used by eval() expression; keep in scope.
// eslint-disable-next-line no-unused-vars
const VAL = (t) => String(t ?? '');
// Used by eval() expression; keep in scope.
// eslint-disable-next-line no-unused-vars
function REL(a, op, b) {
if (isNumericLike(a) && isNumericLike(b)) { const A = Number(String(a).trim()), B = Number(String(b).trim()); if (op === '>') return A > B; if (op === '>=') return A >= B; if (op === '<') return A < B; if (op === '<=') return A <= B; }
else { const A = String(a), B = String(b); if (op === '>') return A > B; if (op === '>=') return A >= B; if (op === '<') return A < B; if (op === '<=') return A <= B; }
@@ -193,6 +191,7 @@ export function evaluateCondition(expr) {
try {
let processed = expr.replace(/var\(`([^`]+)`\)/g, 'VAR("$1")').replace(/val\(`([^`]+)`\)/g, 'VAL("$1")');
processed = processed.replace(/(VAR\(".*?"\)|VAL\(".*?"\))\s*(>=|<=|>|<)\s*(VAR\(".*?"\)|VAL\(".*?"\))/g, 'REL($1,"$2",$3)');
// eslint-disable-next-line no-eval -- intentional: user-defined expression evaluation
return !!eval(processed);
} catch { return false; }
}
@@ -201,6 +200,7 @@ export async function runJS(code) {
const ctx = getContext();
try {
const STscriptProxy = async (command) => { if (!command) return; if (command[0] !== '/') command = '/' + command; const { executeSlashCommands, substituteParams } = getContext(); return await executeSlashCommands?.(substituteParams ? substituteParams(command) : command, true); };
// eslint-disable-next-line no-new-func -- intentional: user-defined async script
const fn = new Function('ctx', 'getVar', 'setVar', 'console', 'STscript', `return (async()=>{ ${code}\n })();`);
const getVar = (k) => getLocalVariable(k);
const setVar = (k, v) => { getContext()?.variables?.local?.set?.(k, v); };
@@ -410,6 +410,8 @@ function injectEditorStyles() {
const U = {
qa: (root, sel) => Array.from((root || document).querySelectorAll(sel)),
// Template-only UI markup.
// eslint-disable-next-line no-unsanitized/property
el: (tag, cls, html) => { const e = document.createElement(tag); if (cls) e.className = cls; if (html != null) e.innerHTML = html; return e; },
setActive(listLike, idx) { (Array.isArray(listLike) ? listLike : U.qa(document, listLike)).forEach((el, i) => el.classList.toggle('active', i === idx)); },
toast: { ok: (m) => window?.toastr?.success?.(m), warn: (m) => window?.toastr?.warning?.(m), err: (m) => window?.toastr?.error?.(m) },
@@ -497,7 +499,10 @@ const UI = {
addConditionRow(container, params) { const row = UI.createConditionRow(params, () => UI.refreshLopDisplay(container)); container.appendChild(row); UI.refreshLopDisplay(container); return row; },
parseConditionIntoUI(block, condStr) {
try {
const groupWrap = block.querySelector('.lwb-ve-condgroups'); if (!groupWrap) return; groupWrap.innerHTML = '';
const groupWrap = block.querySelector('.lwb-ve-condgroups'); if (!groupWrap) return;
// Template-only UI markup.
// eslint-disable-next-line no-unsanitized/property
groupWrap.innerHTML = '';
const top = P.splitTopWithOps(condStr);
top.forEach((seg, idxSeg) => {
const { text } = P.stripOuterWithFlag(seg.expr), g = UI.makeConditionGroup(); groupWrap.appendChild(g);
@@ -587,6 +592,8 @@ export function openVarEditor(entryEl, uid) {
U.qa(pagesWrap, '.lwb-ve-page').forEach(el => el.classList.remove('active')); page.classList.add('active');
let eventsWrap = page.querySelector(':scope > div'); if (!eventsWrap) { eventsWrap = U.el('div'); page.appendChild(eventsWrap); }
const init = () => {
// Template-only UI markup.
// eslint-disable-next-line no-unsanitized/property
eventsWrap.innerHTML = '';
if (!evts.length) eventsWrap.appendChild(UI.createEventBlock(1));
else evts.forEach((_ev, i) => { const block = UI.createEventBlock(i + 1); try { const condStr = String(_ev.condition || '').trim(); if (condStr) UI.parseConditionIntoUI(block, condStr); const disp = String(_ev.display || ''), dispEl = block.querySelector('.lwb-ve-display'); if (dispEl) dispEl.value = disp.replace(/^\r?\n/, '').replace(/\r?\n$/, ''); const js = String(_ev.js || ''), jsEl = block.querySelector('.lwb-ve-js'); if (jsEl) jsEl.value = js; } catch {} eventsWrap.appendChild(block); });
@@ -628,7 +635,29 @@ export function openActionBuilder(block) {
];
const ui = U.mini(`<div class="lwb-ve-section"><div class="lwb-ve-label">添加动作</div><div id="lwb-action-list"></div><button type="button" class="lwb-ve-btn" id="lwb-add-action">+动作</button></div>`, '常用st控制');
const list = ui.body.querySelector('#lwb-action-list'), addBtn = ui.body.querySelector('#lwb-add-action');
const addRow = (presetType) => { const row = U.el('div', 'lwb-ve-row'); row.style.alignItems = 'flex-start'; row.innerHTML = `<select class="lwb-ve-input lwb-ve-mini lwb-act-type"></select><div class="lwb-ve-fields" style="flex:1; display:grid; grid-template-columns: 1fr 1fr; gap:6px;"></div><button type="button" class="lwb-ve-btn ghost lwb-ve-del">删除</button>`; const typeSel = row.querySelector('.lwb-act-type'), fields = row.querySelector('.lwb-ve-fields'); row.querySelector('.lwb-ve-del').addEventListener('click', () => row.remove()); typeSel.innerHTML = TYPES.map(a => `<option value="${a.value}">${a.label}</option>`).join(''); const renderFields = () => { const def = TYPES.find(a => a.value === typeSel.value); fields.innerHTML = def ? def.template : ''; }; typeSel.addEventListener('change', renderFields); if (presetType) typeSel.value = presetType; renderFields(); list.appendChild(row); };
const addRow = (presetType) => {
const row = U.el('div', 'lwb-ve-row');
row.style.alignItems = 'flex-start';
// Template-only UI markup.
// eslint-disable-next-line no-unsanitized/property
row.innerHTML = `<select class="lwb-ve-input lwb-ve-mini lwb-act-type"></select><div class="lwb-ve-fields" style="flex:1; display:grid; grid-template-columns: 1fr 1fr; gap:6px;"></div><button type="button" class="lwb-ve-btn ghost lwb-ve-del">??</button>`;
const typeSel = row.querySelector('.lwb-act-type');
const fields = row.querySelector('.lwb-ve-fields');
row.querySelector('.lwb-ve-del').addEventListener('click', () => row.remove());
// Template-only UI markup.
// eslint-disable-next-line no-unsanitized/property
typeSel.innerHTML = TYPES.map(a => `<option value="${a.value}">${a.label}</option>`).join('');
const renderFields = () => {
const def = TYPES.find(a => a.value === typeSel.value);
// Template-only UI markup.
// eslint-disable-next-line no-unsanitized/property
fields.innerHTML = def ? def.template : '';
};
typeSel.addEventListener('change', renderFields);
if (presetType) typeSel.value = presetType;
renderFields();
list.appendChild(row);
};
addBtn.addEventListener('click', () => addRow()); addRow();
ui.btnOk.addEventListener('click', () => {
const rows = U.qa(list, '.lwb-ve-row'), actions = [];

View File

@@ -4,7 +4,7 @@
* @description 包含 plot-log 解析、快照回滚、变量守护
*/
import { getContext, extension_settings } from "../../../../../extensions.js";
import { getContext } from "../../../../../extensions.js";
import { updateMessageBlock } from "../../../../../../script.js";
import { getLocalVariable, setLocalVariable } from "../../../../../variables.js";
import { createModuleEvents, event_types } from "../../core/event-manager.js";
@@ -31,7 +31,6 @@ import {
import {
preprocessBumpAliases,
executeQueuedVareventJsAfterTurn,
drainPendingVareventBlocks,
stripYamlInlineComment,
OP_MAP,
TOP_OP_RE,
@@ -40,7 +39,6 @@ import {
/* ============= 模块常量 ============= */
const MODULE_ID = 'variablesCore';
const LWB_EXT_ID = 'LittleWhiteBox';
const LWB_RULES_KEY = 'LWB_RULES';
const LWB_SNAP_KEY = 'LWB_SNAP';
const LWB_PLOT_APPLIED_KEY = 'LWB_PLOT_APPLIED_KEY';
@@ -60,6 +58,8 @@ const guardianState = {
// 事件管理器
let events = null;
let initialized = false;
let pendingSwipeApply = new Map();
let suppressUpdatedOnce = new Set();
CacheRegistry.register(MODULE_ID, {
name: '变量系统缓存',
@@ -2146,9 +2146,9 @@ function getMsgIdStrict(payload) {
}
function bindEvents() {
const pendingSwipeApply = new Map();
pendingSwipeApply = new Map();
let lastSwipedId;
const suppressUpdatedOnce = new Set();
suppressUpdatedOnce = new Set();
// 消息发送
events?.on(event_types.MESSAGE_SENT, async () => {
@@ -2386,4 +2386,4 @@ export {
rulesSetTable,
rulesLoadFromMeta,
rulesSaveToMeta,
};
};

File diff suppressed because it is too large Load Diff