Change type of timed events metadata

This commit is contained in:
Cohee
2024-06-22 03:54:54 +03:00
parent 37930caade
commit d02fbbb42f

View File

@ -89,6 +89,7 @@ const MAX_SCAN_DEPTH = 1000;
* @property {boolean} [matchWholeWords] If the scan should match whole words * @property {boolean} [matchWholeWords] If the scan should match whole words
* @property {boolean} [useGroupScoring] If the scan should use group scoring * @property {boolean} [useGroupScoring] If the scan should use group scoring
* @property {number} [uid] The UID of the entry that triggered the scan * @property {number} [uid] The UID of the entry that triggered the scan
* @property {string} [world] The world info book of origin of the entry
* @property {string[]} [key] The primary keys to scan for * @property {string[]} [key] The primary keys to scan for
* @property {string[]} [keysecondary] The secondary keys to scan for * @property {string[]} [keysecondary] The secondary keys to scan for
* @property {number} [selectiveLogic] The logic to use for selective activation * @property {number} [selectiveLogic] The logic to use for selective activation
@ -333,7 +334,7 @@ class WorldInfoBuffer {
class WorldInfoTimedEvents { class WorldInfoTimedEvents {
/** /**
* @type {Map<object, number>} Cache for entry hashes * @type {Map<WIScanEntry, number>} Cache for entry hashes
*/ */
static #entryHashCache = new Map(); static #entryHashCache = new Map();
@ -373,24 +374,27 @@ class WorldInfoTimedEvents {
*/ */
#ensureChatMetadata() { #ensureChatMetadata() {
if (!chat_metadata.timedWorldInfo) { if (!chat_metadata.timedWorldInfo) {
chat_metadata.timedWorldInfo = { chat_metadata.timedWorldInfo = {};
sticky: {},
cooldown: {},
};
} }
if (!chat_metadata.timedWorldInfo.sticky || typeof chat_metadata.timedWorldInfo.sticky !== 'object') { ['sticky', 'cooldown'].forEach(type => {
chat_metadata.timedWorldInfo.sticky = {}; // Ensure the property exists and is an object
} if (!chat_metadata.timedWorldInfo[type] || typeof chat_metadata.timedWorldInfo[type] !== 'object') {
chat_metadata.timedWorldInfo[type] = {};
}
if (!chat_metadata.timedWorldInfo.cooldown || typeof chat_metadata.timedWorldInfo.cooldown !== 'object') { // Clean up invalid entries
chat_metadata.timedWorldInfo.cooldown = {}; Object.entries(chat_metadata.timedWorldInfo[type]).forEach(([key, value]) => {
} if (!value || typeof value !== 'object') {
delete chat_metadata.timedWorldInfo[type][key];
}
});
});
} }
/** /**
* Gets a hash for a WI entry. * Gets a hash for a WI entry.
* @param {object} entry WI entry * @param {WIScanEntry} entry WI entry
* @returns {number} String hash * @returns {number} String hash
*/ */
#getEntryHash(entry) { #getEntryHash(entry) {
@ -404,48 +408,26 @@ class WorldInfoTimedEvents {
} }
/** /**
* Processes entries for a given type of timed event. * Gets a unique-ish key for a WI entry.
* @param {string} type Identifier for the type of timed event * @param {WIScanEntry} entry WI entry
* @param {WIScanEntry[]} buffer Buffer to store the entries * @returns {string} String key for the entry
* @param {(entry: WIScanEntry) => void} onEnded Callback for when a timed event ends
*/ */
#processEntries(type, buffer, onEnded) { #getEntryKey(entry) {
for (const [hash, value] of Object.entries(chat_metadata.timedWorldInfo[type])) { return `${entry.world}.${entry.uid}`;
console.log(`Processing ${type} entry ${hash} with value ${value}`); }
const entry = this.#entries.find(x => String(this.#getEntryHash(x)) === String(hash));
if (this.#chat.length <= Number(value)) { /**
console.log(`Removing ${type} entry from timedWorldInfo: chat not advanced`, entry); * Gets a timed event for a WI entry.
delete chat_metadata.timedWorldInfo[type][hash]; * @param {WIScanEntry} entry WI entry
continue; * @param {'sticky'|'cooldown'} type Type of timed event
} * @returns {WITimedEvent} Timed event for the entry
*/
// Ignore missing entries (they could be from another character's lorebook) #getEntryTimedEvent(entry, type) {
if (!entry) { return {
continue; hash: this.#getEntryHash(entry),
} start: this.#chat.length,
end: this.#chat.length + Number(entry[type]),
// Ignore invalid entries (not configured for timed effects) };
if (!entry[type]) {
console.log(`Removing ${type} entry from timedWorldInfo: entry not ${type}`, entry);
delete chat_metadata.timedWorldInfo[type][hash];
continue;
}
const targetRelease = Number(value) + Number(entry[type]);
if (this.#chat.length > targetRelease) {
console.log(`Removing ${type} entry from timedWorldInfo: ${type} interval passed`, entry);
delete chat_metadata.timedWorldInfo[type][hash];
if (typeof onEnded === 'function') {
onEnded(entry);
}
continue;
}
buffer.push(entry);
console.log(`Timed effect "${type}" applied to entry`, entry);
}
} }
/** /**
@ -458,10 +440,10 @@ class WorldInfoTimedEvents {
return; return;
} }
const hash = this.#getEntryHash(entry); const key = this.#getEntryKey(entry);
const targetRelease = this.#chat.length + entry.cooldown; const event = this.#getEntryTimedEvent(entry, 'cooldown');
chat_metadata.timedWorldInfo.cooldown[hash] = this.#chat.length; chat_metadata.timedWorldInfo.cooldown[key] = event;
console.log(`Adding cooldown entry ${hash} on ended sticky: target release @ message ID ${targetRelease}`); console.log(`Adding cooldown entry ${key} on ended sticky: target release @ message ID ${event.end}`);
// Set the cooldown immediately for this evaluation // Set the cooldown immediately for this evaluation
this.#cooldownSuppressions.push(entry); this.#cooldownSuppressions.push(entry);
} }
@ -475,12 +457,82 @@ class WorldInfoTimedEvents {
console.debug('Cooldown ended for entry', entry.uid); console.debug('Cooldown ended for entry', entry.uid);
} }
/**
* Processes entries for a given type of timed event.
* @param {'sticky'|'cooldown'} type Identifier for the type of timed event
* @param {WIScanEntry[]} buffer Buffer to store the entries
* @param {(entry: WIScanEntry) => void} onEnded Callback for when a timed event ends
*/
#checkTimedEventOfType(type, buffer, onEnded) {
/** @type {[string, WITimedEvent][]} */
const events = Object.entries(chat_metadata.timedWorldInfo[type]);
for (const [key, value] of events) {
console.log(`Processing ${type} entry ${key}`, value);
const entry = this.#entries.find(x => String(this.#getEntryHash(x)) === String(value.hash));
if (this.#chat.length <= Number(value.start)) {
console.log(`Removing ${type} entry ${key} from timedWorldInfo: chat not advanced`, value);
delete chat_metadata.timedWorldInfo[type][key];
continue;
}
// Missing entries (they could be from another character's lorebook)
if (!entry) {
if (this.#chat.length > Number(value.end)) {
console.log(`Removing ${type} entry from timedWorldInfo: entry not found and interval passed`, entry);
delete chat_metadata.timedWorldInfo[type][key];
}
continue;
}
// Ignore invalid entries (not configured for timed effects)
if (!entry[type]) {
console.log(`Removing ${type} entry from timedWorldInfo: entry not ${type}`, entry);
delete chat_metadata.timedWorldInfo[type][key];
continue;
}
if (this.#chat.length > Number(value.end)) {
console.log(`Removing ${type} entry from timedWorldInfo: ${type} interval passed`, entry);
delete chat_metadata.timedWorldInfo[type][key];
if (typeof onEnded === 'function') {
onEnded(entry);
}
continue;
}
buffer.push(entry);
console.log(`Timed effect "${type}" applied to entry`, entry);
}
}
/** /**
* Checks for timed effects on chat messages. * Checks for timed effects on chat messages.
*/ */
checkTimedEvents() { checkTimedEvents() {
this.#processEntries('sticky', this.#stickyActivations, this.#onStickyEndedCallback.bind(this)); this.#checkTimedEventOfType('sticky', this.#stickyActivations, this.#onStickyEndedCallback.bind(this));
this.#processEntries('cooldown', this.#cooldownSuppressions, this.#onCooldownEndedCallback.bind(this)); this.#checkTimedEventOfType('cooldown', this.#cooldownSuppressions, this.#onCooldownEndedCallback.bind(this));
}
/**
* Sets a timed event for a WI entry.
* @param {'sticky'|'cooldown'} type Type of timed event
* @param {WIScanEntry} entry WI entry to check
*/
#setTimedEventOfType(type, entry) {
// Skip if entry does not have the type (sticky or cooldown)
if (!entry[type]) {
return;
}
const key = this.#getEntryKey(entry);
if (!chat_metadata.timedWorldInfo[type][key]) {
const event = this.#getEntryTimedEvent(entry, type);
chat_metadata.timedWorldInfo[type][key] = event;
console.log(`Adding ${type} entry ${key}: target release @ message ID ${event.end}`);
}
} }
/** /**
@ -489,23 +541,8 @@ class WorldInfoTimedEvents {
*/ */
setTimedEvents(activatedEntries) { setTimedEvents(activatedEntries) {
for (const entry of activatedEntries) { for (const entry of activatedEntries) {
if (!entry.sticky && !entry.cooldown) { this.#setTimedEventOfType('sticky', entry);
continue; this.#setTimedEventOfType('cooldown', entry);
}
const hash = this.#getEntryHash(entry);
if (entry.sticky && !chat_metadata.timedWorldInfo.sticky[hash]) {
const targetRelease = this.#chat.length + entry.sticky;
chat_metadata.timedWorldInfo.sticky[hash] = this.#chat.length;
console.log(`Adding sticky entry ${hash}: target release @ message ID ${targetRelease}`);
}
if (entry.cooldown && !chat_metadata.timedWorldInfo.cooldown[hash]) {
const targetRelease = this.#chat.length + entry.cooldown;
chat_metadata.timedWorldInfo.cooldown[hash] = this.#chat.length;
console.log(`Adding cooldown entry ${hash}: target release @ message ID ${targetRelease}`);
}
} }
} }
@ -515,7 +552,7 @@ class WorldInfoTimedEvents {
* @returns {boolean} True if the entry is sticky activated * @returns {boolean} True if the entry is sticky activated
*/ */
isStickyActivated(entry) { isStickyActivated(entry) {
return this.#stickyActivations.some(x => JSON.stringify(x) === JSON.stringify(entry)); return this.#stickyActivations.some(x => this.#getEntryHash(x) === this.#getEntryHash(entry));
} }
/** /**
@ -524,7 +561,7 @@ class WorldInfoTimedEvents {
* @returns {boolean} True if the entry is suppressed by cooldown * @returns {boolean} True if the entry is suppressed by cooldown
*/ */
isOnCooldown(entry) { isOnCooldown(entry) {
return this.#cooldownSuppressions.some(x => JSON.stringify(x) === JSON.stringify(entry)); return this.#cooldownSuppressions.some(x => this.#getEntryHash(x) === this.#getEntryHash(entry));
} }
/** /**