Simple Python Things

If you want to preserve values across a save/load cycle you need to store them in the savegame file, and the easiest way to do that is to put them in some object's scriptdata value since those get saved. The scriptdata is just a text string, so you can write whatever you want to it. (As per j_mie6's suggestion.)

If you have multiple different things to save you can save each to a different object. Every plot has a scriptdata field, as does every player, every unit, every city, and one for the game object (there may be more things that have it too, I didn't check). Alternatively you can write each of them into a dictionary and use "pickle" to save the dictionary on just one object - this has the advantage of not having data overwrite other data if you are not careful. For limited usage, typically plot related things are saved to the matching plot, unit related things to the unit, city related things to a city, and "other stuff" to the game object. If the stuff to save is a class, list, dictionary or such non-simple thing then you use the "pickle.dumps(x)" function to serialize it - a fancy term for converting it to a text string that is in a known format which it can later convert back to the original data via the "pickle.loads(y)" function. If you have multiple values to save then you can put them into a list and pickle the list and put it into a scriptdata to save it, then to load it you unpickle the scriptdata and extract the items from the resulting list. You can look at the original Final Frontier for examples of using this sort of thing directly or Final Frontier Plus for an example of using BugData.

You'd do this in the onPreSave game event handler. Then you'd retrieve the data in the onLoadGame game event handler.

There are mod components that add methods of doing this relatively transparently, so you do not have to put in the code to do the load and save yourself for everything. SdToolKit has stuff for this (the "sd" might stand for "store data") and I think it lets you store the data on any object. The BUG mod also has stuff for this in BugData.py which only uses the game object to store a dictionary of data, and this is already present if you are using BUG (otherwise adding just this may require some other chunks of BUG and figuring out how to make it work - what to call where).

In the long run, using the method of storing everything in a dictionary on the game object is better since it deals with the "multiple things that would otherwise use the same scriptdata" issue. The key into the dictionary is something relevant to the data being stored (like a mod component name, for example) and the data for that key is likely to be a single value, list of values, or another dictionary. This would be good, for example, for storing data for multiple different mod components, like wonders and special units (although in the units case you can probably store data about the unit on the unit itself without much of an issue, unless you then want to add a mod component that also stores data on units).
 
I already have an example for the storage somewhere, but I always forget it's usage :blush: (and never really understood it before this explanation :blush:, so thank you :)). But that's not my main concern, but rather that it adds another level of complexity. Had not thought about the conflict with other mod components, but this could theoretically also be problematic (at least problematic enough that I don't want to deal with it; but I guess the conflicts would not be numerous, so it's not a *that* big problem).
Guess it has to go this way.

Any more hints about the SdToolKit? Not for now, but possibly for later.
 
Any more hints about the SdToolKit? Not for now, but possibly for later.
I have never actually used it.

Apparently it defines a small number of functions(well, not so small - there are at least 3 different sets, some of which are more capable than others) that you use, mainly two that you use yourself in your code to get/put the values from/into the thing any time you use them, much like using a database to store your data. A quick look at SdToolKitCustom.py and it appears that you don't actually need to put anything into the onPreSave or onLoad event handlers - any time you change the data it always loads the data into the scriptdata (in fact, it first gets its data from the scriptdata, creating a new dictionary if it fails, sets/changes the data, and then loads it back into the script data). This is a bit inefficient but saves you from having to modify those event handlers so use of the code is entirely self contained wherever you use it.

If you want to make your changes independent of a 3rd party toolkit you could do it that same way yourself (possibly using it as an example of how to do so), but that still leaves you with the potential of multiple mod components interfering with each other which is a big part of what this sort of tool was made to avoid.

I'm beginning to think that, since the is "Simple Python Things", it might be better to skip the toolkit and just do it directly on the object in question (the unit, in this case). You could use the SdToolKiitCustom.py as an example of what to do, including the error checking you might want (you might end up trying to extract data the first time when it has not yet been initialized so there is none, for example).
 
Thanks :).
But sounds a bit complicated. Not sure if it's worth dealing with it for so small mod components, but well...don't know what I might do in the future :D. Just have to remember it at the right point.

Edit: Ah, I see your edit :D. Might take a look :).
 
I have something to add to that:

you say that you may try to extract something that doesn't exist yet...

