Quantcast
Download
(9 Kb)
Download
Updated: 04/07/21 04:17 AM
Pictures
File Info
Compatibility:
Flames of Ambition (6.3.5)
Updated:04/07/21 04:17 AM
Created:03/21/21 11:05 AM
Monthly downloads:408
Total downloads:409
Favorites:4
MD5:
6.3.5
Story Saver  Updated this week!
Version: 7
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 option (if was)
  • Read saved subtitles
  • Read saved books/notes
  • Browse saved quest items
  • Show place of event on map
  • Remove event
  • Remove duplicates
  • Filter events by type
  • Fulltext search of events
  • Sort events

Dependencies:
  • LibGPS
  • LibMapPing (optional, although LibGPS requires LibMapPing)

Cautions:
  • Reading book/note from Lore Library will add new event to history

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

Plans:
In future i will consider possibility of adding batch deletions and auto-deleting events after a certain number of days have passed
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 04/09/21, 05:58 PM  
tiker

Forum posts: 0
File comments: 17
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
Unread 04/07/21, 08:28 PM  
tiker

Forum posts: 0
File comments: 17
Uploads: 0
Found a bug.

Talking to NPCs, the last option is usually "Goodbye." or when handing in a quest, the last option is "Nevermind". Story Saver picks this up and looks fine when viewing the history. Duplicates are not created if you keep opening the same window. Once you log out and log back on, if you view the same events, the last option of all events is missing. When talking to the NPC or whatever, the events are re-added again including the last option. Log out and back on again, the last line is missing again.
Report comment to moderator  
Reply With Quote
Unread 04/07/21, 06:47 PM  
tiker

Forum posts: 0
File comments: 17
Uploads: 0
I've been testing it. Looks good so far.
Report comment to moderator  
Reply With Quote
Unread 04/04/21, 01:26 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 12
Uploads: 2
New version

Today or tomorrow i will upload new version of addon. I have already tested it, but i think that i need more people to test character variables schema migration. If anybody wants to help me - please answer.
Report comment to moderator  
Reply With Quote
Unread 03/26/21, 05:16 AM  
tiker

Forum posts: 0
File comments: 17
Uploads: 0
Originally Posted by f1rex
Yes, thats why i added "return" before cache deletion block and broke addon. Now i have removed cache deletion block completely. At least for time. I want to add "refCount" param to account cache to resolve this problem, but i dont know what to do with users who already are using this addon on more than one character.
The issue with a reference counter is that if a character is deleted, books that character has seen will never be deleted.

You may have to forget about deleting the cache like the way it is now. Or move the events to be shared across all characters.
Report comment to moderator  
Reply With Quote
Unread 03/25/21, 02:05 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 12
Uploads: 2
Re: Re: Re: Investigations!

Originally Posted by Alianym
Originally Posted by f1rex
Warning: Spoiler

Hey, thank you for your post. Anyway LibGPS is used for retrieve global coordinates of player. Maybe you know how to get it without LibGPS?

For now i am trying to do global refactoring of this addon. New feature is coming (deduplication). Variables structure will be changed and i write migration function, but this is dangerous, so i am trying to be careful and test all. Then i will try to do something with map.

About Librarium. It overrides SetupBook function. My AddOn does same. And Librarian too. So question is in order, who did it last. So last will receive all calls of SetupBook function. I am not advanced AddOn creator, just beginner, but i think this is normal behavior. Correct me if i am wrong. Thank you
Hi!
So I use this one for local coordinates:
Code:
GetMapPlayerPosition(unitTag)
Returns: normalizedX, normalizedZ, heading, isShownInCurrentMap
And this for world coordinates:
Code:
GetUnitWorldPosition(unitTag)
Returns: zoneId, worldX, worldY, worldZ
Regarding the Librarium and the SetupBook function, as far as I know you're right. Whoever did it last will receive the calls. I can double-check my code later, but I'm pretty sure I incorporate the SetupBook function into my new version. Which means if mine comes after yours, it'll inherit any changes you made to the function. Haven't looked at how yours does it, but I'll do some more compatibility testing later to make sure they work fine together.
Thank you for your examples.

