How would you suggest AI_unitUpdate and AI_chooseProduction being controlled from the XML though?
For AI_unitUpdate, I see you have provided unitinfos PythonDoTurn. But, I imagine this is in *addition* to whatever movement the AI makes for the unit as part of the normal turn. I have many units for which I have written the movement logic in python. AI_unitUpdate returns true or false, true if I have made a move, false if I couldn't find anything and I want the normal AI to move it. Can you add this callback? My AI_unitUpdate gets messy with a big set of if-statements to get to the right unit type, and it is hard to merge individual units into another mod.
For AI_chooseProduction, what I want to do is override the decision that a city makes, about what unit to build next. I am not sure how to "hang" this off a python callback defined in XML; I guess I need to think about that more, unless somebody else has a good suggestion.
The callback method for a particular civic is called both when it's being activated or deactivated (along with specialists, religions, promotions, etc.) One of the arguments passed to the python method is the integer "iChange", which is either a 1 or a -1 depending on whether you're switching to or switching from a particular civic.
Please make this more clear in the documentation. Rereading your example #1 for the third time, I finally spotted the "iHappiness * iChange", but only after you told me in this thread. In addition, a prototype for each function would be helpful as a quick reference.
Other thoughts ...
onImprovementBuilt is very helpful, corresponding to ImprovementInfo PythonCallback. I suppose it would also take iChange, called with -1 when the improvement is destroyed. It is important to note a "bug", or design philosophy anyway, for improvements. There is onImprovementDestroyed; but this is *not called* when an improvement is built over. If I build improvement A, and later build improvement B on the same plot, A is destroyed but the onImprovementDestroyed event is not generated. I would call this a "bug", but the destroyed routine may be intended to give a pillage bonus, and building over an improvement should not generate that. I worked around this for my particular case, but in general if some benefit is given when an improvement is added, it should be removed when the improvement is built over.
One challenge for calls to AI_unitUpdate is that you may want to add, or delete units during the call. For example, a unit may wish to delete itself, or convert itself into another unit which is both a delete and an add. Doing this during the AI movement loop is a big no-no. You get inconsistent results and occasionally huge runtime. I do not understand the details of why, but generally, you should not modify a list while some other routine is in the middle of iterating it. I am not sure if other modders have had this problem.
In both of my large python projects, I have had to maintain a separate list object, of "unit add/delete to process after the AI loop". So my code for an AI_update may wish to delete the unit; instead it calls a subroutine to add the deletion request onto this list. Then in my onEndGameTurn, I walk through this list and perform the adds, conversions and deletions and empty the list.
So if you do provide a nice hook for AI_unitUpdate, you may wish to provide this type of list. It would be more of a convenience than a necessity, I suppose, because the author can always put their own list and onEndGameTurn. But it took me a while to figure out why I was getting inconsistent results and/or long runtime; so other modders may run into the same problem and give up on python without understanding why.