What I want to do:
> Store, and process, actor-specific data (such as health, occupation, etc), in such a way that it's naturally included in AC's Save/Load system, or, if that's not possible, in such a way that it can be saved at the same time as AC executes a Save (and, of course reloaded when AC executes a Load)
Currently I'm storing this data in the AC Global variable system. It's just about manageable with only a few actors, and just a few types of data, but even then the variable system gets clogged up very quickly, and it's clearly sub-optimal to store a set of variables called, e.g. Actor1_Health, Actor2_Health, Actor3_Health, etc etc. That's why god invented arrays
But, no arrays in AC, so I need to come up with some other mechanism for handling such data
Now, I know how to script a system to store the data under normal, non AC, circumstances, and, I know (theoretically at any rate) how to use AC scripting to keep such data synchronised with the AC Save/Load system. But, that doesn't really get me any further forward, because in order to do that, I have to pre-define the variables I'm going to use in the AC Global variable system, so... it's still going to get clogged up very fast
So, what to do? I'm sure other users must have come up against this problem before. In AGS you can define arrays within its scripting system, and that data automatically gets included in the AGS Save/Load system, but I can't quite get a handle on how to achieve the same thing in AC, so any hints or tips would be much appreciated
Comments
"100;090;001;110;100;"
It seems a little bit of an awkward, and potentially error-prone solution, but it does have the big advantage of keeping the number of AC global variables down, and would mean that the data would be automatically included in the AC Save System
I actually wrote a script a while back to encode and decode the data in this kind of format, before abandoning the idea, but I wonder if this is potentially the best solution after all?
There's also Json serialization, but I rather like the method above.
Two tutorials are available on custom save data:
I've had a need for this facility pretty much since day one, but I've put off doing anything significant about it in case I ended up heading down a blind alley (and also because I'm a lazy boy at heart)
Sounds like I wasn't too far off the right track with the idea of storing each dataset as a delimited string, but saving the data independently via binary serialization has some attraction too
Pros and cons for both approaches, I suspect, but the only way to find out will be to knuckle down and actually try and implement one, or the other, (or both)
@Alverik thanks for those code snippets. I'll probably use them as a template for my experiments. I may report back in this thread later, depending on how things progress
@HarryOminous: As the update tutorial describes, the best way to hook into AC's save system is to hook into the OnBeforeSaving / OnAfterLoading custom events.
Once I was confident I wasn't going down a blind alley, it didn't actually take that long to get something up and running
In the end I settled on saving each array as a delimited string, which has the advantage that you can see (at least part of) the data dynamically in the Variables Manager, which may prove helpful in debugging. It also means that the data is naturally included in AC's Save/Load system
What proved very useful was Alverik's str.Split(',') trick, which I used to replace some horribly clunky code I'd written earlier when I was first thinking about this approach
Basically what I do is initialise the string "arrays" when the game starts, and maintain the data in a set of real arrays, in parallel. I rebuild the string equivalent whenever the real internal array data changes, and I rebuild the real internal arrays from the string data whenever an AC Load occurs
All I need to do now is write some ActionLists, one to Set the data for each array/element, and one to Check the data. Writing user ActionLists is well documented (as is everything in AC) and I've already written a couple of small ones for other functions, so I'm not expecting (famous last words) that to prove problematic. I'll use ActionVarCheck and ActionVarSet as templates
The only thing that's delaying me on that score is trying to decide whether it would be better to create one giant whack-off version of each to handle all the different arrays, driven by enums to control which array to process - or whether it would be better to create one ActionList per array. I suspect the former is the correct way to do it, even though it will probably lead to large, indigestible, chunks of code
Thanks again for the feedback
so, hopefully the post hasn't gone for good, but if it has: "thanks for the feedback, and this is how i implemented it" (um, yanno, with the strings, and the parallel arrays, and the onafterloading events, and suchlike)
As to the matter in hand, I settled on creating one single "Array Element Check" and one single "Array Element Set" ActionList, which allow the user (me) to select by Array name and Element ID (both currently driven by enums), and then check the values in the array, or update them, depending on the ActionList. They're pretty much written now. Just got to battle test them under real game conditions
The only small drawback to the delimited strings approach is that I can only have one array-string per dataset (i.e. I've got one for ActorDialoguePoint encoded as numeric data, one for ActorName encoded as string data, one for ActorNameKnown encoded as boolean data, even though they're all "Actor" arrays with the same number of entries in), and it needs a non-trivial amount of manual scripting in order to add any new ones, as I'll surely need to do. But, I can live with that if it gives me the ability to process array data and keep the AC Global Variable list manageable
Now, back to the fun stuff...