mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-13 18:31:16 +08:00
304 lines
8.0 KiB
JavaScript
304 lines
8.0 KiB
JavaScript
// ST-BME: 隐藏旧楼层引擎
|
||
// 通过临时把旧楼层标记为 is_system=true,让宿主主回复与 ST-BME 自己的聊天读取一起跳过这些楼层。
|
||
|
||
const hideState = {
|
||
managedChatRef: null,
|
||
hiddenIndices: new Set(),
|
||
lastProcessedLength: 0,
|
||
scheduledTimer: null,
|
||
};
|
||
|
||
function getTimerApi(runtime = {}) {
|
||
return {
|
||
setTimeout:
|
||
typeof runtime.setTimeout === "function"
|
||
? runtime.setTimeout.bind(runtime)
|
||
: globalThis.setTimeout.bind(globalThis),
|
||
clearTimeout:
|
||
typeof runtime.clearTimeout === "function"
|
||
? runtime.clearTimeout.bind(runtime)
|
||
: globalThis.clearTimeout.bind(globalThis),
|
||
};
|
||
}
|
||
|
||
function getJquery(runtime = {}) {
|
||
if (typeof runtime.$ === "function") return runtime.$;
|
||
if (typeof globalThis.$ === "function") return globalThis.$;
|
||
return null;
|
||
}
|
||
|
||
function getCurrentChat(runtime = {}) {
|
||
try {
|
||
const context =
|
||
typeof runtime.getContext === "function" ? runtime.getContext() : null;
|
||
return Array.isArray(context?.chat) ? context.chat : null;
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
function normalizeHideSettings(settings = {}) {
|
||
return {
|
||
enabled: Boolean(settings.enabled),
|
||
hideLastN: Math.max(
|
||
0,
|
||
Math.trunc(
|
||
Number(
|
||
settings.hideLastN ??
|
||
settings.hide_last_n ??
|
||
settings.keepLastN ??
|
||
settings.keep_last_n ??
|
||
0,
|
||
) || 0,
|
||
),
|
||
),
|
||
};
|
||
}
|
||
|
||
function syncSystemAttribute(chat, indices = [], value = "true", runtime = {}) {
|
||
if (!Array.isArray(indices) || indices.length === 0) return;
|
||
if (getCurrentChat(runtime) !== chat) return;
|
||
|
||
const jq = getJquery(runtime);
|
||
if (!jq) return;
|
||
|
||
const selector = indices.map((index) => `.mes[mesid="${index}"]`).join(",");
|
||
if (!selector) return;
|
||
jq(selector).attr("is_system", value);
|
||
}
|
||
|
||
function unhideTrackedChat(chat, runtime = {}) {
|
||
if (!Array.isArray(chat) || hideState.hiddenIndices.size === 0) {
|
||
return { shownCount: 0 };
|
||
}
|
||
|
||
const toShow = [];
|
||
for (const index of hideState.hiddenIndices) {
|
||
const message = chat[index];
|
||
if (!message || message.is_system !== true) continue;
|
||
message.is_system = false;
|
||
toShow.push(index);
|
||
}
|
||
|
||
syncSystemAttribute(chat, toShow, "false", runtime);
|
||
return { shownCount: toShow.length };
|
||
}
|
||
|
||
function swapManagedChat(nextChat, runtime = {}) {
|
||
const previousChat = hideState.managedChatRef;
|
||
if (previousChat && previousChat !== nextChat) {
|
||
unhideTrackedChat(previousChat, runtime);
|
||
hideState.hiddenIndices.clear();
|
||
hideState.lastProcessedLength = 0;
|
||
}
|
||
hideState.managedChatRef = nextChat;
|
||
}
|
||
|
||
export function runFullHideCheck(settings = {}, runtime = {}) {
|
||
const normalized = normalizeHideSettings(settings);
|
||
const chat = getCurrentChat(runtime);
|
||
if (!chat || chat.length === 0) {
|
||
resetHideState(runtime);
|
||
return {
|
||
active: false,
|
||
hiddenCount: 0,
|
||
shownCount: 0,
|
||
managedCount: 0,
|
||
chatLength: 0,
|
||
};
|
||
}
|
||
|
||
swapManagedChat(chat, runtime);
|
||
|
||
if (!normalized.enabled || normalized.hideLastN <= 0) {
|
||
const { shownCount } = unhideTrackedChat(chat, runtime);
|
||
hideState.hiddenIndices.clear();
|
||
hideState.lastProcessedLength = chat.length;
|
||
return {
|
||
active: false,
|
||
hiddenCount: 0,
|
||
shownCount,
|
||
managedCount: 0,
|
||
chatLength: chat.length,
|
||
};
|
||
}
|
||
|
||
const visibleStart =
|
||
normalized.hideLastN >= chat.length
|
||
? 0
|
||
: Math.max(0, chat.length - normalized.hideLastN);
|
||
const desiredHiddenIndices = new Set();
|
||
const managedHiddenIndices = new Set();
|
||
const toHide = [];
|
||
const toShow = [];
|
||
|
||
for (let index = 0; index < chat.length; index++) {
|
||
const message = chat[index];
|
||
if (!message) continue;
|
||
|
||
const shouldHide = index < visibleStart;
|
||
const isHidden = message.is_system === true;
|
||
const wasHiddenByBme = hideState.hiddenIndices.has(index);
|
||
|
||
if (shouldHide) {
|
||
desiredHiddenIndices.add(index);
|
||
if (wasHiddenByBme || !isHidden) {
|
||
managedHiddenIndices.add(index);
|
||
}
|
||
if (!isHidden) {
|
||
message.is_system = true;
|
||
toHide.push(index);
|
||
}
|
||
continue;
|
||
}
|
||
|
||
if (isHidden && wasHiddenByBme) {
|
||
message.is_system = false;
|
||
toShow.push(index);
|
||
}
|
||
}
|
||
|
||
syncSystemAttribute(chat, [...desiredHiddenIndices], "true", runtime);
|
||
syncSystemAttribute(chat, toShow, "false", runtime);
|
||
|
||
hideState.hiddenIndices = managedHiddenIndices;
|
||
hideState.lastProcessedLength = chat.length;
|
||
|
||
return {
|
||
active: true,
|
||
hiddenCount: toHide.length,
|
||
shownCount: toShow.length,
|
||
managedCount: managedHiddenIndices.size,
|
||
chatLength: chat.length,
|
||
};
|
||
}
|
||
|
||
export function runIncrementalHideCheck(settings = {}, runtime = {}) {
|
||
const normalized = normalizeHideSettings(settings);
|
||
const chat = getCurrentChat(runtime);
|
||
if (!chat || chat.length === 0) {
|
||
resetHideState(runtime);
|
||
return {
|
||
active: false,
|
||
hiddenCount: 0,
|
||
shownCount: 0,
|
||
managedCount: 0,
|
||
chatLength: 0,
|
||
incremental: false,
|
||
};
|
||
}
|
||
|
||
if (
|
||
hideState.managedChatRef !== chat ||
|
||
!normalized.enabled ||
|
||
normalized.hideLastN <= 0
|
||
) {
|
||
return {
|
||
...runFullHideCheck(normalized, runtime),
|
||
incremental: false,
|
||
};
|
||
}
|
||
|
||
const chatLength = chat.length;
|
||
const previousLength = hideState.lastProcessedLength;
|
||
if (chatLength <= previousLength) {
|
||
return {
|
||
...runFullHideCheck(normalized, runtime),
|
||
incremental: false,
|
||
};
|
||
}
|
||
|
||
const previousVisibleStart =
|
||
previousLength > 0 ? Math.max(0, previousLength - normalized.hideLastN) : 0;
|
||
const nextVisibleStart = Math.max(0, chatLength - normalized.hideLastN);
|
||
const toHide = [];
|
||
|
||
if (nextVisibleStart > previousVisibleStart) {
|
||
for (let index = previousVisibleStart; index < nextVisibleStart; index++) {
|
||
const message = chat[index];
|
||
if (!message || message.is_system === true) continue;
|
||
message.is_system = true;
|
||
hideState.hiddenIndices.add(index);
|
||
toHide.push(index);
|
||
}
|
||
}
|
||
|
||
syncSystemAttribute(chat, toHide, "true", runtime);
|
||
hideState.lastProcessedLength = chatLength;
|
||
|
||
return {
|
||
active: true,
|
||
hiddenCount: toHide.length,
|
||
shownCount: 0,
|
||
managedCount: hideState.hiddenIndices.size,
|
||
chatLength,
|
||
incremental: true,
|
||
};
|
||
}
|
||
|
||
export function applyHideSettings(settings = {}, runtime = {}) {
|
||
return runFullHideCheck(settings, runtime);
|
||
}
|
||
|
||
export function scheduleHideSettingsApply(
|
||
settings = {},
|
||
runtime = {},
|
||
delayMs = 120,
|
||
) {
|
||
const timers = getTimerApi(runtime);
|
||
if (hideState.scheduledTimer) {
|
||
timers.clearTimeout(hideState.scheduledTimer);
|
||
hideState.scheduledTimer = null;
|
||
}
|
||
|
||
const snapshot = normalizeHideSettings(settings);
|
||
hideState.scheduledTimer = timers.setTimeout(() => {
|
||
hideState.scheduledTimer = null;
|
||
applyHideSettings(snapshot, runtime);
|
||
}, Math.max(0, Math.trunc(Number(delayMs) || 0)));
|
||
}
|
||
|
||
export function unhideAll(runtime = {}) {
|
||
const timers = getTimerApi(runtime);
|
||
if (hideState.scheduledTimer) {
|
||
timers.clearTimeout(hideState.scheduledTimer);
|
||
hideState.scheduledTimer = null;
|
||
}
|
||
|
||
const managedChat = hideState.managedChatRef;
|
||
const { shownCount } = unhideTrackedChat(managedChat, runtime);
|
||
hideState.hiddenIndices.clear();
|
||
hideState.lastProcessedLength = Array.isArray(managedChat)
|
||
? managedChat.length
|
||
: 0;
|
||
|
||
return {
|
||
active: false,
|
||
shownCount,
|
||
managedCount: 0,
|
||
};
|
||
}
|
||
|
||
export function resetHideState(runtime = {}) {
|
||
const timers = getTimerApi(runtime);
|
||
if (hideState.scheduledTimer) {
|
||
timers.clearTimeout(hideState.scheduledTimer);
|
||
hideState.scheduledTimer = null;
|
||
}
|
||
|
||
const managedChat = hideState.managedChatRef;
|
||
unhideTrackedChat(managedChat, runtime);
|
||
hideState.managedChatRef = null;
|
||
hideState.hiddenIndices.clear();
|
||
hideState.lastProcessedLength = 0;
|
||
}
|
||
|
||
export function getHideStateSnapshot() {
|
||
return {
|
||
hasManagedChat: Boolean(hideState.managedChatRef),
|
||
managedHiddenCount: hideState.hiddenIndices.size,
|
||
lastProcessedLength: hideState.lastProcessedLength,
|
||
scheduled: Boolean(hideState.scheduledTimer),
|
||
};
|
||
}
|