Download
(14 Kb)
Download
Updated: 02/11/24 02:18 PM
Pictures
File Info
Updated:02/11/24 02:18 PM
Created:03/21/21 11:05 AM
Monthly downloads:113
Total downloads:4,707
Favorites:21
MD5:
Story Saver
Version: 14
by: f1rex [More]
This AddOn saves history of dialogues, subtitles, books/notes and quest items. Saved data can be displayed with /storysaver command or special keybind in settings

AddOn allows you to:
  • Read saved dialogues with all options and previously selected options
  • Read saved subtitles
  • Read saved books/notes
  • Browse saved quest items
  • Show place of event on map
  • Delete event
  • Filter events by type
  • Fulltext search of events
  • Sort events
  • Configure auto-deletion after specific count of days

Languages (if you want to help with adding new languages and/or supporting them, please, write to me):
  • English (fallback)
  • Ukrainian
  • Russian

Dependencies:
  • LibAddonMenu-2.0
  • LibGPS
  • LibMapPing (optional, although LibGPS requires LibMapPing)

Cautions:
  • Remember to backup your data file periodically, especially do it before AddOn update
  • Reading book/note from Lore Library will add new event to history

GitHub:
For any contributions, please, use https://github.com/powerbq/eso-addon-storysaver

Purpose:
There are times when simply no time/desire/effort to read dialogues or notes (for example in group dungeons). In this case, you would like not to lose plot thread and be able to restore it later. Or when you just want to remember quest or phrase referenced by NPC. AddOn functionality will help you with this
Version 14