I would suggest using a pickled script data dict (like we use in jamie's rome, see baldyrs civplayer.) and then overide the dict with a DefaultDict (you would have to make it but I can supply the code) which is making use of pythons overloaded types to make it so that dictionaries return a default value if there is no value to be had!
 
the code is literally:
Code:
class defaultdict(dict):
    def __init__(self, default=None):
        dict.__init__(self)
        self.default = default

    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.default

:p
 
...okay...just looked at that stuff...and it would still be overkill.
Since I only have to save a single integer per instance, I don't even have to use pickle, but just scriptData would be enough, wouldn't it?

And nothing prevents me from setting this data every time it changes, yes? Don't have to go through saving all that stuff before the savegame is created, right?
So that currently makes for me 5 additional lines (4 lines loading/exception handling, 1 line saving). Nothing more. Or am I missing something?
 
...okay...just looked at that stuff...and it would still be overkill.
Since I only have to save a single integer per instance, I don't even have to use pickle, but just scriptData would be enough, wouldn't it?

And nothing prevents me from setting this data every time it changes, yes? Don't have to go through saving all that stuff before the savegame is created, right?
So that currently makes for me 5 additional lines (4 lines loading/exception handling, 1 line saving). Nothing more. Or am I missing something?

That sounds correct. Since it is only one value you can easily just load it at the start of the code (or initialize it if that fails), use it, then save it when you are done. The integer to text and text to integer do not require the pickle stuff.

You also do not need anything in the pre-save or load event handlers since you are loading and saving directly every time you use the data. If you did this in multiple places, and/or in event handlers or callbacks that are called a lot, this would be inefficient but still probably not cause a very large reduction in speed. (In fact, it turns out that the SdToolKit stuff doesn't modify those either - it always loads and saves to the scriptdata any time the data is retrieved or set too. I think BugData may have code in those event handlers, making it a bit more efficient if it does, but I'm not really sure. FFP only stores and retrieves its data from the BugData stuff in those event handlers, so FFP is getting the reduced calls to pickle/unpickle the data and transfer it to and from the DLL whether or not BugData does it that way but that is because vanilla FF was "manually" doing about the same thing in those two places anyway.)

It is also easier to add the feature to a mod if you don't need to modify some event handlers in addition to adding the code that actually does the work.

Which is why I started to think the toolkit was overkill. It is in some ways better, since when it is in use you can avoid issues from having multiple different mod components (but may have to convert them to use it when merging), but it adds a whole new download to be installed just to get this one "simple" thing working.

If you ever need to store something else from some other mod component on the same units (like something that adds some data to many different units - a disease system where they can be spread by units, for example) then that is when I'd consider using something like the toolkit (or directly do the same type of thing it does), especially if the data is more complex than just a number or two. If you get multiple mod components that save data and someone had a problem with them, that might be the time to write a tutorial on how to convert them to use a toolkit like that. That is a nice option since that time might never come.
 
That sounds correct. Since it is only one value you can easily just load it at the start of the code (or initialize it if that fails), use it, then save it when you are done. The integer to text and text to integer do not require the pickle stuff.

Ah, good, thanks :).

You also do not need anything in the pre-save or load event handlers since you are loading and saving directly every time you use the data. If you did this in multiple places, and/or in event handlers or callbacks that are called a lot, this would be inefficient but still probably not cause a very large reduction in speed.
[...]
It is also easier to add the feature to a mod if you don't need to modify some event handlers in addition to adding the code that actually does the work.

Had the same thought, and since the saving of the data is only run a few times at all per hero unit, I don't think it will be that bad.

[...]
That is a nice option since that time might never come.

:lol: :goodjob:
Sounds overall reasonable for me. No need for that at the moment :).



Good, then I'll upload the thing tomorrow. It works already, but I'll maybe look over it again for some optimizations.
 
Thanks The_J and God-Emperor for support

When you upload it i want to make it a part of Caveman to Cosmos mod.
It will prevent obsolete heroes exploit and give some game balance.
 
No I am not a modder. I have no idea how to do that.

But i talked with others C2C modders and they said that they like this idea but now they had other priorities to implement. So I am very greatful tha you done it.

It is always more simple to implement something that exist than write it from begining.
Once more time thank you very much. I will say them that you are script author.

EDIT:

StartegyOnly (C2C mod native author) said that he cant add this now because it is not done in WOC/BuG style

@The_J

Since you made it. Can you made it in that style also?
 
Give my your mobile so I will send you message on Thursday ;)
 
The_J it is Thrusday now.

Time to wake up and rebuild your heroes mod to WoC/BUG style as you promise.

Sooner you start than faster you finish ;)
Bleasing from hard working people in Poland. ;)
 
Or I thought I'd do it :ack:.
Does anyone with BUG experience have a clue, why one function from the merged file is triggered, but the other not, without any error messages in the log?
e.g. onUnitBuilt is triggered, but no onBeginGameTurn. The log says both has been recognized. And I have no idea where the problem could be :dunno:.
 
Back
Top Bottom