Update variables v2 state handling
This commit is contained in:
@@ -28,7 +28,7 @@ import {
|
||||
applyXbGetVarForMessage,
|
||||
parseValueForSet,
|
||||
} from "./var-commands.js";
|
||||
import { applyStateForMessage, clearStateAppliedFrom } from "./state2/index.js";
|
||||
import { applyStateForMessage } from "./state2/index.js";
|
||||
import {
|
||||
preprocessBumpAliases,
|
||||
executeQueuedVareventJsAfterTurn,
|
||||
@@ -1624,16 +1624,10 @@ function rollbackToPreviousOf(messageId) {
|
||||
const id = Number(messageId);
|
||||
if (Number.isNaN(id)) return;
|
||||
|
||||
clearStateAppliedFrom(id);
|
||||
|
||||
if (typeof globalThis.LWB_StateRollbackHook === 'function') {
|
||||
Promise.resolve(globalThis.LWB_StateRollbackHook(id)).catch((e) => {
|
||||
console.error('[variablesCore] LWB_StateRollbackHook failed:', e);
|
||||
});
|
||||
}
|
||||
const prevId = id - 1;
|
||||
if (prevId < 0) return;
|
||||
|
||||
// ???? 1.0 ???????
|
||||
const snap = getSnapshot(prevId);
|
||||
if (snap) {
|
||||
const normalized = normalizeSnapshotRecord(snap);
|
||||
@@ -1647,12 +1641,52 @@ function rollbackToPreviousOf(messageId) {
|
||||
}
|
||||
}
|
||||
|
||||
function rebuildVariablesFromScratch() {
|
||||
async function rollbackToPreviousOfAsync(messageId) {
|
||||
const id = Number(messageId);
|
||||
if (Number.isNaN(id)) return;
|
||||
|
||||
// ???????? floor>=id ? L0
|
||||
if (typeof globalThis.LWB_StateRollbackHook === 'function') {
|
||||
try {
|
||||
await globalThis.LWB_StateRollbackHook(id);
|
||||
} catch (e) {
|
||||
console.error('[variablesCore] LWB_StateRollbackHook failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
const prevId = id - 1;
|
||||
const mode = getVariablesMode();
|
||||
|
||||
if (mode === '2.0') {
|
||||
try {
|
||||
const mod = await import('./state2/index.js');
|
||||
await mod.restoreStateV2ToFloor(prevId); // prevId<0 ???
|
||||
} catch (e) {
|
||||
console.error('[variablesCore][2.0] restoreStateV2ToFloor failed:', e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// mode === '1.0'
|
||||
rollbackToPreviousOf(id);
|
||||
}
|
||||
|
||||
|
||||
async function rebuildVariablesFromScratch() {
|
||||
try {
|
||||
const mode = getVariablesMode();
|
||||
if (mode === '2.0') {
|
||||
const mod = await import('./state2/index.js');
|
||||
const chat = getContext()?.chat || [];
|
||||
const lastId = chat.length ? chat.length - 1 : -1;
|
||||
await mod.restoreStateV2ToFloor(lastId);
|
||||
return;
|
||||
}
|
||||
// 1.0 旧逻辑
|
||||
setVarDict({});
|
||||
const chat = getContext()?.chat || [];
|
||||
for (let i = 0; i < chat.length; i++) {
|
||||
applyVariablesForMessage(i);
|
||||
await applyVariablesForMessage(i);
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
@@ -1842,7 +1876,7 @@ async function applyVariablesForMessage(messageId) {
|
||||
} catch (e) {
|
||||
parseErrors++;
|
||||
if (debugOn) {
|
||||
try { xbLog.error(MODULE_ID, `plot-log è§£æž<EFBFBD>失败:楼å±?${messageId} å<EFBFBD>?${idx + 1} 预览=${preview(b)}`, e); } catch {}
|
||||
try { xbLog.error(MODULE_ID, `plot-log 解析失败:楼<EFBFBD>?${messageId} <20>?${idx + 1} 预览=${preview(b)}`, e); } catch {}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1873,7 +1907,7 @@ async function applyVariablesForMessage(messageId) {
|
||||
try {
|
||||
xbLog.warn(
|
||||
MODULE_ID,
|
||||
`plot-log 未产生å<EFBFBD>¯æ‰§è¡ŒæŒ‡ä»¤ï¼šæ¥¼å±?${messageId} å<EFBFBD>—æ•°=${blocks.length} è§£æž<EFBFBD>æ<EFBFBD>¡ç›®=${parsedPartsTotal} è§£æž<EFBFBD>失败=${parseErrors} 预览=${preview(blocks[0])}`
|
||||
`plot-log 未产生可执行指令:楼<EFBFBD>?${messageId} 块数=${blocks.length} 解析条目=${parsedPartsTotal} 解析失败=${parseErrors} 预览=${preview(blocks[0])}`
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
@@ -2149,7 +2183,7 @@ async function applyVariablesForMessage(messageId) {
|
||||
const denied = guardDenied ? `,被规则拦截=${guardDenied}` : '';
|
||||
xbLog.warn(
|
||||
MODULE_ID,
|
||||
`plot-log 指令执行å<EFBFBD>Žæ— å<EFBFBD>˜åŒ–:楼å±?${messageId} 指令æ•?${ops.length}${denied} 示例=${preview(JSON.stringify(guardDeniedSamples))}`
|
||||
`plot-log 指令执行后无变化:楼<EFBFBD>?${messageId} 指令<EFBFBD>?${ops.length}${denied} 示例=${preview(JSON.stringify(guardDeniedSamples))}`
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
@@ -2218,7 +2252,7 @@ function bindEvents() {
|
||||
|
||||
events?.on(event_types.MESSAGE_SENT, async () => {
|
||||
try {
|
||||
snapshotCurrentLastFloor();
|
||||
if (getVariablesMode() !== '2.0') snapshotCurrentLastFloor();
|
||||
const chat = getContext()?.chat || [];
|
||||
const id = chat.length ? chat.length - 1 : undefined;
|
||||
if (typeof id === 'number') {
|
||||
@@ -2247,7 +2281,7 @@ function bindEvents() {
|
||||
if (typeof id === 'number') {
|
||||
await applyVarsForMessage(id);
|
||||
applyXbGetVarForMessage(id, true);
|
||||
snapshotForMessageId(id);
|
||||
if (getVariablesMode() !== '2.0') snapshotForMessageId(id);
|
||||
}
|
||||
} catch {}
|
||||
});
|
||||
@@ -2259,7 +2293,7 @@ function bindEvents() {
|
||||
if (typeof id === 'number') {
|
||||
await applyVarsForMessage(id);
|
||||
applyXbGetVarForMessage(id, true);
|
||||
snapshotForMessageId(id);
|
||||
if (getVariablesMode() !== '2.0') snapshotForMessageId(id);
|
||||
}
|
||||
} catch {}
|
||||
});
|
||||
@@ -2283,33 +2317,35 @@ function bindEvents() {
|
||||
events?.on(event_types.MESSAGE_EDITED, async (data) => {
|
||||
try {
|
||||
const id = getMsgIdLoose(data);
|
||||
if (typeof id === 'number') {
|
||||
clearAppliedFor(id);
|
||||
rollbackToPreviousOf(id);
|
||||
if (typeof id !== 'number') return;
|
||||
|
||||
setTimeout(async () => {
|
||||
await applyVarsForMessage(id);
|
||||
applyXbGetVarForMessage(id, true);
|
||||
if (getVariablesMode() !== '2.0') clearAppliedFor(id);
|
||||
|
||||
try {
|
||||
const ctx = getContext();
|
||||
const msg = ctx?.chat?.[id];
|
||||
if (msg) updateMessageBlock(id, msg, { rerenderMessage: true });
|
||||
} catch {}
|
||||
// ? ?? await????? apply ????????????
|
||||
await rollbackToPreviousOfAsync(id);
|
||||
|
||||
try {
|
||||
const ctx = getContext();
|
||||
const es = ctx?.eventSource;
|
||||
const et = ctx?.event_types;
|
||||
if (es?.emit && et?.MESSAGE_UPDATED) {
|
||||
suppressUpdatedOnce.add(id);
|
||||
await es.emit(et.MESSAGE_UPDATED, id);
|
||||
}
|
||||
} catch {}
|
||||
setTimeout(async () => {
|
||||
await applyVarsForMessage(id);
|
||||
applyXbGetVarForMessage(id, true);
|
||||
|
||||
await executeQueuedVareventJsAfterTurn();
|
||||
}, 10);
|
||||
}
|
||||
try {
|
||||
const ctx = getContext();
|
||||
const msg = ctx?.chat?.[id];
|
||||
if (msg) updateMessageBlock(id, msg, { rerenderMessage: true });
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
const ctx = getContext();
|
||||
const es = ctx?.eventSource;
|
||||
const et = ctx?.event_types;
|
||||
if (es?.emit && et?.MESSAGE_UPDATED) {
|
||||
suppressUpdatedOnce.add(id);
|
||||
await es.emit(et.MESSAGE_UPDATED, id);
|
||||
}
|
||||
} catch {}
|
||||
|
||||
await executeQueuedVareventJsAfterTurn();
|
||||
}, 10);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
@@ -2317,28 +2353,44 @@ function bindEvents() {
|
||||
events?.on(event_types.MESSAGE_SWIPED, async (data) => {
|
||||
try {
|
||||
const id = getMsgIdLoose(data);
|
||||
if (typeof id === 'number') {
|
||||
lastSwipedId = id;
|
||||
clearAppliedFor(id);
|
||||
rollbackToPreviousOf(id);
|
||||
if (typeof id !== 'number') return;
|
||||
|
||||
const tId = setTimeout(async () => {
|
||||
pendingSwipeApply.delete(id);
|
||||
await applyVarsForMessage(id);
|
||||
await executeQueuedVareventJsAfterTurn();
|
||||
}, 10);
|
||||
lastSwipedId = id;
|
||||
if (getVariablesMode() !== '2.0') clearAppliedFor(id);
|
||||
|
||||
pendingSwipeApply.set(id, tId);
|
||||
}
|
||||
// ? ?? await???????????????
|
||||
await rollbackToPreviousOfAsync(id);
|
||||
|
||||
const tId = setTimeout(async () => {
|
||||
pendingSwipeApply.delete(id);
|
||||
await applyVarsForMessage(id);
|
||||
await executeQueuedVareventJsAfterTurn();
|
||||
}, 10);
|
||||
|
||||
pendingSwipeApply.set(id, tId);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
// message deleted
|
||||
events?.on(event_types.MESSAGE_DELETED, (data) => {
|
||||
events?.on(event_types.MESSAGE_DELETED, async (data) => {
|
||||
try {
|
||||
const id = getMsgIdStrict(data);
|
||||
if (typeof id === 'number') {
|
||||
rollbackToPreviousOf(id);
|
||||
if (typeof id !== 'number') return;
|
||||
|
||||
// ? ????????await ???????
|
||||
await rollbackToPreviousOfAsync(id);
|
||||
|
||||
// ✅ 2.0:物理删除消息 => 同步清理 WAL/ckpt,避免膨胀
|
||||
if (getVariablesMode() === '2.0') {
|
||||
try {
|
||||
const mod = await import('./state2/index.js');
|
||||
await mod.trimStateV2FromFloor(id);
|
||||
} catch (e) {
|
||||
console.error('[variablesCore][2.0] trimStateV2FromFloor failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
if (getVariablesMode() !== '2.0') {
|
||||
clearSnapshotsFrom(id);
|
||||
clearAppliedFrom(id);
|
||||
}
|
||||
@@ -2349,7 +2401,7 @@ function bindEvents() {
|
||||
|
||||
events?.on(event_types.GENERATION_STARTED, (data) => {
|
||||
try {
|
||||
snapshotPreviousFloor();
|
||||
if (getVariablesMode() !== '2.0') snapshotPreviousFloor();
|
||||
|
||||
// cancel swipe delay
|
||||
const t = (typeof data === 'string' ? data : (data?.type || '')).toLowerCase();
|
||||
@@ -2364,7 +2416,7 @@ function bindEvents() {
|
||||
});
|
||||
|
||||
// chat changed
|
||||
events?.on(event_types.CHAT_CHANGED, () => {
|
||||
events?.on(event_types.CHAT_CHANGED, async () => {
|
||||
try {
|
||||
rulesClearCache();
|
||||
rulesLoadFromMeta();
|
||||
@@ -2372,6 +2424,13 @@ function bindEvents() {
|
||||
const meta = getContext()?.chatMetadata || {};
|
||||
meta[LWB_PLOT_APPLIED_KEY] = {};
|
||||
getContext()?.saveMetadataDebounced?.();
|
||||
|
||||
if (getVariablesMode() === '2.0') {
|
||||
try {
|
||||
const mod = await import('./state2/index.js');
|
||||
mod.clearStateAppliedFrom(0);
|
||||
} catch {}
|
||||
}
|
||||
} catch {}
|
||||
});
|
||||
}
|
||||
@@ -2408,6 +2467,33 @@ export function initVariablesCore() {
|
||||
applyDeltaTable: applyRulesDeltaToTable,
|
||||
save: rulesSaveToMeta,
|
||||
};
|
||||
|
||||
globalThis.LWB_StateV2 = {
|
||||
/**
|
||||
* @param {string} text - 包含 <state>...</state> 的文本
|
||||
* @param {{ floor?: number, silent?: boolean }} [options]
|
||||
* - floor: 指定写入/记录用楼层(默认:最后一楼)
|
||||
* - silent: true 时不触发 stateAtomsGenerated(初始化用)
|
||||
*/
|
||||
applyText: async (text, options = {}) => {
|
||||
const { applyStateForMessage } = await import('./state2/index.js');
|
||||
const ctx = getContext();
|
||||
const floor =
|
||||
Number.isFinite(options.floor)
|
||||
? Number(options.floor)
|
||||
: Math.max(0, (ctx?.chat?.length || 1) - 1);
|
||||
const result = applyStateForMessage(floor, String(text || ''));
|
||||
// ✅ 默认会触发(当作事件)
|
||||
// ✅ 初始化时 silent=true,不触发(当作基线写入)
|
||||
if (!options.silent && result?.atoms?.length) {
|
||||
$(document).trigger('xiaobaix:variables:stateAtomsGenerated', {
|
||||
messageId: floor,
|
||||
atoms: result.atoms,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2429,6 +2515,7 @@ export function cleanupVariablesCore() {
|
||||
|
||||
// clear global hooks
|
||||
delete globalThis.LWB_Guard;
|
||||
delete globalThis.LWB_StateV2;
|
||||
|
||||
// clear guard state
|
||||
guardBypass(false);
|
||||
@@ -2454,4 +2541,4 @@ export {
|
||||
rulesSetTable,
|
||||
rulesLoadFromMeta,
|
||||
rulesSaveToMeta,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user