Problem with XML database additions

Firerunner

Chieftain
Joined
Aug 1, 2011
Messages
7
Okay, this is probably a silly beginner problem somewhere that is easily fixed, but I've been spending a couple hours trying to find the error and have become none the wiser.

What I am attempting to do is to create a new mod to grant AI units a combat bonus on higher difficulties to increase the challenge when going to war, and decided the most logical way to do this was to grant all their units free promotions increasing combat strength ala Morale from the national wonder.

However, when I add an XML file to the mod, it doesn't seem to get loaded, even when I've added it to OnModActivated under the mod properties. At least, that is my deduction from the Live tuner error messages when starting the game: [string "C:\..."]:30: attempt to index field 'PROMOTION_EMPERORAI' (a nil value) coupled with the fact that the promotions I defined in the XML aren't present in the UnitPromotions table when I look for them in the console.

This is the Database log:
Spoiler :
[27541.071] constraint failed
[27541.071] While executing - 'INSERT INTO ArtDefine_StrategicView(StrategicViewType, TileType, Asset) VALUES(?,?,?)'
[27544.300] Validating Foreign Key Constraints...
[27544.300] Invalid Reference on ArtDefine_Landmarks.LayoutHandler - "SPECIAL" does not exist in ArtDefine_LandmarkTypes
[27544.300] Invalid Reference on ArtDefine_Landmarks.LayoutHandler - "SPECIAL" does not exist in ArtDefine_LandmarkTypes
[27544.300] Invalid Reference on ArtDefine_Landmarks.LayoutHandler - "SPECIAL" does not exist in ArtDefine_LandmarkTypes
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_PRIVATEER" does not exist in Units
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_SPANISH_GALLEON" does not exist in Units
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_SPANISH_TREASURE CART" does not exist in Units
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_DANISH_LONGBOAT" does not exist in Units
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_SAXON_HUSCARL" does not exist in Units
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_POLYNESIAN_WAR_CANOE" does not exist in Units
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_HITTITE_WARCHARIOT" does not exist in Units
[27545.174] Invalid Reference on UnitGameplay2DScripts.UnitType - "UNIT_SUMERIAN_PHALANX" does not exist in Units
[27545.174] Failed Validation.
[27545.548]
-- SQLite Memory Statistics --
Memory Usage:
[Cur] [Max]
Malloc: 287688 2406080
PageCache: 3527 3742
LookAside: 45 1878
Scratch: 0 1

Static Buffer Overflows:
[TooLarge] [NoSpace]
PageCache: 0 0
Scratch: 0 0

Largest Allocations:
Malloc: 65280
PageCache: 1160
Scratch: 5128

Prepared Statements:
Current: 5

This is the XML log:
Spoiler :
[27544.285] **** Validating Game Database *****
[27545.174] Performing Localization Checks
[27545.174] Checking Tag Format...
[27545.174] Note: Tags must only use [A-Z_] characters, start with 'TXT_KEY_', and be under 128 characters long.
[27545.190] Validating UnitGameplay
[27545.190] Number of selection sounds doesn't match number of units.
[27545.190] Validating Notifications
[27545.190] **** VALIDATION FAILED *****
[27545.190] Validation Took 0.912791 seconds
[27545.548] **** Validating Prefetch Process *****
[27545.548] **** Validation Success *****
[27545.548] SetGlobalActionInfo
[27545.548]
-- SQLite Memory Statistics --
Memory Usage:
[Cur] [Max]
Malloc: 287688 2406080
PageCache: 3527 3742
LookAside: 45 1878
Scratch: 0 1

Static Buffer Overflows:
[TooLarge] [NoSpace]
PageCache: 0 0
Scratch: 0 0

Largest Allocations:
Malloc: 65280
PageCache: 1160
Scratch: 5128

Prepared Statements:
Current: 5

As far as I can tell from looking around these are normal and not indicative of errors on my end, right?

Note: Right now the .lua file will grant the promotion to all units (including the player), which I'm aware of and using to test it more easily.

I've attached the mod in its current state in a zip file, any pointers to what I'm doing wrong would be greatly appreciated. :)
 

Attachments

Okay, the main problem is that you defined TXT_KEY_PROMOTION_KINGAI three times (you obviously meant to rename the last two). Because you can't do that, the game threw out the entire XML file. Fix that and it should be fine.

Beyond that, here are a few things to consider:

1> Contrary to its name, SerialEventUnitCreated doesn't just trigger whenever a unit is created. It also triggers whenever a unit embarks, disembarks, upgrades, rebases, or a few other things. In this particular case that isn't a problem as you'll never want to remove the promotion once you have it, but you'll waste quite a bit of overhead on this.

2> GameInfo["UnitPromotions"]["PROMOTION_KINGAI"]["ID"]
can be much more easily written as GameInfoTypes.PROMOTION_KINGAI instead. Or GameInfo.UnitPromotions["PROMOTION_KINGAI"].ID; there are a lot of ways you can write it.

3> Game:GetHandicapType() gives the handicap for YOU. It does NOT return the handicap for the AIs, who are always on Chieftain. In this particular case you probably want to keep it this way, as you're trying to help the AI when you pick a higher difficulty for yourself, but it's something to be aware of.
 
Ah, so it was a silly mistake, but not of the kind I was looking for (is that ever the case?). Thanks a lot for pointing it out.

From my understanding errors that lead to xml files getting thrown away are supposed to appear in the XML log file, which was what led me to look elsewhere - but that is not always the case, I guess?

Re 1:
I had read that this is the case, but wasn't able to find any hooks that only get called when a new unit is constructed, so I ended up judging the overhead to probably be small enough that it didn't matter too much. Do you know of any hooks that fit better? An alternative could be to check for new units at the start of each turn (since there seems to be a counter available for the total number of units built) and then run on those units, but I'm not convinced the overhead will be smaller by doing it this way.

Re 2:
Noted, and thanks. Far more used to Java and Python than Lua, so hints on how to write concise code is always welcome. :)

Re 3:
Duly noted. Not sure how this would interact with multiplayer, but that is kind of outside the scope of what I am doing at the moment anyway. Still good to know, though.

Re whowhard:
What? I'll admit it was a stupid mistake, but I had tried to fix it for some time and there were a lot of unknowns for me since I haven't worked with Civ mods before. So I decided on posting to clear up whether it was some issue with mod configuration that I wasn't aware of. Or is it the point of the mod that you disapprove of?
 
From my understanding errors that lead to xml files getting thrown away are supposed to appear in the XML log file, which was what led me to look elsewhere - but that is not always the case, I guess?

Usually they'll be in the Database.log. In this particular case, it SHOULD have been in that log; that was what whoward posted a copy of. So you should check to make sure you remembered to enable logging in the first place (in your config.ini file, search for LoggingEnabled; it should be set to 1, not 0). The game will make basic logs even if you haven't turned that flag on, but it'll ONLY give the log for the base game's load, and not the updated log when the mod is loaded.

You see, these log files should have multiple blocks of errors in them if you're using mods; the first block will be for the game's initial load (when it loads the core database), and the second will be for the mods that it loads when you start a modded game. Your log didn't appear to have that second block, which means you might not have enabled logging in the first place.

Re 1:
I had read that this is the case, but wasn't able to find any hooks that only get called when a new unit is constructed,

There aren't any others. But you can still reduce overhead tremendously for longer on-creation functions, solely by checking to see if the current turn number matches the "created on" turn number for that particular unit. Some of us take this further; in my mod, I added a "Rookie" promotion that all units get at creation, and that disappears once it's been in a combat. (The promotion makes the newly trained unit 10% weaker, but gives it double XP for its first fight.) Between checking that promotion and the turn number, it becomes effectively impossible for the unit to trigger this code more than once. In your case it's not very important, since your function only adds a single promotion and so doesn't care if it executes more than once, but if you've got a function that gives, say, extra XP to certain types of units? Then you have to be a lot more careful.

Re 2:
Noted, and thanks. Far more used to Java and Python than Lua, so hints on how to write concise code is always welcome. :)

If all you ever want to use is ID numbers for known entities (which you will, 90+% of the time), then GameInfoTypes is just much easier to use in mods. The long form, like what you used, is the way to go in two situations:
> If you want to use something other than ID for a given type, like in the case of your CombatClass check.
> If you don't KNOW which entity you're going to check beforehand. That is, if a routine passes the string of the promotion type to be used, you can use that variable in the place of the "PROMOTION_KINGAI" and it'll work. Very handy when you want to link entities of different types. For instance, in my Mythology mod there are seven Pantheons, each of which is tied to a specific hidden Project. I can take the name of the Pantheon type for a given player (say, PANTHEON_GREEK), append "PROJECT_" to the start of it, and use that new string as the array index when accessing the Projects structure.
You could have done something similar, assembling the name of the promotion to be added from the name of the difficulty level. But if you're only using a few types, it's better not to bother.

Re 3:
Duly noted. Not sure how this would interact with multiplayer, but that is kind of outside the scope of what I am doing at the moment anyway. Still good to know, though.

Mods don't work in multiplayer, barring the hotseat override Gedemon figured out a while back. So that one's not really a problem in this case. My point was just that it's easy to forget that while YOU might be on Emperor, the AI isn't, and if you'd wanted to pull values from the Handicap arrays you might look in the wrong spot if you're not careful. For your particular situation that's not important, as you're only basing the bonus on the handicap the active player chose.
 
Now I'm somewhat confused, as I have the following set in my config.ini file:

; Enable the logging system
LoggingEnabled = 1

I had another look at the log, and I see that the multiple sections in it might be one section for each mod - from skimming I had assumed that they were for each time you started Civ, so I only included the latest. Though it no longer has the error message in it to make it easy to check.

Apologies to whoward then - I only saw the '....' message and no indications of an edit, which I took to be an expression of disdain either for the concept of the mod or for asking the question, which was why I responded as I did.

Thanks again for the help. :)
 
Apologies to whoward then - I only saw the '....' message and no indications of an edit, which I took to be an expression of disdain

Sorry about that, I'd posted a split second later with more of less the same comments, and I couldn't find a delete button.

Anyway, I tend to do sarcasm and leave disdain to others ;)
 
Back
Top Bottom