falconne
meep
It's great that Civ4's game logic is completely exposed in a SDK, but I was disappointed the framework tightly couples the game rules and game AI. It doesn't allow pure AI mods to be played directly against each other, with different civs in the game controlled by completely different AI modules.
I was hoping there would be something like Robocode that allows AI modules to compete in a single environment without human intervention. I think the advantages of something like that are obvious. Not only does it provide empirical as to which AI modules are better than others, it allows AI mod writers to test newer versions of their mods against older versions, to check if complex changes didn't make the AI worse due to some bug. This isn't so easy when all AI's in the game a driven by the same code.
So anyway, I thought I'd have a crack at creating a utility that allowed this to happen. I decided to start with the SDK first, as this is where most AI coding is done and work on Python later. My goal was to make something that allowed mods that follow the same game rules, but have different AI logic, to be combined into one CvGameCore.dll with ability for different Civs in a game started from this dll to use different AI modules (so, for e.g., if a dll is created with 2 AI mods, then a game started with that dll will have half the AI's using one module and the rest using the other). By "AI module", I refer extracting just the bits of a mod that define AI logic and packaging it into an "AI module" that can coexist with other "AI modules". Combined with AutoPlay, this would create the simulation environment I want.
Because it would ignore non AI classes, this utility would work just as well for total conversion mods, so long as the mods put the AI logic in the places where it's supposed to go.
I now have an initial version that satisfies the the requirements to a reasonable extent. I've been testing it successfully with the Better AI mod for BTS, by having "Better AI" driven Civs play against those driven by the AI shipped with BTS 3.17. This was a good test mod as all the AI changes were done in the SDK.
I was hoping there'd be other substantial AI mods out there I could test with. If anyone's got one please let me know where I can get the source.
I thought I'd put what I have so far out there hoping someone working on an AI mod would try it out to see how well their improvements are coming along and tell me if they find problems with it.
Download: Build #2
How it Works
The tool (called AIColosseum.exe) takes as input the location of the SDK source for the mods to be added to the "colosseum" and a destination path where the colosseum source will be created. The "colosseum source" is code that can be compiled to create a new CvGameCore.dll with the AI modules form each input mod crammed in there.
The architecture of the SDK is such that all AI logic should go in the Cv*AI classes (i.e. the unit AI goes in CvUnitAI class). I used this fact to make the assumption that only the content of those classes are required to construct the "AI module" for that mod. This isn't strictly true, but it's good enough to start with. For a pure AI mod, any changes that are done to other classes should be about fixing game bugs and adding utility functions to support the AI. I take the non AI classes from one mod and assume that those will be compatible with all the other mods given for the utility.
The jist of what happens is, the Cv*AI classes of the colosseum source are hollowed out and turned into abstract interfaces, with every method being virtual and their implementations stubbed out. This interface is a composite of the interfaces of each input mod (i.e. for each Cv*AI class, every method definition that is in at least one input mod gets represented in the new class). Then, for each Cv*AI class, for every input mod, a new class is created that derives from the Cv*AI class (named with the mod's name appended to the basename) and the content of this class will be the content of the Cv*AI class for that mod. Now all the tool has to do is change every location where an AI object is instantiated for a player to use the specific implementation class that is appropriate for the AI module that player is assigned to and polymorphism does the rest. There's quite a few things that must be changed for things to work after this, but that's all detail.
Most of work is actually in analysing the source classes and shifting methods around, dealing with encapsulation, statics, detecting incompatibilities, etc and because some of the classes in the SDK are tens of thousands of lines long, the utility takes a while to run.
I don't create functionality to auto run the game once it has started. I'll do that in a later version, but for now, to be able to create a "simulation environment", the primary mod (the one from which the non AI classes will be copied from) will need to have AIAutoPlay from mrgenie and jdog5000.
Normally, the game treats the human player differently than AI players. Theoretically, on Noble difficulty, there should be no difference between human and AI. Just in case, I've made it so that the first player slot (which is human by default) be treated as an AI during game setup (it has to be set back to human just before the . When running the game using AutoPlay functionality, the first slot is set to be treated as an AI, so it should be all good.
At the moment, you can't pick which Civ gets which AI module - they get automatically allocated as evenly as possible. If you create a colosseum with 3 mods, then Slot1=Mod1, Slot2=Mod2, Slot3=Mod3, Slot4=Mod1, Slot5=Mod2... and so on. Barbarians get assigned whatever mod happens to align with the slot they're in. I will make this selectable in the future too.
When the leader name is displayed on the interface during the game, the name of the module they are running will be appended (e.g. Alexander (BetterAI)), so you can tell who's who at a glance.
Usage
Simple command line usage:
AIColosseum.exe --dest=<destination path> --source=<source path>,<mod name> [...]
--dest is a folder where the colosseum code will be created. It will be created if it does not exist. NOTE: If it already exists, the source files in there will be overwritten without warning!
--source can be included multiple times, once for each input mod. The <source path> is where to find the SDK source for that mod, and <mod name> is how the module will be identified, for naming its classes and showing against the name of leaders using that module. The first source module given will be used as the "primary" module - all the non AI classes form this mod will be copied as the basis for those classes in the colosseum source. This means, even though it's ok for the input mods to have a few differences in their non AI classes, only the functionality of those classes in the first mod will be available in the colosseum, so it should contain the superset of functionality required for all mods.
The utility does not copy anything other than source code from the primary mod to the destination folder. You will need to copy Boost and Python folders, as well as makefiles over to the destination yourself to build it. There are no new files created, so you don't need to modify your makefiles.
NOTE: When starting a game, make sure you select "Noble" for difficulty of the first slot, so it isn't handicapped.
For example, to create a colosseum with the Better AI mod vs the AI shipped with BTS (which I call Vanilla) on my machine, I use:
AIColosseum.exe --dest=D:\Dev\Civ\Colosseum --source="D:\Dev\Civ\Better AI\Trunk\CvGameCoreDLL,BetterAI" --source="D:\Dev\Civ\BTS-Original,Vanilla"
Typically, I would test this by setting MapRandSeed to a specific value so I generate the same map each time, selecting the same two leaders each game and AutoPlaying to the end of a "Duel" sized balanced map on "Quick". I'd do this first on vanilla BTS 3.17 for 2 or 3 games and record the results. Then I'd open up the built colosseum versio, do the same (same map seed, same leaders and all other options) and see if the BetterAI controlled player does better against the Vanilla controlled player than it did when they were both Vanilla controlled.
Admittedly, I had to do some slight modifications to the BetterAI source before it could be used by this utility. This was because there was a method signature change in the mod that made it particularly difficult to accomodate both the Vanilla signature and the BetterAI signature in the interface class (unfortunate combination of argument default values and implicit conversion), but apart from that everything else combined without a problem.
I should also mention that destination source will not have any comments from the original mods in them, as these need to be stripped while parsing the mod source.
Limitations
I hope to address these soon, but as the first build, there are a number of useful features lacking:
- Ability to manually assign modules to player slots. I'll probably do this through a settings file.
- Automatically splice in AutoPlay component if it doesn't exist in the primary mod.
- Combine non AI classes so the primary mod doesn't have to have the superset of functionality. This is easy when methods exist in one mod and not others, but becomes difficult when existing methods have different content across mods
- Functionality to ease benchmarking. Currently, for benchmarking, you should make use of the MapRandSeed setting in CivilizationIV.ini to make sure you always test with the same starting conditions.
Even with these limitations, I hope someone finds this useful in improving the AI in their mod. There's bound to be a few corner cases of code changes that can't be combined together, but if you notify me of any problems, I'll find a fix for them.
I was hoping there would be something like Robocode that allows AI modules to compete in a single environment without human intervention. I think the advantages of something like that are obvious. Not only does it provide empirical as to which AI modules are better than others, it allows AI mod writers to test newer versions of their mods against older versions, to check if complex changes didn't make the AI worse due to some bug. This isn't so easy when all AI's in the game a driven by the same code.
So anyway, I thought I'd have a crack at creating a utility that allowed this to happen. I decided to start with the SDK first, as this is where most AI coding is done and work on Python later. My goal was to make something that allowed mods that follow the same game rules, but have different AI logic, to be combined into one CvGameCore.dll with ability for different Civs in a game started from this dll to use different AI modules (so, for e.g., if a dll is created with 2 AI mods, then a game started with that dll will have half the AI's using one module and the rest using the other). By "AI module", I refer extracting just the bits of a mod that define AI logic and packaging it into an "AI module" that can coexist with other "AI modules". Combined with AutoPlay, this would create the simulation environment I want.
Because it would ignore non AI classes, this utility would work just as well for total conversion mods, so long as the mods put the AI logic in the places where it's supposed to go.
I now have an initial version that satisfies the the requirements to a reasonable extent. I've been testing it successfully with the Better AI mod for BTS, by having "Better AI" driven Civs play against those driven by the AI shipped with BTS 3.17. This was a good test mod as all the AI changes were done in the SDK.
I was hoping there'd be other substantial AI mods out there I could test with. If anyone's got one please let me know where I can get the source.
I thought I'd put what I have so far out there hoping someone working on an AI mod would try it out to see how well their improvements are coming along and tell me if they find problems with it.
Download: Build #2
How it Works
The tool (called AIColosseum.exe) takes as input the location of the SDK source for the mods to be added to the "colosseum" and a destination path where the colosseum source will be created. The "colosseum source" is code that can be compiled to create a new CvGameCore.dll with the AI modules form each input mod crammed in there.
The architecture of the SDK is such that all AI logic should go in the Cv*AI classes (i.e. the unit AI goes in CvUnitAI class). I used this fact to make the assumption that only the content of those classes are required to construct the "AI module" for that mod. This isn't strictly true, but it's good enough to start with. For a pure AI mod, any changes that are done to other classes should be about fixing game bugs and adding utility functions to support the AI. I take the non AI classes from one mod and assume that those will be compatible with all the other mods given for the utility.
The jist of what happens is, the Cv*AI classes of the colosseum source are hollowed out and turned into abstract interfaces, with every method being virtual and their implementations stubbed out. This interface is a composite of the interfaces of each input mod (i.e. for each Cv*AI class, every method definition that is in at least one input mod gets represented in the new class). Then, for each Cv*AI class, for every input mod, a new class is created that derives from the Cv*AI class (named with the mod's name appended to the basename) and the content of this class will be the content of the Cv*AI class for that mod. Now all the tool has to do is change every location where an AI object is instantiated for a player to use the specific implementation class that is appropriate for the AI module that player is assigned to and polymorphism does the rest. There's quite a few things that must be changed for things to work after this, but that's all detail.
Most of work is actually in analysing the source classes and shifting methods around, dealing with encapsulation, statics, detecting incompatibilities, etc and because some of the classes in the SDK are tens of thousands of lines long, the utility takes a while to run.
I don't create functionality to auto run the game once it has started. I'll do that in a later version, but for now, to be able to create a "simulation environment", the primary mod (the one from which the non AI classes will be copied from) will need to have AIAutoPlay from mrgenie and jdog5000.
Normally, the game treats the human player differently than AI players. Theoretically, on Noble difficulty, there should be no difference between human and AI. Just in case, I've made it so that the first player slot (which is human by default) be treated as an AI during game setup (it has to be set back to human just before the . When running the game using AutoPlay functionality, the first slot is set to be treated as an AI, so it should be all good.
At the moment, you can't pick which Civ gets which AI module - they get automatically allocated as evenly as possible. If you create a colosseum with 3 mods, then Slot1=Mod1, Slot2=Mod2, Slot3=Mod3, Slot4=Mod1, Slot5=Mod2... and so on. Barbarians get assigned whatever mod happens to align with the slot they're in. I will make this selectable in the future too.
When the leader name is displayed on the interface during the game, the name of the module they are running will be appended (e.g. Alexander (BetterAI)), so you can tell who's who at a glance.
Usage
Simple command line usage:
AIColosseum.exe --dest=<destination path> --source=<source path>,<mod name> [...]
--dest is a folder where the colosseum code will be created. It will be created if it does not exist. NOTE: If it already exists, the source files in there will be overwritten without warning!
--source can be included multiple times, once for each input mod. The <source path> is where to find the SDK source for that mod, and <mod name> is how the module will be identified, for naming its classes and showing against the name of leaders using that module. The first source module given will be used as the "primary" module - all the non AI classes form this mod will be copied as the basis for those classes in the colosseum source. This means, even though it's ok for the input mods to have a few differences in their non AI classes, only the functionality of those classes in the first mod will be available in the colosseum, so it should contain the superset of functionality required for all mods.
The utility does not copy anything other than source code from the primary mod to the destination folder. You will need to copy Boost and Python folders, as well as makefiles over to the destination yourself to build it. There are no new files created, so you don't need to modify your makefiles.
NOTE: When starting a game, make sure you select "Noble" for difficulty of the first slot, so it isn't handicapped.
For example, to create a colosseum with the Better AI mod vs the AI shipped with BTS (which I call Vanilla) on my machine, I use:
AIColosseum.exe --dest=D:\Dev\Civ\Colosseum --source="D:\Dev\Civ\Better AI\Trunk\CvGameCoreDLL,BetterAI" --source="D:\Dev\Civ\BTS-Original,Vanilla"
Typically, I would test this by setting MapRandSeed to a specific value so I generate the same map each time, selecting the same two leaders each game and AutoPlaying to the end of a "Duel" sized balanced map on "Quick". I'd do this first on vanilla BTS 3.17 for 2 or 3 games and record the results. Then I'd open up the built colosseum versio, do the same (same map seed, same leaders and all other options) and see if the BetterAI controlled player does better against the Vanilla controlled player than it did when they were both Vanilla controlled.
Admittedly, I had to do some slight modifications to the BetterAI source before it could be used by this utility. This was because there was a method signature change in the mod that made it particularly difficult to accomodate both the Vanilla signature and the BetterAI signature in the interface class (unfortunate combination of argument default values and implicit conversion), but apart from that everything else combined without a problem.
I should also mention that destination source will not have any comments from the original mods in them, as these need to be stripped while parsing the mod source.
Limitations
I hope to address these soon, but as the first build, there are a number of useful features lacking:
- Ability to manually assign modules to player slots. I'll probably do this through a settings file.
- Automatically splice in AutoPlay component if it doesn't exist in the primary mod.
- Combine non AI classes so the primary mod doesn't have to have the superset of functionality. This is easy when methods exist in one mod and not others, but becomes difficult when existing methods have different content across mods
- Functionality to ease benchmarking. Currently, for benchmarking, you should make use of the MapRandSeed setting in CivilizationIV.ini to make sure you always test with the same starting conditions.
Even with these limitations, I hope someone finds this useful in improving the AI in their mod. There's bound to be a few corner cases of code changes that can't be combined together, but if you notify me of any problems, I'll find a fix for them.