From f3e751862235ee0868b01a3ad4c9a47ba2e54e10 Mon Sep 17 00:00:00 2001 From: Daryl Date: Sat, 21 Feb 2026 20:40:33 -0400 Subject: [PATCH] Enhance swipe data handling to correctly display swipe-specific tracker stats: add getSwipeData function and refactor commitTrackerData to utilize it --- src/core/persistence.js | 35 ++++++++++++++++++- src/systems/integration/sillytavern.js | 48 ++++++++++++-------------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/core/persistence.js b/src/core/persistence.js index e6343c8..1ad8e65 100644 --- a/src/core/persistence.js +++ b/src/core/persistence.js @@ -247,11 +247,23 @@ export function updateMessageSwipeData() { } const swipeId = message.swipe_id || 0; - message.extra.rpg_companion_swipes[swipeId] = { + const swipeEntry = { userStats: lastGeneratedData.userStats, infoBox: lastGeneratedData.infoBox, characterThoughts: lastGeneratedData.characterThoughts }; + message.extra.rpg_companion_swipes[swipeId] = swipeEntry; + + // Mirror to swipe_info so data survives page reloads regardless of active swipe + if (message.swipe_info && message.swipe_info[swipeId]) { + if (!message.swipe_info[swipeId].extra) { + message.swipe_info[swipeId].extra = {}; + } + if (!message.swipe_info[swipeId].extra.rpg_companion_swipes) { + message.swipe_info[swipeId].extra.rpg_companion_swipes = {}; + } + message.swipe_info[swipeId].extra.rpg_companion_swipes[swipeId] = swipeEntry; + } // console.log('[RPG Companion] Updated message swipe data after user edit'); break; @@ -259,6 +271,27 @@ export function updateMessageSwipeData() { } } +/** + * Reads RPG tracker data for a specific swipe from a message. + * Checks message.extra first (in-memory, current session), then message.swipe_info + * (serialized by SillyTavern on save, available after page reload). + * + * @param {Object} message - The chat message object + * @param {number} swipeId - The swipe index to read + * @returns {{userStats, infoBox, characterThoughts}|null} The swipe data or null + */ +export function getSwipeData(message, swipeId) { + // Primary: in-memory extra (current session or after a recent write) + const fromExtra = message.extra?.rpg_companion_swipes?.[swipeId]; + if (fromExtra) return fromExtra; + + // Fallback: swipe_info (populated by ST when loading from disk) + const fromSwipeInfo = message.swipe_info?.[swipeId]?.extra?.rpg_companion_swipes?.[swipeId]; + if (fromSwipeInfo) return fromSwipeInfo; + + return null; +} + /** * Loads RPG data from the current chat's metadata. * Automatically migrates v1 inventory to v2 format if needed. diff --git a/src/systems/integration/sillytavern.js b/src/systems/integration/sillytavern.js index 3af43a8..0e121a4 100644 --- a/src/systems/integration/sillytavern.js +++ b/src/systems/integration/sillytavern.js @@ -22,7 +22,7 @@ import { updateCommittedTrackerData, $musicPlayerContainer } from '../../core/state.js'; -import { saveChatData, loadChatData, autoSwitchPresetForEntity } from '../../core/persistence.js'; +import { saveChatData, loadChatData, autoSwitchPresetForEntity, getSwipeData } from '../../core/persistence.js'; import { i18n } from '../../core/i18n.js'; // Generation & Parsing @@ -67,20 +67,19 @@ export function commitTrackerData() { const message = chat[i]; if (!message.is_user) { // Found last assistant message - commit its tracker data - if (message.extra && message.extra.rpg_companion_swipes) { - const swipeId = message.swipe_id || 0; - const swipeData = message.extra.rpg_companion_swipes[swipeId]; + const swipeId = message.swipe_id || 0; + const swipeData = getSwipeData(message, swipeId); - if (swipeData) { - // console.log('[RPG Companion] Committing tracker data from assistant message at index', i, 'swipe', swipeId); - committedTrackerData.userStats = swipeData.userStats || null; - committedTrackerData.infoBox = swipeData.infoBox || null; - committedTrackerData.characterThoughts = swipeData.characterThoughts || null; - } else { - // console.log('[RPG Companion] No swipe data found for swipe', swipeId); - } + if (swipeData) { + // console.log('[RPG Companion] Committing tracker data from assistant message at index', i, 'swipe', swipeId); + committedTrackerData.userStats = swipeData.userStats || null; + committedTrackerData.infoBox = swipeData.infoBox || null; + committedTrackerData.characterThoughts = swipeData.characterThoughts || null; } else { - // console.log('[RPG Companion] No RPG data found in last assistant message'); + // No saved swipe data — treat as empty (e.g. first message, no prior generation) + committedTrackerData.userStats = null; + committedTrackerData.infoBox = null; + committedTrackerData.characterThoughts = null; } break; } @@ -386,12 +385,12 @@ export function onMessageSwiped(messageIndex) { // console.log('[RPG Companion] Loading data for swipe', currentSwipeId); - // IMPORTANT: onMessageSwiped is for DISPLAY only! - // lastGeneratedData is for DISPLAY, committedTrackerData is for GENERATION - // It's safe to load swipe data into lastGeneratedData - it won't be committed due to !lastActionWasSwipe check - if (message.extra && message.extra.rpg_companion_swipes && message.extra.rpg_companion_swipes[currentSwipeId]) { - const swipeData = message.extra.rpg_companion_swipes[currentSwipeId]; - + // Load saved swipe data into both display (lastGeneratedData) and extensionSettings. + // Safe to call parseUserStats() unconditionally because updateMessageSwipeData() is called + // on every manual edit, so the swipe store always reflects the latest user changes before + // any navigation can overwrite them. + const swipeData = getSwipeData(message, currentSwipeId); + if (swipeData) { // Load swipe data into lastGeneratedData for display (both modes) lastGeneratedData.userStats = swipeData.userStats || null; lastGeneratedData.infoBox = swipeData.infoBox || null; @@ -403,13 +402,12 @@ export function onMessageSwiped(messageIndex) { lastGeneratedData.characterThoughts = swipeData.characterThoughts || null; } - // DON'T parse user stats when loading swipe data - // This would overwrite manually edited fields (like Conditions) with old swipe data - // The lastGeneratedData is loaded for display purposes only - // parseUserStats() updates extensionSettings.userStats which should only be modified - // by new generations or manual edits, not by swipe navigation + // Sync extensionSettings.userStats so stat bars reflect this swipe + if (swipeData.userStats) { + parseUserStats(swipeData.userStats); + } - // console.log('[RPG Companion] 🔄 Loaded swipe data into lastGeneratedData for display:', currentSwipeId); + // console.log('[RPG Companion] 🔄 Loaded swipe data for swipe:', currentSwipeId); } else { // console.log('[RPG Companion] â„šī¸ No stored data for swipe:', currentSwipeId); }