- Changed logic of dialogue options getting (GetChatter* functions don't work properly)
- Refactoring


Version 13

- Fixed book reading
- Added gamepad support
- Settings menu
- Delete selected instead of optimize storage
- Ukrainian localization
- Fixes
- Refactoring


Version 12

- Removed external tools
- Fixed book reading for new APIVersion
- Moved all data to account wide saved variables
- Optimize storage instead of deduplication
- Doesn't save dialogues if there is only a guild store option
- Doesn't create dialogue event for body if it already exists in another event
- Adds new options to existing dialogue event
- Stores the date of option adding
- Stores the option type for future using
- Huge of improvements
- Moved old data migration methods to another class
- Other refactoring


Version 11

- Renamed executable and source file (from main.* to cleanup.*)
- Added files for building .exe from .py (Python 3+ with PIP required)


Version 10

- API version update
- Added executable for unused cache cleanup (bin folder). Look .py file for source code


Version 9

- API version update


Version 8

- Minor fixes


Version 7

- Added automatic check for duplicates on new event


Version 6

- Changed character variables schema
- Added quest items event type
- Added manual deduplication
- Improved map functionality (thanks to Alianym)
- Minor improvements and refactoring


Version 5

- Fixed syntax error


Version 4

- Changed max size of book part to 500 characters
- Disabled account variables cleanup


Version 3

- Fixed bug when some books were saving incorrectly (thanks to tiker)


Version 2

- Fixed error during init (thanks to tiker)
Post A Reply Comment Options
Unread 02/04/24, 01:35 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 17
Uploads: 2
I'm back

Hey!

Sorry for big delay, these two years and now I have conditions that are out of my control, but for now I have a little time and inspiration for making my AddOn better. Firstly, I decided to concentrate my efforts on solving conceptual problems and get rid of external script for cache cleaning. Also, I changed the dialogue events concept. Look at changelog for more details. Update is already here. Please, backup before update. Really. Do it even if everything is okay. I've got my data file broken because of filesystem or SSD issue. I didn't have a backup. So don't repeat after me. I try to test everything, but I don't give any guarantees that I will not break something, and loosing AddOn data is critical. All data must be migrated to new version without any problems, but s*** happens.

Next step will be to add AddOn settings menu with possibilities to configure how records will be deleted and some other options.

Also, I want to add more locales (thanks snorunt361 for feedback) and try to add gamepad compatibility (thanks Tatila for feedback). Write to me here if you want to help with translation. Or just create a pull request on GitHub (link is in the AddOn description).

Thanks!
Report comment to moderator  
Reply With Quote
Unread 05/31/22, 07:42 AM  
snorunt361
AddOn Author - Click to view AddOns

Forum posts: 3
File comments: 13
Uploads: 1
Hello.
I made JP.lua file.
What should I do with this file?

I like to save quest items.

This is my selfishness.
I would be happy if I could switch the automatic save on and off for each filter.
Conversations are usually turned off and conversations do not increase.

I'm not good at English.
Sorry.
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
こんにちは。
私は日本語のファイルを作りました。
私はこのファイルをどうすれば良いでしょうか?
私はこのアドオンのクエストアイテムを記録できる所がとても好きです。
そして、これは私の我儘になります。
フィルターごとに自動保存のオン・オフを設定できたら嬉しいです。
普段は会話をオフにすれば無尽蔵に増えることがなくなります。
私は英語が下手です。
すみません。
Report comment to moderator  
Reply With Quote
Unread 03/03/22, 01:09 PM  
Tatila

Forum posts: 4
File comments: 1
Uploads: 0
gamepad compatibility

I really like this mod, but for the fact that dialogue logging doesn't work with the gamepad UI active, and I have to play with a gamepad.

It behaves very strangely, occasionally registering the interaction with npcs, such as if it's a different npc from the last one you talked to, with the actual registered log often being from a previous conversation, and not registering follow-ups from the same dialogue, like it does on kb+m.

Would it be possible to add gamepad compatibility?

It also seems to miss the opening dialogue of a conversation, even with kb+m, which would also be a nice addition.
Report comment to moderator  
Reply With Quote
Unread 02/23/22, 10:32 PM  
NeuroticPixels
Addon Addict
 
NeuroticPixels's Avatar
Premium Member

Forum posts: 211
File comments: 869
Uploads: 0
Used the cleanup.exe and got this error when I logged back into the game:
Code:
user:/SavedVariables/StorySaver.lua:30: } expected (to close { at line 27) near 'Warriors'
Report comment to moderator  
Reply With Quote
Unread 01/06/22, 08:46 AM  
Baertram
Super Moderator
 
Baertram's Avatar
ESOUI Super Moderator
AddOn Author - Click to view AddOns

Forum posts: 4965
File comments: 6033
Uploads: 78
Lua should be able to do the same then. You could also create 2 different tables on the SV so you only need to iterate one dedicated without accidently deleting be character saved data.
Unfortunately I'm not able to code in python (I assume this is the py file?) else I'd have checked the code and tried to provide you more info how to achieve the same in lua.

Your code seems to loop over the SV table entries and do something:
Code:
for account_1 in data[realm_1]:
            for category_1 in data[realm_1][account_1][character_1]:
                if category_1 == 'version':
                    continue

                for name_1 in data[realm_1][account_1][character_1][category_1]:
                    for hash_1 in data[realm_1][account_1][character_1][category_1][name_1]:
                        body = data[realm_1][account_1][character_1][category_1][name_1][hash_1]
                        found = False
                        for realm_2 in data:
                            if realm_2 == realm_1:
                                continue

                            for account_2 in data[realm_2]:
                                if account_2 != account_1:
                                    continue

                                for character_2 in data[realm_2][account_2]:
                                    if character_2 == character_1:
                                        continue

                                    for category_2 in data[realm_2][account_2][character_2]:
                                        if category_2 != category_1:
                                            continue

                                        for name_2 in data[realm_2][account_2][character_2][category_2]:
                                            if name_2 != name_1:
                                                continue

                                            for event_2 in data[realm_2][account_2][character_2][category_2][name_2]:
                                                hash_2 = data[realm_2][account_2][character_2][category_2][name_2][event_2]['hash']
                                                if hash_2 == hash_1:
                                                    found = True

                                                if 'selectedOptionHash' in data[realm_2][account_2][character_2][category_2][name_2][event_2]:
                                                    selected_option_hash = data[realm_2][account_2][character_2][category_2][name_2][event_2]['selectedOptionHash']
                                                    if selected_option_hash == hash_1:
                                                        found = True

                                                if 'optionHashes' in data[realm_2][account_2][character_2][category_2][name_2][event_2]:
                                                    for i, option_hash in data[realm_2][account_2][character_2][category_2][name_2][event_2]['optionHashes'].items():
                                                        if option_hash == hash_1:
                                                            found = True
And if anything is not found it deletes it with del data[realm_1][account_1][character_1][category_1][name_1][hash_1].
This would be the same in lua, with just setting it = nil -> data[realm_1][account_1][character_1][category_1][name_1][hash_1] = nil

edit: Looks like the code above would be something like this in lua:
Lua Code:
  1. for realm, realmData in pairs(SVTable) do
  2.    for account, accountData in pairs (realmData) do
  3.       for category, categoryData in pairs (accountData ) do
  4.         .... --items here
  5.       end
  6.    end
  7. end

As you got access to the SV and this is only a table you are able to use for key, value in pairs(stable) do and do your checks + cleanup this way. If you provide me an example lua file of the SVs and one example where the cache is stored in it and what needs to be checked and cleaned when I might be able to help you build the lua code.

This woulds trip the need to download python executables, dependencies via pip etc. AND especially to use external sofftware and executables in your addon. Just do it within the addon's code.
All you need to think about is that the SVs will be cached during gameplay in internal lua tables. So modifiying the SV file on your disk wil ldo nothing until you logout first before! But modfying them ingame in the cachec tables that point to the svfile on your disk + doing a reloadui will update the internat tables AND the SV file properly and clear the cache.
So all you need is the logi to loop over the SV files, which is pretty easy if you know the SV table name (and you know it, it's given in oyur txt manifest file ## SavedVariables: tag) and where to look at, what to compare with and then set it = nil
At the end call ReloadUI("ingame") and you are done with the cleanup.


Originally Posted by f1rex
Originally Posted by Baertram
About the included exe file:
Aren't you able to delete the unused cache from your SavedVariables file from lua code ingame?
What exactly is the exe doing? I assume it deletes contents of the SV file? Just set this content = nil ingame and reload the Ui and it will be updated in the SV file.
Hey! Cache stores globally in SV, but events stores per character. AddOn doesn't know how many characters or accounts uses one record in cache. So EXE iterates cache records and finds usages and removes it when nobody uses it. For now i don't know another way to cleanup. I stored PY file for analyze what exactly program does and script for build your own EXE, but can answer any question about it.
Last edited by Baertram : 01/06/22 at 12:39 PM.
Report comment to moderator  
Reply With Quote
Unread 01/06/22, 03:17 AM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 17
Uploads: 2
Originally Posted by Baertram
About the included exe file:
Aren't you able to delete the unused cache from your SavedVariables file from lua code ingame?
What exactly is the exe doing? I assume it deletes contents of the SV file? Just set this content = nil ingame and reload the Ui and it will be updated in the SV file.
Hey! Cache stores globally in SV, but events stores per character. AddOn doesn't know how many characters or accounts uses one record in cache. So EXE iterates cache records and finds usages and removes it when nobody uses it. For now i don't know another way to cleanup. I stored PY file for analyze what exactly program does and script for build your own EXE, but can answer any question about it.
Report comment to moderator  
Reply With Quote
Unread 01/05/22, 01:18 PM  
Baertram
Super Moderator
 
Baertram's Avatar
ESOUI Super Moderator
AddOn Author - Click to view AddOns

Forum posts: 4965
File comments: 6033
Uploads: 78
About the included exe file:
Aren't you able to delete the unused cache from your SavedVariables file from lua code ingame?
What exactly is the exe doing? I assume it deletes contents of the SV file? Just set this content = nil ingame and reload the Ui and it will be updated in the SV file.
Report comment to moderator  
Reply With Quote
Unread 01/05/22, 04:50 AM  
Baertram
Super Moderator
 
Baertram's Avatar
ESOUI Super Moderator
AddOn Author - Click to view AddOns

Forum posts: 4965
File comments: 6033
Uploads: 78
You can use LibCustomMenu and add a right click context menu to the entries at the list.
Filtered rows could be deleted then. Or you add a keybind to delete "all currently shown" (filtered) rows?

Depending on the list type: If you add checkboxes to each entry of the list (as a new first column) one could mark multiple ones and then right click -> Delete checked
If the list type is a zo_scrolllist (https://github.com/esoui/esoui/tree/...s/zo_templates) there should be a function to enable selection and/or highlighting. Selection means you click an entry to select it and it stays selected, and you click it again to deselect it.
Highlighting means it will show a highlight as you move the mouse over it.

function ZO_ScrollList_EnableSelection(self, selectionTemplate, selectionCallback)
The selectionTemplate is the XML virtual template used to define how the selected entry looks like, e.g. "ZO_ThinListHighlight"
And the selectionCallback is a function you specify that is called as the selection was done -> e.g. show the text of the selected entry somewhere.
An example can be found here -> The character selection ingame:

https://github.com/esoui/esoui/blob/...board.lua#L394
It uses the selection template "ZO_TallListHighlight" and the callbackFunction called as you select an entry is OnCharacterSelectionChanged.
The parameters passed in to the functions are:
previouslySelectedData, selectedData

where the data tables are the data of the rows of the scrolllist, so it got an index and whatever data you have passed to it during the scrollLists setupRow callback function "setupCallback" in function
ZO_ScrollList_AddDataType(self, typeId, templateName, height, setupCallback, hideCallback, dataTypeSelectSound, resetControlCallback)



Originally Posted by f1rex
Originally Posted by LoneStar2911
Until another way is implemented, what's the best way to delete entries right now?
Hey, sorry for big delay. For now best way is to filter rows you want to delete and X-E X-E X-E from the top :-)

If you have idea how you see batch-deletion functionality, please share it. I mean interface of course

Thank you
Last edited by Baertram : 01/05/22 at 04:54 AM.
Report comment to moderator  
Reply With Quote
Unread 06/02/21, 01:36 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 17
Uploads: 2
Originally Posted by LoneStar2911
Until another way is implemented, what's the best way to delete entries right now?
Hey, sorry for big delay. For now best way is to filter rows you want to delete and X-E X-E X-E from the top :-)

If you have idea how you see batch-deletion functionality, please share it. I mean interface of course

Thank you
Report comment to moderator  
Reply With Quote
Unread 05/11/21, 04:32 PM  
NeuroticPixels
Addon Addict
 
NeuroticPixels's Avatar
Premium Member

Forum posts: 211
File comments: 869
Uploads: 0
Until another way is implemented, what's the best way to delete entries right now?
Report comment to moderator  
Reply With Quote
Unread 04/17/21, 01:30 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 17
Uploads: 2
Originally Posted by tiker
Another thing I noticed but have checked yet...

The latest version is supposed to detect and not add duplicate events. That means that the manual option to remove duplicate events should do nothing (assuming that the latest version is the only version ever used). However, even if the latest version is the only version used, the manual button to remove duplicate events still removes some entries. That means that the automatic and manual duplicate event checking functions are behaving differently. I haven't had time to figure this out yet.
Manual deduplication is for records added before latest version. Duplicate check is simple, but not for dialogues. For dialogues it checks everything - selected option - options and order and body. If anything is not match - event is unique.
Report comment to moderator  
Reply With Quote
Unread 04/16/21, 10:07 AM  
tiker

Forum posts: 0
File comments: 32
Uploads: 0
Another thing I noticed but have checked yet...

The latest version is supposed to detect and not add duplicate events. That means that the manual option to remove duplicate events should do nothing (assuming that the latest version is the only version ever used). However, even if the latest version is the only version used, the manual button to remove duplicate events still removes some entries. That means that the automatic and manual duplicate event checking functions are behaving differently. I haven't had time to figure this out yet.
Report comment to moderator  
Reply With Quote
Unread 04/16/21, 09:45 AM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 17
Uploads: 2
Originally Posted by tiker
After some testing, the first part is fixed (below) but there are still a couple of other items to figure out.

First problem (part 1): Last options (Goodbye., Nevermind, etc.) missing:
Caused by what looks to be an assumption that LUA tables are sorted when stored which is incorrect. In my case, take the following example:
Code:
                        ["1618400326-13"] = 
                        {
                            ["optionHashes"] = 
                            {
                                [2] = "1202672317-8",
                                [1] = "2237067526-30",
                            },
                            ["zoneIndex"] = 17,
                            ["y"] = 0.4008920082,
                            ["hash"] = "746736584-19",
                            ["x"] = 0.1428016038,
                        },
The second option "1202672317-8" (which is "Goodbye.") is stored first in the table. When it is displayed by the addon (interface.lua around line 310) it is assumed that the options are in order. To fix, change the following:
Code:
        for i, optionHash in pairs(optionHashes) do
            body = StorySaver:GetAccountCache(eventType, name)[optionHash]
            if i == 1 then
                optionsBody = body
            else
                optionsBody = optionsBody .. '\r\n' .. body
            end
        end
to this:
Code:
		local optionHash = nil
        for i =1, #optionHashes do
			optionHash = optionHashes[i]
            body = StorySaver:GetAccountCache(eventType, name)[optionHash]
            if i == 1 then
                optionsBody = body
            else
                optionsBody = optionsBody .. '\r\n' .. body
            end
        end
First problem (part 2):
Is unknown and may never be figured out. Some of the event tables that should have contained the strings "Goodbye.", etc. dropped the strings from the event option hash tables. Not sure if that was from the migration, from using the option to delete duplicated events, etc. But somewhere else, possibly with past versions, similar code existed but removed the strings. I deleted my saved variables file for this addon to reset it and started over. I have not been able to re-create this part of the issue yet.
Hey, before latest version options like "Goodbye" didn't save. I added it only in last version. Now i have more free time so i will look at your solution. Thank you
Report comment to moderator  
Reply With Quote
Unread 04/16/21, 06:32 AM  
tiker

Forum posts: 0
File comments: 32
Uploads: 0
After some testing, the first part is fixed (below) but there are still a couple of other items to figure out.

First problem (part 1): Last options (Goodbye., Nevermind, etc.) missing:
Caused by what looks to be an assumption that LUA tables are sorted when stored which is incorrect. In my case, take the following example:
Code:
                        ["1618400326-13"] = 
                        {
                            ["optionHashes"] = 
                            {
                                [2] = "1202672317-8",
                                [1] = "2237067526-30",
                            },
                            ["zoneIndex"] = 17,
                            ["y"] = 0.4008920082,
                            ["hash"] = "746736584-19",
                            ["x"] = 0.1428016038,
                        },
The second option "1202672317-8" (which is "Goodbye.") is stored first in the table. When it is displayed by the addon (interface.lua around line 310) it is assumed that the options are in order. To fix, change the following:
Code:
        for i, optionHash in pairs(optionHashes) do
            body = StorySaver:GetAccountCache(eventType, name)[optionHash]
            if i == 1 then
                optionsBody = body
            else
                optionsBody = optionsBody .. '\r\n' .. body
            end
        end
to this:
Code:
		local optionHash = nil
        for i =1, #optionHashes do
			optionHash = optionHashes[i]
            body = StorySaver:GetAccountCache(eventType, name)[optionHash]
            if i == 1 then
                optionsBody = body
            else
                optionsBody = optionsBody .. '\r\n' .. body
            end
        end
First problem (part 2):
Is unknown and may never be figured out. Some of the event tables that should have contained the strings "Goodbye.", etc. dropped the strings from the event option hash tables. Not sure if that was from the migration, from using the option to delete duplicated events, etc. But somewhere else, possibly with past versions, similar code existed but removed the strings. I deleted my saved variables file for this addon to reset it and started over. I have not been able to re-create this part of the issue yet.
Report comment to moderator  
Reply With Quote
Unread 04/09/21, 05:58 PM  
tiker

Forum posts: 0
File comments: 32
Uploads: 0
Found the cause of the bug. I have a partial fix so far but more testing is required.
Report comment to moderator  
Reply With Quote
Post A Reply



Category Jump: