Part of the data structures package.
An InfoArray is an array, which is used for holding data in info classes. In other words, it is intended and optimized to read XML data and not be edited once set.
Note: all files mentioned here are in Data.
The class contain an array of tokens.
A token is an array of shorts of length 1 to 4.
An InfoArray is set as InfoArrayMod. This is a child class of InfoArray, which has the functions to modify the content. InfoArray itself can't modify itself, meaning passing a pointer to an InfoArray should be safe even if it isn't const.
The constructor takes 4 arguments, all of them JITarrayTypes. Those are used to tell which type each index in the token represents. Using JIT_ARRAY_NO_TYPE will reduce the size of the token and all but the first arguments defaults to JIT_ARRAY_NO_TYPE.
The JITarrayTypes enum is in MOD_enums.h
In the reading class, call the read like this:
InfoArrayName.read(pXML, getType(), "Tag");
That's it for reading. Based on the types given to the constructor, the read function will figure out how to read everything in Tag. There is no need to tell the code what the XML looks like as autodetection should take care of that.
The JITarrayTypes given to the constructor tells what each index in the token should contain. Set in MODS_enums.h, most of them links to an XML file. This mean the loader will assert if the string is not found as a type in the string in question. It will not care if the string is present as a type in another XML file.
There are a few types, which will not link to a file, but rather have a different meaning.
Reads as an int.
The intention here is to read as a float. However the data is stored in a short. As a result, a float is read, multiplied by 100 and then stored as an int.
Technically it will be the same as storing an int, but it can produce more readable XML files. The first usage was for unit yield demands. For some reason some people had an issue figuring out that 100 meant using one yield/turn. Adding the demands as a float helped on the problem. If 10 units use 0.1 each, it is easier to read that they add up to 1 each turn.
TODO write something on how the code will accept various XML layouts and what it will read in each case.
There are just a few functions for getting info out of the array.
Tells how many tokens the array contain
Tells how many variables each token contain
Returns the types set by the constructor. Valid arguments are ints from 0 to 3.
This will return the value of token A. B is the index inside the token and defaults to 0 as this is the most often used value.
The * part is because there is a get function for each type, at least if InfoArrayGet.h is filled out completely. The interesting part here is that this approach will set the return type to match the XML type, like if the index is of type JIT_ARRAY_UNIT_CLASS, then the return type will be UnitClassTypes.
InfoArray is exported to python. However python isn't as strict with types and all get functions are merged into get(A, B).
Say we need an array of free promotions. The first argument in the constructor will then be JIT_ARRAY_PROMOTION while the rest are default.
When reading, strings are read from XML. They are compared to types in GC.getPromotionInfo() to find a matching index and will assert if nothing is found. This mean it will not accept TERRAIN_GRASSLAND and convert that to a promotion index (vanilla will not detect the usage of a wrong type for this).
When reading, getPromotion(index) has to be used. Any other get function will cause an assert. The return type is PromotionTypes.
This highly strict type system is intended to catch bugs where XML or DLL modders mix up types. However python will not use this strict system, which mean the modders should be more careful.
It's actually fairly simple:
for (int i = 0; i < pInfoArray.getLength(); ++i)
value = get*(i)
What might be less obvious (to some) is that the pointer directly to the InfoArray can be cached
const InfoArray* pInfoArray = GC.getXMLFILEInfo().getInfoArray()
This way the computer will not have to fetch the pointer each time it has to use it and the code will run a bit faster. It will also make it easier to step in the debugger as the loop control will only call getLength(), which itself is just a get function for an int.
No need to understand this section. It's only added to tell what goes on behind the functions.
The code is written under the assumption that the array will be looped when used. Because of this, it is technically a single short array of length = (length * token length) where the shorts are placed token by token. Since the array is allocated in a single block of memory, looping it will ensure sequential memory access, which in turn gives ideal conditions to utilize hardware caches.