About SetupBook override chain:
I think there is only one way to avoid conflicts with other addons. We need to check if SetupBook is already overrided by known list of addons (for example LORE_READER.SetupBook == StorySaver.OnBook) and retrieve real "core" SetupBook (YourAddon.coreSetupBook = StorySaver.coreSetupBook). It looks like workaround, but not pretty solution.
Report comment to moderator  
Reply With Quote
Unread 03/25/21, 01:44 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 12
Uploads: 2
Originally Posted by tiker
New bug:

Events are stored per character. The cache is stored globally. When a single character removes all events for a book, it is removed from the cache. If another character has an event for the book that was deleted, you get an error when trying to read the book (obviously since the cache for the book was deleted).

Code:
bad argument #1 to 'table.concat' (table/struct expected, got nil)
stack traceback:
[C]: in function 'table.concat'
user:/AddOns/StorySaver/Interface.lua:299: in function 'StorySaverInterface:Read'
|caaaaaa<Locals> self = [table:1]{currentSortOrder = T, currentSortKey = "name", automaticallyColorRows = T}, data = [table:2]{name = "The Truth in Sequence: Volume ...", sortIndex = 95, when = "3/23/2021", eventType = 3, zoneName = "The Brass Fortress", eventId = "1616521957-3-3"}, eventData = [table:3]{name = "The Truth in Sequence: Volume ...", medium = 9, zoneIndex = 590, showTitle = T, x = 0.2623027939, y = 1.0371052354, hash = "3872171983-2490"}, title = "The Truth in Sequence: Volume ...", medium = 9, showTitle = T, hash = "3872171983-2490" </Locals>|r
user:/AddOns/StorySaver/Interface.lua:60: in function 'callback'
EsoUI/Libraries/ZO_KeybindStrip/ZO_KeybindStrip.lua:679: in function 'ZO_KeybindStrip:TryHandlingKeybindDown'
|caaaaaa<Locals> self = [table:4]{insertionId = 5, batchUpdating = F, allowDefaultExit = T}, keybind = "UI_SHORTCUT_PRIMARY", buttonOrEtherealDescriptor = ud, keybindButtonDescriptor = [table:5]{keybind = "UI_SHORTCUT_PRIMARY", addedForSceneName = "storySaver", alignment = 3} </Locals>|r
(tail call): ?
(tail call): ?
Yes, thats why i added "return" before cache deletion block and broke addon. Now i have removed cache deletion block completely. At least for time. I want to add "refCount" param to account cache to resolve this problem, but i dont know what to do with users who already are using this addon on more than one character.
Report comment to moderator  
Reply With Quote
Unread 03/25/21, 01:38 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 12
Uploads: 2
Re: Errors

Originally Posted by LoneStar2911
Got this today upon login, after updating:

