JDataKit: Python Data Storage Utility

Jeckel

Great Reverend
Joined
Nov 16, 2005
Messages
1,637
Location
Peoria, IL
JDataKit Modding Utility

This mod component is not ment for stand alone use. If you simply add this mod in by itself
there will be no ingame changes.

This comp is intended as a wrapper to Stone-D's SdToolKit. Instead of importing the methods from SdToolKit, you would instead import this mod's methods. Its main function is that the mod adds another level of storage to SdToolKit. It also automaticly stores the given data under a given unit. The code is pretty well documented and explained in the files so check it out for your self. :)

One final note. I had to put a new function in the SdToolKit file. It is surounded by
## JDataKit Start ##
and
## JDataKit End ##

and is also been added to the SdToolKit's readme file.


This modcomp comes with Dr Elmer Jiggle's CustomEventManager and a CvJDataKitEventManager.py file which sets the onUnitCreated and onUnitLost events. These two events set and remove Types dictionaries on all units so that types and stats can mearly be set and gotten.


The meat of the modcomp and the only file that is nessesary, besides SdToolKit.py, is CvJDataStorageUtils.py.

There are three important terms that are used in this code. They are Type, Stat, and Value. A Type is made up of a Python Dictionary. Each Type dictionary contains 0 or more Stats and each Stat has a Value. Throughout the code and the info below, TypesDict and similar referres to the primary dictionary for each unit that contains the individual sub dictionarys of Stat/Value pairs.

For example take the TypesDict

{ "Physical" : { "Strength" : 4, "Dexterity" : 2, "Stamina" : 3 }, "Social" : { "Appearance" : 3, "Manipulation" : 1, "Charisma" : 4 } }

In that example the entire dictionary would be the primary dictionary that is stored on a specific pUnit object. Each key of the primary dictionary, the "Physical" and "Social" keys, is termed a Type. The value of each Type has set as its value a dictionary, this sub dictionary is termed a StatsDict or a dictionary of Stat/Value pairs. Both Types and Stats should be strings as other kinds of data may have unforseen results. The python dictionary value of each Stat is termed Value and is being referred to when the capitallized version of the word is used. Though I origionally wrote this with the intention of storing only integars and maybe strings as Values, I don't forsee any problems storing any kind of data that would be normally exceptable by SdToolKit.

Also important to note. While I use pUnit in my examples, any Civ obj that has the methods pObj.getOwner() and pObj.getID() can be used to store data in a data pool unique to that object. If at anypoint the owner or ID of the object changes, neither SdToolKit nor my wrapper code transfers stored data, all this must be done by the modder.

This files methods are listed and explained below.

####################################################

Spoiler :
CvJDataStorageUtils.py

initTypesDict(pUnit, dictInit=None)
Returns True on success, False on failure.
This method sets the initial types dictionary on the unit. You can give an optional dictionary that will be used instead of the default one.

initTypeStatsDict(pUnit, xType)
Returns True on success, False on failure.
This will initiate a blank StatsDict under the key xType. This StatsDict can then have Stat/Value pairs written to it with the set methods below.

########################
# Verification methods #
########################

hasTypesDict(pUnit)
Returns True on success, False on failure.
Tells you if the unit has the primary dictionary of Types set on it.

hasTypeStatsDict(pUnit, xType)
Returns True on success, False on failure.
This takes a Type and tells you if the offered unit has a dictionary of Stats listed under that Type.

hasTypeStat(pUnit, xType, xStat):
Returns True on success, False on failure.
This takes both a Type and a Stat and tells if the unit has that Stat.

###################
# The set methods #
###################

setTypeStatsDict(pUnit, xType, dictStats=None)
Returns True on success, False on failure.
This takes a Type and an optional python dictionary containing Stat/Value pairs. If the optional dictionary is not provided then the Type's StatsDict will be set blank. If the optional dictionary is provided then it will replace the current Type's StatsDict. Note if the Type does not exist, this method will auto initTypeStatsDict() for you and then set the value as normal.

