In my preinit stage, I have a large data set being included in the compiled game as a cache.
I’m wondering if this data set is being deep-copied into every UNDO state, which might seriously reduce the number of states available to the player.
If I can guarantee no changes will occur in this data set during gameplay, is there a way to force the interpreter to only keep one copy of the data, and refer to this one copy in all UNDO states?
Is this something the interpreter already does? (Am I worried about a problem that doesn’t exist?)
Not yet. Will it vary by machine? Because mine is kind of a statistical outlier, and would have a lot more memory available for UNDO states than most. I could probably test it on my phone, I suppose…
It’s more a desire to maximize this for the player, than the number of UNDO states being a present problem. I can see there is waste somewhere, and I want to reduce it. If it only offers 20 states but could offer 100, then I would like to push for 100 by reducing copies of unchanging data in each state. (These are fictitious numbers. Idk what the average is for a game.)
EDIT: Specifically, I’m asking if there’s a way to force certain data to be shallow-copied instead of deep-copied, per UNDO state, and/or how these states are made, mostly for the sake of knowledge itself. It’s not so much “I need a solution for a specific problem in one game in particular”.
I remember originally thinking this was how it worked, but I guess I seriously misunderstood something I had read a few months ago, and found myself under the false impression that it copied all the data, per state.
What you’ve posted makes a lot more sense, though, given historical limitations of computer memory.
Thank you for posting this! I am happily corrected!
Um… I’m not sure what there is to verify. If you only get two UNDOs then it looks like that’s what you’re going to be stuck with. (With the notable exception of frobTADS, the Unix console-mode interpreter, which makes the undo limit configurable on the command line.)
The interpreter normally allows 4096 undo records, with one being used every time a property changes. The code comments say that a simple game with the adv3 library uses about 200 per turn, although I suspect that number has probably gone up as the library evolved — the frobTADS source code here says that games typically get only five or six UNDOs with the default value. So I guess it’s not unthinkable that a very large game could end up having two or even just a single UNDO state available.
(Although that does give me pause about my own large game, should I ever get around to writing it…)
Ohhhh okay, so transient still gets included during preinit? I thought transient stuff contributed to preinit calculations, but didn’t get saved in the game file.
4096 records is only 64KB of RAM. I think we could double it without issue. And if anyone was working on a TADS interpreter on a really memory-strapped system they could lower it again (but I suspect TADS wouldn’t fit on such a system regardless of the UNDO size.)
Really the question is if we should only double it, or whether it should be made even bigger than that.
Edit: Based on @RealNC’s advice I’ve increased the undo limit by 16 times. But it will take some time for the other interpreters to include the increase.
We meaning everyone . If we change it in the tads-runner repo then it will filter down to Parchment and Gargoyle. But we could also coordinate to update QTADS and other interpreters at the same time.
Follow-up question: If there are pointers to objects in the cache when the game saves, would these pointers be restored correctly, because the data is cached in the original game file? Do transient references only become nil when the transient object was created after the game began? Or do all transient references become nil, regardless of where the data is stored, or when the data was created?
EDIT: Mostly asking because I’m not sure if my AI needs to hold onto any references to the cache in a save file, should I choose to make the cache transient, lol…
You said: “If there are pointers to objects in the cache when the game saves, would these pointers be restored correctly”
That sounds like the cache is storing references to other objects. If it’s the other way around (other, non-transient objects are pointing to the cache) then it’s fine.
That’s entirely on me for not clarifying. Sorry about that, lol.
Okay, so these specific references would restore correctly from a game save file? A non-transient non-cache object storing a reference to a never-modified, preinit-cached, transient object?
(Sorry if this should be obvious. I ask for clarification a lot; side-effect of my neurotype.)
I was wrong. It’s not fine since the properties that point to anything transient will be set to nil after a RESTORE.
So since you have properties that refer to the cache, don’t make the cache transient. Unless you can manually restore those properties in port-restore or post-restart code.
But you should probably do a simple test to see if the amount of undo steps changes with a transient cache or not. If not (or if the difference is small) then I’d say it’s not worth the extra effort.