Code:
user:/AddOns/StorySaver/StorySaver.lua:71: unexpected symbol near 'for'
Code:
user:/AddOns/StorySaver/Interface.lua:357: attempt to index a nil value
stack traceback:
user:/AddOns/StorySaver/Interface.lua:357: in function 'handler'
user:/AddOns/StorySaver/Interface.lua:364: in function 'StorySaverInterface.SetupCheckableButton'
|caaaaaa<Locals> control = ud, texturePrefix = "EsoUI/Art/MainMenu/menubar_not...", handler = user:/AddOns/StorySaver/Interface.lua:344 </Locals>|r
StorySaverEventListFrameFilterAndSearchSubtitles_Initialized:3: in function '(main chunk)'
|caaaaaa<Locals> self = ud </Locals>|r
Code:
user:/AddOns/StorySaver/Interface.lua:357: attempt to index a nil value
stack traceback:
user:/AddOns/StorySaver/Interface.lua:357: in function 'handler'
user:/AddOns/StorySaver/Interface.lua:364: in function 'StorySaverInterface.SetupCheckableButton'
|caaaaaa<Locals> control = ud, texturePrefix = "EsoUI/Art/MainMenu/menubar_soc...", handler = user:/AddOns/StorySaver/Interface.lua:344 </Locals>|r
StorySaverEventListFrameFilterAndSearchDialogues_Initialized:3: in function '(main chunk)'
|caaaaaa<Locals> self = ud </Locals>|r
Code:
user:/AddOns/StorySaver/Interface.lua:357: attempt to index a nil value
stack traceback:
user:/AddOns/StorySaver/Interface.lua:357: in function 'handler'
user:/AddOns/StorySaver/Interface.lua:364: in function 'StorySaverInterface.SetupCheckableButton'
|caaaaaa<Locals> control = ud, texturePrefix = "EsoUI/Art/MainMenu/menubar_jou...", handler = user:/AddOns/StorySaver/Interface.lua:344 </Locals>|r
StorySaverEventListFrameFilterAndSearchBooks_Initialized:3: in function '(main chunk)'
|caaaaaa<Locals> self = ud </Locals>|r
Hey, fixed it. It was syntax error. Some problems with lua coding.
Report comment to moderator  
Reply With Quote
Unread 03/25/21, 06:15 AM  
tiker

Forum posts: 0
File comments: 17
Uploads: 0
New bug:

Events are stored per character. The cache is stored globally. When a single character removes all events for a book, it is removed from the cache. If another character has an event for the book that was deleted, you get an error when trying to read the book (obviously since the cache for the book was deleted).

Code:
bad argument #1 to 'table.concat' (table/struct expected, got nil)
stack traceback:
[C]: in function 'table.concat'
user:/AddOns/StorySaver/Interface.lua:299: in function 'StorySaverInterface:Read'
|caaaaaa<Locals> self = [table:1]{currentSortOrder = T, currentSortKey = "name", automaticallyColorRows = T}, data = [table:2]{name = "The Truth in Sequence: Volume ...", sortIndex = 95, when = "3/23/2021", eventType = 3, zoneName = "The Brass Fortress", eventId = "1616521957-3-3"}, eventData = [table:3]{name = "The Truth in Sequence: Volume ...", medium = 9, zoneIndex = 590, showTitle = T, x = 0.2623027939, y = 1.0371052354, hash = "3872171983-2490"}, title = "The Truth in Sequence: Volume ...", medium = 9, showTitle = T, hash = "3872171983-2490" </Locals>|r
user:/AddOns/StorySaver/Interface.lua:60: in function 'callback'
EsoUI/Libraries/ZO_KeybindStrip/ZO_KeybindStrip.lua:679: in function 'ZO_KeybindStrip:TryHandlingKeybindDown'
|caaaaaa<Locals> self = [table:4]{insertionId = 5, batchUpdating = F, allowDefaultExit = T}, keybind = "UI_SHORTCUT_PRIMARY", buttonOrEtherealDescriptor = ud, keybindButtonDescriptor = [table:5]{keybind = "UI_SHORTCUT_PRIMARY", addedForSceneName = "storySaver", alignment = 3} </Locals>|r
(tail call): ?
(tail call): ?
Last edited by tiker : 03/25/21 at 06:16 AM.
Report comment to moderator  
Reply With Quote
Unread 03/25/21, 06:11 AM  
tiker

Forum posts: 0
File comments: 17
Uploads: 0
Re: Errors

Originally Posted by LoneStar2911
Got this today upon login, after updating:

Code:
user:/AddOns/StorySaver/StorySaver.lua:71: unexpected symbol near 'for'
I'd say remove "return" from line 69.
Report comment to moderator  
Reply With Quote
Unread 03/24/21, 08:57 PM  
Alianym
AddOn Author - Click to view AddOns

Forum posts: 3
File comments: 51
Uploads: 6
Re: Re: Investigations!