setTypeStat(pUnit, xType, xStat, xStatValue=None)
Returns True on success, False on failure.
This works much like the other set, but it requires a valid Type and will NOT auto create one. Stat does not have to exist yet, and if it does the current value will be overwritten by xStatValue. If xStatvalue is left blank or set to None then the Value of Stat will be set to the integar 0.

######################
# The delete methods #
######################

Note: All the delete methods return True if given nonexistant Types or Stats.

delTypesDict(pUnit)
Returns True on success, False on failure.
This will remove all JDataKit stored data. It will NOT effect in any way other data stored by SdToolKit.

delTypeStatsDict(pUnit, xType)
Returns True on success, False on failure.
This will remove a Type and all the Stat/Value pairs in its dictionary.

delTypeStat(pUnit, xType, xStat)
Returns True on success, False on failure.
This will remove a single Stat/Value pair from a Type's StatsDict.

###################
# The get methods #
###################

getDataIDStr(pObj=None)
This is intended for internal use and merely returns a unique ID string for a given CyObject.

getUnitStatsStrType_StrStatList(pUnit, strDelim="_", bStatsTypeFirst=True)
I wrote this just for fun and to test some things for a non Civ project.
What it does is returns a list of deliminated TYpe/Stat pairs. So using the example above, this function would return a python list object, ["Physical"_"Strength", "Physical"_"Dexterity", "Physical"_"Stamina", "Social"_"Appearance", "Social"_"Manipulation", "Social"_"Charisma"].

getTypesDict(pUnit)
Returns a dictionary obj on success, False on failure.
This will return the entire TypesDict of the given unit.
Note: This method requires the sdGetEntity method added to the SdToolKit file and will not function without it.

getTypeStatsDict(pUnit, xType)
Returns a dictionary obj on success, False on failure.
This will return the StatsDict for a given Type.
Note: This method requires the sdGetEntity method added to the SdToolKit file and will not function without it.

getTypeStat(pUnit, xType, xStat)
Returns None on Failure.
This will give you the Value of the given Stat.
Note: This method requires the sdGetEntity method added to the SdToolKit file and will not function without it.


The reason I wrote this utility to wrap around SdToolKit is the problem of transfering the stored data from one unit object to another, say when its allegiance changes in the UnitAllegiance Mod. In game terms the unit didn't die, it is the same unit, just owned by someone else, but in code terms the old unit (and all the stored data for it) are gone. For example, that units religions from the JUnitReligion would be gone and lost forever unless I planned for allegiance change in the religion mod or religion in the allegiance mod. Neither of wich is exceptable.

Hense I wrote this. Now if the religion mod sets the religions with JDataKit, then the allegiance mod, or any mod that uses different unit objects for the same ingame unit, can use JDataKit to get that units intire data and put it on the new unit obj.

I will be going over my previous mods as I get time and transfering them to use this storage structure. I also am finishing up some addons for this that will provide more specific options and functions for CyUnits and auto setting of data on them. Don't know if anyone else will find use of this, but its out there none the less and will make my life easyer. Use as you will. :)


File: JDataKit_v0.11.zip
Compatible: Civ4 v1.61 and Warlords
Mod Folder: Mods\JDataKit
Released: October 10, 2006
Size: 20.4 kb

CivFanatics: JDataKit Modcomp v0.11 File Now Available
 
Great job Jeckel :goodjob:
 
Thanx TheLopez. :D

If that was you that already downloaded it, I had to take out a pUnit.isDead() check in the hasTypesDict(). I have reuploaded the corrected file.

Sorry for any inconvieniese and hope it helps out. :)
 
Is there an example file available, or could you say, how to implement this to DataStorage.py, sdToolKit.py and/or SdToolKitAdvanced.py ?
 
Hehe, I am acually finishing up and testing an example mod right now that will add some stats to each unit.

But the simple explanation is this. From the download zip you need the CvJDataStorage.py file and the SdToolKit.py file. From that point you ignore the SdToolKit.py file and import the CvJDataStorage.py. You then basicly use the CvJDataStorage's methods just as you would sdToolKit methods. The only difference is you gave SdToolKit a string to store the data under, with this you instead give it a CyUnit object.

Check the spoiler in the first post for peticulars on what each method does, but other then the naming of things, it functions basicly just like SdToolKit.

But as I said, I am finishing up a mod that uses this modcomp utility and should have it out in a day or two. :)
 
Dur, I can't believe I forgot, the mod I released a few days ago, JNavalEnhancements, uses this modcomp utility to store its data. The eventmanager file that comes with the download also has a simple example of initializing the data for new units and deleting from dead units. :)
 
OK, so I'll have to import yours, instead of sdToolKit.py.
But what about DataStorage.py and/or SdToolKitAdvanced.py ?
Because they use different prompts.
Will these be passed through or will there be problems?
And how to transfer the stats in the UnitAllegiance Mod?
And, I think this is the main question, will this be useful for other mods than UnitAllegiance, and if yes, could you please give examples, when should I use yours instead of the origin?
 
It will not use the DataStorage.py or SdToolKitAdvanced.py that you mention. My comp imports SdToolKit and uses its prodived methods plus one method that I added. So only the SdToolKit.py provided with the modcomp will work for sure.

I don't forsee to many situations that would demand the use of this modcomp other then UnitAllegiance Mod and my own JUnitCapture Mod. But another example could be if a mod at some point needed to turn a unit of one type into a unit of another type, say turning a unit into a slave when they are fortified in a Slave Camp for X turns. Beyond that I really can't name any petecular instances. While indiviual modders may never need it, it may be a nice tool for those that combine mods and find one of the mods changes the CyUnit at some point.

As long as it allows my mods to work even after a unit has changed allegiance then it has served its purpose to me. :)
 
Thank you for your answer, and I'm glad that not so much files have to be changed.
Jeckel said:
As long as it allows my mods to work even after a unit has changed allegiance then it has served its purpose to me. :)
In my case I combined the UnitAllegiance with the Slavery mod and now I'm interested in passing the settings of unit #1 to unit #2 as you said for settler and unit religion mods and alos for the unit statistics mod.
How do I do this? It seems that I am too dumb to get the whole interdependences.
 
What will I have to do for passing the sdToolkit-entries form old units to new units? For example in the UnitAllegiance Mod.
 
Ok, sorry it took me a minute, been busy on another project. :)

To transfer JDataKit stored data from an old CyUnit to a new CyUnit:

Code:
def transferUnitData(pOldUnit, pNewUnit):

        dictOldData = CvJDataStorageUtils.getTypesDict(pOldUnit)

        if (not CvJDataStorageUtils.delTypesDict(pUnit)):
                CvJDataStorageUtils.initTypesDict(pUnit, dictOldData)
                return None

        for strType in dictOldData:
                CvJDataStorageUtils.setTypeStatsDict(pNewUnit, strType, dictOldData[strType])

        return None

By passing the old CyUnit object and the new CyUnit object to this method, all the JDataKit stored data will be moved. :)
 
Ah, Ok, but for being able to use this function, I'll have to use yourwrap-around, ther's no other way, right?
 
Correct, only data stored with the wrapper will be seen/useable by the wrapper.

As for doing it another way, unless I missed somthing, the standard SdToolKit lacked a way to get an entire data pool, you could only call items within the pool. I'm not sure if you can do that in the other storage files you mentioned, but the standard one seems to lack it. That in itself is an easy thing to fix and the method was only like 5 total lines of code and just took a few lines out of the normal sdGetVal() method.

The problem though, is most data in SdToolKit is stored in sub data pools of a primary data pool, both of which get unique string names. Since modders all use their own naming conventions to denote their mod's data and subdata pools, it is a real pain to call specific data from outside the mod it was stored in. You have to know that other mod's naming conventions and which pools hold which subpools which hold which specific data. This makes getting the data for one unit from 8 different mods very difficult. Even if all the mods use
Code:
str(pUnit.getOwner()) + "_" + str(pUnit.getID())
as the name of each unit's subdata pool, you would still need a list somewhere that listed all the primary data pool names and some code to check all of them and gather their data. This list would then have to manually updated each time you add a new mod.

The main purpose of this mod is fixing this problem of widely scattered and variously named data pools by providing a standardized way to store and retrieve unit data. The fact that everything is stored in one spot and can be easyly gotten and moved is just a happy (and planned ;)) side effect. :)
 
Back
Top Bottom