Originally Posted by f1rex
Warning: Spoiler

Hey, thank you for your post. Anyway LibGPS is used for retrieve global coordinates of player. Maybe you know how to get it without LibGPS?

For now i am trying to do global refactoring of this addon. New feature is coming (deduplication). Variables structure will be changed and i write migration function, but this is dangerous, so i am trying to be careful and test all. Then i will try to do something with map.

About Librarium. It overrides SetupBook function. My AddOn does same. And Librarian too. So question is in order, who did it last. So last will receive all calls of SetupBook function. I am not advanced AddOn creator, just beginner, but i think this is normal behavior. Correct me if i am wrong. Thank you
Hi!
So I use this one for local coordinates:
Code:
GetMapPlayerPosition(unitTag)
Returns: normalizedX, normalizedZ, heading, isShownInCurrentMap
And this for world coordinates:
Code:
GetUnitWorldPosition(unitTag)
Returns: zoneId, worldX, worldY, worldZ
Regarding the Librarium and the SetupBook function, as far as I know you're right. Whoever did it last will receive the calls. I can double-check my code later, but I'm pretty sure I incorporate the SetupBook function into my new version. Which means if mine comes after yours, it'll inherit any changes you made to the function. Haven't looked at how yours does it, but I'll do some more compatibility testing later to make sure they work fine together.
Last edited by Alianym : 03/24/21 at 08:58 PM.
Report comment to moderator  
Reply With Quote
Unread 03/24/21, 03:04 PM  
LoneStar2911
Addon Addict
 
LoneStar2911's Avatar
Premium Member

Forum posts: 108
File comments: 483
Uploads: 0
Exclamation Errors

Got this today upon login, after updating:

Code:
user:/AddOns/StorySaver/StorySaver.lua:71: unexpected symbol near 'for'
Code:
user:/AddOns/StorySaver/Interface.lua:357: attempt to index a nil value
stack traceback:
user:/AddOns/StorySaver/Interface.lua:357: in function 'handler'
user:/AddOns/StorySaver/Interface.lua:364: in function 'StorySaverInterface.SetupCheckableButton'
|caaaaaa<Locals> control = ud, texturePrefix = "EsoUI/Art/MainMenu/menubar_not...", handler = user:/AddOns/StorySaver/Interface.lua:344 </Locals>|r
StorySaverEventListFrameFilterAndSearchSubtitles_Initialized:3: in function '(main chunk)'
|caaaaaa<Locals> self = ud </Locals>|r
Code:
user:/AddOns/StorySaver/Interface.lua:357: attempt to index a nil value
stack traceback:
user:/AddOns/StorySaver/Interface.lua:357: in function 'handler'
user:/AddOns/StorySaver/Interface.lua:364: in function 'StorySaverInterface.SetupCheckableButton'
|caaaaaa<Locals> control = ud, texturePrefix = "EsoUI/Art/MainMenu/menubar_soc...", handler = user:/AddOns/StorySaver/Interface.lua:344 </Locals>|r
StorySaverEventListFrameFilterAndSearchDialogues_Initialized:3: in function '(main chunk)'
|caaaaaa<Locals> self = ud </Locals>|r
Code:
user:/AddOns/StorySaver/Interface.lua:357: attempt to index a nil value
stack traceback:
user:/AddOns/StorySaver/Interface.lua:357: in function 'handler'
user:/AddOns/StorySaver/Interface.lua:364: in function 'StorySaverInterface.SetupCheckableButton'
|caaaaaa<Locals> control = ud, texturePrefix = "EsoUI/Art/MainMenu/menubar_jou...", handler = user:/AddOns/StorySaver/Interface.lua:344 </Locals>|r
StorySaverEventListFrameFilterAndSearchBooks_Initialized:3: in function '(main chunk)'
|caaaaaa<Locals> self = ud </Locals>|r
Report comment to moderator  
Reply With Quote
Unread 03/24/21, 01:57 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 12
Uploads: 2
Originally Posted by tiker
Originally Posted by f1rex
Can you tell me where i can find this book to reproduce situation? :-)
Sort of.

In Clockwork City, head to the crafting building. Click on the various bookshelves. You'll get random books but the books "The Truth in Sequence: Volume 10" and "The Truth in Sequence: Volume 1" will give you this problem. Typically, I was able to get one or both books without any problems on the second floor of the crafting building, middle section.

What I figured out is that counting the number of characters in the array in memory is not the same when written to file. Take this for example:
Code:
                    ["Note to Throne Keeper Farvad"] = 
                    {
                        ["1714440070-1077"] = 
                        {
                            [1] = "Farvad, \n\nYesterday I happened to pass by the mausoleum of King Ra Boshek and decided to stop by, as I've always admired the Statues of Ward and Warning that guard its entrance. I was shocked to find the crypt in a state of abject negligence. Sand choked the doorway, prayer wheels were faded or missing, and someone had scrawled \"Yazhmeena is Indecorous!\" on the lintel. \n\nThis is entirely unacceptable. Ra Boshek's crypt is in your quadrant of the necropolis, and I must hold you responsible for this malfeasance. I am well aware that, since that incident with the drunken scholar (may Satakal smite him), the remains of Ra Boshek are no longer in residence in his mausoleum. This is no excuse: the re-consecration of His Majesty's remains—what the Ash'abah left of him, anyway—is nearly complete, and his Rite of Re-Interment is to take place at Mid Year. I expect to see his mausoleum restored to pristine condition by Loredas at the latest, or you won't be spending any Fredas nights in Bergama for the foreseeable future. \n\n— Priestess Yazhmeena, High Throne Keeper",
                        },
                    },
Going by the key, this should be 1077 characters. Copy / paste to your favorite text editor and count the characters, you'll find 1079 characters. I don't know if it is the escape characters that make it longer writting to the file or not but it is longer. You might be able to get away with reducing 2000 to 1990 but without knowing why there are extra characters, who knows if that'll work when translating to other languages.
Maybe it is just UTF-8 two-three-four-more-bytes chars. I have changed part size to 500 "chars". I hope it is good stock. Maybe even too :-D. Max size of string in saved variables is 2048 chars, but i think it means bytes, not chars.
Report comment to moderator  
Reply With Quote
Unread 03/24/21, 01:51 PM  
f1rex
AddOn Author - Click to view AddOns

Forum posts: 0
File comments: 12
Uploads: 2
Re: Investigations!

Originally Posted by Alianym
Hey all,

Fellow story-loving AddOn author here. Saw this and just had to take a look.
Anyway, seeing as I've done similar stuff in the past with some of my AddOns, figured I could chime in and potentially help out. Or at least confirm some things.

With the SavedVars string issue, I've personally had no issue with
Code:
length <= 1900
per iteration.

As for the map issue, I kinda solved that too. Kinda. I re-implemented it without LibGPS, because I've never used it before and don't know how it works. I've highlighted in red what I removed/changed, and green what I added.

Code:
function StorySaverInterface:ShowOnMap(data)
    local eventData = data.eventData
    local zoneIndex = eventData.zoneIndex
    local globalX = eventData.x
    local globalY = eventData.y

    --SCENE_MANAGER:Show('worldMap') --I opted to use a base ZOS function to do the same thing
    ZO_WorldMap_ShowWorldMap()

    --Get MapIndex
    local zoneId = GetZoneId(zoneIndex)
    if GetParentZoneId(zoneId) ~= zoneId then --This implementation will only take you to the zone map. Therefore it's necessary to account for subzones
	zoneId = GetParentZoneId(zoneId)
    end

    local mapIndex = GetMapIndexByZoneId(zoneId)

    --Set to Map
    ZO_WorldMap_SetMapByIndex(mapIndex) 

    --LibGPS3:MapZoomInMax(globalX, globalY)

    if LibMapPing ~= nil then
        local localX, localY = LibGPS3:GlobalToLocal(globalX, globalY)
        LibMapPing:SetMapPing(MAP_PIN_TYPE_RALLY_POINT, MAP_TYPE_LOCATION_CENTERED, localX, localY)
	zo_callLater(function() ZO_WorldMap_PanToNormalizedPosition(localX, localY) end, 1500)
    end
end
The delayed function is because otherwise it happens too suddenly and could give people headaches. On big maps like Cyrodiil the zoom speed is still very sudden, but it's mitigated this way. Also I removed the REGISTER_EVENT code, because it wasn't needed in my implementation and actually bugged a couple things out (like the fast-swaps between maps).

Also fun fact, this AddOn will store your interactions with custom books in The Librarium.
Hey, thank you for your post. Anyway LibGPS is used for retrieve global coordinates of player. Maybe you know how to get it without LibGPS?

For now i am trying to do global refactoring of this addon. New feature is coming (deduplication). Variables structure will be changed and i write migration function, but this is dangerous, so i am trying to be careful and test all. Then i will try to do something with map.

About Librarium. It overrides SetupBook function. My AddOn does same. And Librarian too. So question is in order, who did it last. So last will receive all calls of SetupBook function. I am not advanced AddOn creator, just beginner, but i think this is normal behavior. Correct me if i am wrong. Thank you
Report comment to moderator  
Reply With Quote
Unread 03/24/21, 02:40 AM  
Alianym
AddOn Author - Click to view AddOns

Forum posts: 3
File comments: 51
Uploads: 6
Investigations!

Hey all,

Fellow story-loving AddOn author here. Saw this and just had to take a look.
Anyway, seeing as I've done similar stuff in the past with some of my AddOns, figured I could chime in and potentially help out. Or at least confirm some things.

With the SavedVars string issue, I've personally had no issue with
Code:
length <= 1900
per iteration.

As for the map issue, I kinda solved that too. Kinda. I re-implemented it without LibGPS, because I've never used it before and don't know how it works. I've highlighted in red what I removed/changed, and green what I added.

Code:
function StorySaverInterface:ShowOnMap(data)
    local eventData = data.eventData
    local zoneIndex = eventData.zoneIndex
    local globalX = eventData.x
    local globalY = eventData.y

    --SCENE_MANAGER:Show('worldMap') --I opted to use a base ZOS function to do the same thing
    ZO_WorldMap_ShowWorldMap()

    --Get MapIndex
    local zoneId = GetZoneId(zoneIndex)
    if GetParentZoneId(zoneId) ~= zoneId then --This implementation will only take you to the zone map. Therefore it's necessary to account for subzones
	zoneId = GetParentZoneId(zoneId)
    end

    local mapIndex = GetMapIndexByZoneId(zoneId)

    --Set to Map
    ZO_WorldMap_SetMapByIndex(mapIndex) 

    --LibGPS3:MapZoomInMax(globalX, globalY)

    if LibMapPing ~= nil then
        local localX, localY = LibGPS3:GlobalToLocal(globalX, globalY)
        LibMapPing:SetMapPing(MAP_PIN_TYPE_RALLY_POINT, MAP_TYPE_LOCATION_CENTERED, localX, localY)
	zo_callLater(function() ZO_WorldMap_PanToNormalizedPosition(localX, localY) end, 1500)
    end
end
The delayed function is because otherwise it happens too suddenly and could give people headaches. On big maps like Cyrodiil the zoom speed is still very sudden, but it's mitigated this way. Also I removed the REGISTER_EVENT code, because it wasn't needed in my implementation and actually bugged a couple things out (like the fast-swaps between maps).

Also fun fact, this AddOn will store your interactions with custom books in The Librarium.
Last edited by Alianym : 03/24/21 at 02:42 AM.
Report comment to moderator  
Reply With Quote
Post A Reply



Category Jump: