Mini-engine progress

It's good to see that the obstacles seem to get smaller by time. It's no longer graphics, just 3D graphics, and that doesn't need to be done from scratch. I hope that this tendency continues 🙂

A very far off question:
Does it seem possible to train Civ4 AI with machine learning? I know StarCraft2 does it and IIRC FreeCiv too.

I just asked ChatGPT about it and gave a very interesting summary. To my surprise it specifically mentioned Civilization 😅
Spoiler If you are interested... :
Yes! Some strategy games have experimented with AI that learns and improves by playing against human players. While they may not use large language models (LLMs) specifically, they often leverage machine learning, neural networks, or reinforcement learning. Here are some notable examples:

1. AlphaStar (StarCraft II - DeepMind)

Developed by DeepMind, AlphaStar was trained using reinforcement learning and supervised learning from human matches.

It reached Grandmaster level in StarCraft II by learning from human replays and playing against itself.


2. OpenAI Five (Dota 2)

A machine learning AI that trained by playing millions of matches against itself.

It surpassed top human players and even defeated professional teams.


3. Tesseract AI (Company of Heroes 3)

Uses machine learning to analyze human strategies and improve AI behavior dynamically.

The AI adapts to playstyles rather than using static pre-programmed strategies.


4. Total War: Arena & Creative Assembly Experiments

Creative Assembly has experimented with reinforcement learning for Total War AI.

AI can learn from past battles and adjust tactics over time.


5. Mini-AlphaGo (Go & Turn-Based Games)

Inspired by AlphaGo, some AI in turn-based games like Go or Chess continues to evolve by learning from human play.


6. AI in Online Strategy Games

Games like Clash of Clans and other competitive mobile strategy games use AI that adjusts defensive strategies based on previous attacks.

Some MOBA bots (like in League of Legends) use AI to learn player movements and improve over time.


Challenges of Learning AIs in Strategy Games

Balance Issues: AI that learns too fast can become unbeatable or exploit mechanics.

Computational Cost: Running complex learning algorithms in real-time is demanding.

Unpredictability: AI that adapts too much might lead to broken or frustrating gameplay.


Future of AI in Strategy Games

We might see AI generals in RTS games that develop unique tactics based on past games.

AI could personalize difficulty in 4X games like Civilization based on your playstyle.

Future strategy games could feature AI that mimics human-like strategic thinking instead of following pre-set patterns.


 
Does it seem possible to train Civ4 AI with machine learning?
Since the AI is in the DLL, the answer is yes. The question is how much work it would be. We can set up interprocess communication hooks to let an external process gain access to the game data and send commands like move unit X to plot Y. It would likely be a massive undertaking to get it up and running through and that's before even starting to make an external AI to act on it. It's possible that there are other ways to do it too, but placing the AI in another process means we get rid of all compiler restrictions, which may be of benefit in case of AI as they seem to need the newest stuff.

In short it's possible in theory, but it's not something I would expect to see soon. It could be a project of the same size as making a new exe.
 
Bad news. I investigated Sugar Bomb Engine as it's an open source engine based on GameBryo. Looking through the source I found this.
PHP:
    else if(extension.Icmp("nif") == 0)
    {
        mpSys->Warning("idRenderModelStatic::InitFromFile: NIF models are not yet supported!: \'%s\'", name.c_str());
        //loaded = LoadNIF( name );
        loaded = false;
        reloadable = true;
    }
Any other ideas where we might be able to find information on how to decode the nif files?
 
Bad news. I investigated Sugar Bomb Engine as it's an open source engine based on GameBryo. Looking through the source I found this.
PHP:
    else if(extension.Icmp("nif") == 0)
    {
        mpSys->Warning("idRenderModelStatic::InitFromFile: NIF models are not yet supported!: \'%s\'", name.c_str());
        //loaded = LoadNIF( name );
        loaded = false;
        reloadable = true;
    }
Any other ideas where we might be able to find information on how to decode the nif files?


Nif Tools perhaps? I can't speak to anything related to editing them, but from other games running the same engine, this seems to be the standard tools to edit them. But that's just my impression from an evening's googling.
 
Nif Tools perhaps? I can't speak to anything related to editing them, but from other games running the same engine, this seems to be the standard tools to edit them. But that's just my impression from an evening's googling.
I'm no expert but as I understand what needed is not an EDITOR but an ENGINE.
Maybe this isn't the best illustration but... Thinking of a car what we need is not someone who can paint fancy flames or skulls or butterflies on the chassis of our car. Rather we need someone who can build the whole chassis (or rather already has a complete spare one) into which we can put our new motor.
 
I'm no expert but as I understand what needed is not an EDITOR but an ENGINE.
What we need is code, which can convert NIF into something understood by Godot (or some other engine). Having the source code for some editor, which can read/write the NIF format is a whole lot better than no code at all. It's not copy paste, but I never imagined we would find code, which is completely copy paste.
 
lurker's comment:
I don't think I've seen anyone do a 'Civ like' in it yet but am keeping an eye out for one as I'm sure there's already something out there not discovered yet
I see you haven't been hanging out in the Civ3 C&C space a whole lot recently. There has been a slow-and-not-all-that-steady (but moving again) effort in that direction, using Godot, over the past three-plus years. The announcement thread is here and the latest release thread is here.

I was involved with it a good amount for the first year-plus. Although WildWeazel had used Unity a bit, none of us were game programmers, just regular programmers. But Godot was a pleasure to work with, even in its prior iteration (Godot 3). We chose to use C# because it was the common language that those of us who started it shared, and with Civ III as our base goal, there were no DLL interoperability concerns - but my understanding is you can mix C++, C#, and GodotScript. One of the benefits of using C# is that for the parts that are logic-focused (versus graphics focused) you can use JetBrains Rider as your IDE, which is much more powerful than the Godot editor for code-heavy areas. You could likely use JetBrains' CLion if you went C++, although we had some challenges getting Visual Studio (full, not VSCode) to play nicely with Godot and C# a couple years ago when we tried that. That may have improved since then.

We wrote our own code to read Civ3 legacy file formats and convert the into formats that Godot understands natively. We also didn't take advantage of all the built-in features Godot has, due to not being game programmers and being unaware that it supports things like game loops natively, so we probably did things more the hard way than we needed to. Cross-platform and building has been good, it's possible to build for Mac/Linux/Windows from one PC, and there haven't been too many platform-specific issues to iron out.

I'd encourage those looking at the mini-engine for IV who also own III (or can pick it up cheaply on Steam/GOG) to try out what we've done as an example of it being used in a Civ-like, albeit an isometric one rather than a 3D one. You can have various layers, you can have modals (we did that the hard way initially, due to lack of knowledge), and we don't have regrets about choosing it.
 
lurker's comment:

I see you haven't been hanging out in the Civ3 C&C space a whole lot recently. There has been a slow-and-not-all-that-steady (but moving again) effort in that direction, using Godot, over the past three-plus years. The announcement thread is here and the latest release thread is here.

I was involved with it a good amount for the first year-plus. Although WildWeazel had used Unity a bit, none of us were game programmers, just regular programmers. But Godot was a pleasure to work with, even in its prior iteration (Godot 3). We chose to use C# because it was the common language that those of us who started it shared, and with Civ III as our base goal, there were no DLL interoperability concerns - but my understanding is you can mix C++, C#, and GodotScript. One of the benefits of using C# is that for the parts that are logic-focused (versus graphics focused) you can use JetBrains Rider as your IDE, which is much more powerful than the Godot editor for code-heavy areas. You could likely use JetBrains' CLion if you went C++, although we had some challenges getting Visual Studio (full, not VSCode) to play nicely with Godot and C# a couple years ago when we tried that. That may have improved since then.

We wrote our own code to read Civ3 legacy file formats and convert the into formats that Godot understands natively. We also didn't take advantage of all the built-in features Godot has, due to not being game programmers and being unaware that it supports things like game loops natively, so we probably did things more the hard way than we needed to. Cross-platform and building has been good, it's possible to build for Mac/Linux/Windows from one PC, and there haven't been too many platform-specific issues to iron out.

I'd encourage those looking at the mini-engine for IV who also own III (or can pick it up cheaply on Steam/GOG) to try out what we've done as an example of it being used in a Civ-like, albeit an isometric one rather than a 3D one. You can have various layers, you can have modals (we did that the hard way initially, due to lack of knowledge), and we don't have regrets about choosing it.
Hah that's funny, despite admittedly not hanging out there lately (I miss the Civ3 area but am very focussed atm on finishing my final Civ2 mods, so that I can get to playing more Civ3 mods sooner than later), I actually did think to check if C7 was using Godot these days before making that post and had a quick look but must have ended up in an old thread or missed the text mentioning it lol, doh! I should have messaged you and @WildWeazel about this to double check and then see if you had any advice too. That's great to hear you Civ3 C7 guys have switched over to Godot and have literally gone through the kind of challenges the Civ4 crew are facing, please keep up with the lurking here. ;)

EDIT: I see Suede has done a recent video on your work too!

 
Last edited:
Wow, this is neat. I'm still going through the thread to grok what's happening here, but I echo everything @Dale said above regarding Godot and the use of a game engine. It provides all those things you need at a higher level of abstraction so you can focus on the game logic and assets. As mentioned none of us were even game developers to start with but we've done just fine, even without knowing enough to take full advantage of what Godot offers.
 
As mentioned none of us were even game developers to start with but we've done just fine, even without knowing enough to take full advantage of what Godot offers.
This is the thing. Generally speaking, games don't use everything a game engine offers. Sometimes it's because of developers not being skilled enough and sometimes it's just because the game doesn't actually need that like single player games doesn't really need network support. The question you need to ask is if you can make what you need with the subset of the engine you plan to use rather than how you can use everything in the engine to do something to your game, planned feature or not.

Sure it's plausible to add some new feature to make use of some engine feature, but that's really an extension to an existing game rather than planning it prior to writing the first line of code. I can imagine something like adding the ability to modify 3D models on the fly, like having ships, which change flags according to owner without having to make a model for each CivilizationTypes.

It provides all those things you need at a higher level of abstraction so you can focus on the game logic and assets.
And this is the main thing. We don't need to develop a game. Most of the game logic is in the DLL, so what we do need to do is to make a bridge between the DLL and a game engine. We then come back to converting vanilla assets into Godot compatible files. We don't even need to implement the game loop because that's (mostly) CvGame::update().

I see Suede has done a recent video n your work too!
This video points out the ability to unlock more modding options. We have some of those through the DLL and/or python, but with an open source exe, we can open up for way more options. Orbit/satellite map layer like in Call to power 1, Subterranean map layer. The options are endless if we aren't as restricted on the engine level.
 
This video points out the ability to unlock more modding options. We have some of those through the DLL and/or python, but with an open source exe, we can open up for way more options. Orbit/satellite map layer like in Call to power 1, Subterranean map layer. The options are endless if we aren't as restricted on the engine level.
Yeah indeed multiple links map layers like in Civilization 2 Test of Time (+ Master of Magic, Heroes of Might & Magic, Warlock, Age of Wonders & the other examples you gave) is probably my number 1 wishlist item the Civ3 C7 project and I think I mentioned it earlier in this thread for this Civ4 project too! :)

It suffered greatly in Test of Time due to Civ2's 7 player limit so it would work so much better in Civ3 and Civ4. And as you say the applications and creative ideas that can come from the modding community once available to them are endless!

For example Test of Time came with a Midgard fantasy scenario with 4 linked worlds: underworld caves/dungeons/lava world with a globlin race, under sea with a merfolk race, surface fantasy forest world with humans/elves/barbarians/undead, and lastly a sky world with a bird people.
1739947559848.png

And it came with a scifi scenario with 4 linked worlds: an earth like alien world colonised by human and alien factions who work their way to orbital space flight techs, eventually you reach a space layer map with orbital platforms that unlock techs and equipment that open portals to the rest of the solar system such as a dark dusty glowing mining planet and then sky platforms in the clouds of a gas giant where giant alien machines lurk.
1739947864931.png

Fans of course took this tech and did all sorts of cool stuff eg..

Kestrel did an enhanced version of the famous Mars Now scenario with a underground level where you can use diggers to make passages between caves and build cities (reminding me of the old game Outpost) and then you could eventually fly back and invade a post apocalyptic earth map with it's own underground level. Just imagine @The_J 's Civ4 Mars Now with a underground layer added on.
SMarsNOW.png

Dadais did a Skyrim scenario with a overworld and underworld map with all the caves and dungeons linked to their surface entrances.
SSkyrim01.png SSkyrim02.png

And probably the craziest idea I've seen is Prof Garfield and JPetrowski using the multi world system and some clever LUA coding to make a World War 2 scenario where you build Civ6-7 like external city buildings on the main daytime map but there's a linked second nighttime strategic bombing map that updates based on whatever is built in the daytime map and bombers can destroy buildings at night (where there's no cloud cover) which will then show as rubble on the daytime map.
SOverTheReich1.png SOverTheReich2.png

So yeah if crazy stuff like that can be done in Civ2's ancient engine, I can only imagine what sorts of awesome crazy things could be done in Civ3 and Civ4 if a multi world system was added to the fan rebuilds! :)

.
 
Last edited:
Does it seem possible to train Civ4 AI with machine learning? I know StarCraft2 does it and IIRC FreeCiv too.

Going by https://pythonprogramming.net/starcraft-ii-ai-python-sc2-tutorial/, what you'd do is create an environment in python that makes it easy to write an AI. A learning environment. Python 3 I would hope. It would probably be a headless engine exposing some way to control the human player. You'd then write a rule-based AI. Then, replace the decisions with something like deep reinforcement learning, neural networks, CNNs...

Importantly, if you do Machine Learning, you'll want a FAST engine. But on the plus side, you don't need to care about multithreading as you'd just run N games in parallel.

It may also be possible to use MILPs to solve for truly optimal play of some subset of mechanics. Like, maximise the amount of research you can get from an isolated start (don't need to handle AI). But MILP solvers aren't quite there yet. The HiGHS solver is pretty good, but it's single-threaded at the moment. They should be adding parallel solving soon, and that's when it should get really good. Now, if you were really creative, you might be able to craft a custom branch-and-bound algorithm that also minimises the redundant symmetric states. One would hope that would be even faster, in theory, but it's tough to beat MILP solvers. There's also other tactics like decomposing the problem into N-turn blocks, but I wasn't able to make that fast.

Nif Tools perhaps? I can't speak to anything related to editing them, but from other games running the same engine, this seems to be the standard tools to edit them. But that's just my impression from an evening's googling.
Yes, loading NIFs is a solved problem. Should be easy as pie.

Anyway. An actual progress this time. A milestone. Path verification is working, or at least appears to work. Turn 209 of a 1040x640 map:

Code:
FAStar for Barbarian Worker start=[286, 150] goal=[669, 155] result=1 flags=0 numUnits=1 domain=2 1687ms
Generating path 1486 from { [286, 150] with Barbarian Worker } to { [669, 155] } with maxTurns 2147483647
Vectorised path finder took 808.243ms
Path cost matches.
CmdCiv4 log Info void __cdecl MyCvDLLEngineIFace::AutoSave(bool):
Pathfinder reset.
FAStar for Fluffy Warrior start=[690, 69] goal=[690, 68] result=1 flags=4 numUnits=1 domain=2 4.1201ms
Pathfinder reset.
Performed 6 game updates in 45.8825s.

That is full verification. Checks the path cost of the final path, and checks pathCost+pathValid for each step in A*. That's why the vectorised pathfinder is so slow here.

There's still a chance though that there's some higher level bug somewhere causing different paths to be requested. But the way this works is that all unit pathing requests are passed to an internal FAStar instance if verification is enabled or my pathfinder won't handle it yet. So that's at least minimising the chance of such bugs.

Turning off step verification:

Code:
FAStar for Barbarian Worker start=[285, 149] goal=[669, 155] result=1 flags=0 numUnits=1 domain=2 1587.21ms
Generating path 1485 from { [285, 149] with Barbarian Worker } to { [669, 155] } with maxTurns 2147483647
Vectorised path finder took 5.2291ms
Path cost matches.
Pathfinder reset.
FAStar for Barbarian Worker start=[286, 150] goal=[669, 155] result=1 flags=0 numUnits=1 domain=2 1566.69ms
Generating path 1486 from { [286, 150] with Barbarian Worker } to { [669, 155] } with maxTurns 2147483647
Vectorised path finder took 5.402ms
Path cost matches.
CmdCiv4 log Info void __cdecl MyCvDLLEngineIFace::AutoSave(bool):
Pathfinder reset.
FAStar for Fluffy Warrior start=[690, 69] goal=[690, 68] result=1 flags=4 numUnits=1 domain=2 4.1857ms
Pathfinder reset.
Performed 6 game updates in 37.9029s.

Here's a long path, which goes across the map:

Code:
Pathfinder reset.
FAStar for Barbarian Warrior start=[921, 270] goal=[350, 194] result=1 flags=0 numUnits=1 domain=2 471.223ms
Generating path 1254 from { [921, 270] with Barbarian Warrior } to { [350, 194] city of Carib with Barbarian Warrior } with maxTurns 1
Vectorised path finder took 0.0026ms
FAStar for Barbarian Warrior start=[921, 270] goal=[261, 199] result=1 flags=0 numUnits=1 domain=2 102.758ms
Generating path 1255 from { [921, 270] with Barbarian Warrior } to { [261, 199] city of Tiwanaku with Huayna Capac Archer } with maxTurns 2147483647
Vectorised path finder took 25.4883ms
Path cost matches.

So, 26ms for the longest path. It's okay. Alright. Not as fast as I would like. But I could make it faster if I wanted to by using Block A* without an LDDB, which is actually feasible, but the internal data layout is more complex.

Turn time is ~2.8s with no verification. With 4K barbs running around. Five workers. Some of them are probably building intercontinental barbarian highways.

Current restrictions: Land units only, no unit stacks, AI only.

Landmark locations are computed at startup in ~180ms. This could be done in the background. Landmark distance (cost) fields are computed on-demand, in a background task.

There is a landmark heuristic instance for each "movement type". Combination of: unit MP, movement promotions, team route cost changes.

And a landmark heuristic is optional. It can be computed in parallel, and when it isn't available yet, the pathfinder can just use no heuristic.

The downside of parallel landmark updates is the possibility of non-deterministic pathfinding. This is unlikely as the pathfinder does not use "parent pointers", and only relies on a distance field for path reconstruction, but could still happen if through some fluke of pathing, a plot gets the same path cost with a different number of movement points. This could probably be mitigated by taking the minimum movement points for equal path costs within the pathfinder, or by making landmark updates deterministic.

The heuristic can also be updated by local changes. If a plot changes, you can compute the maximum path cost reduction going through that plot, and subtract it from the heuristic. And I hope that's correct! Then you can have some threshold where you launch another landmark distance field computation task. So in the end, maintaining the landmark distance field has little cost.

Also, to feed the vectorised pathfinder, everything that affects pathCost and pathValid is complied into a per-team bitmap, which is masked by the unit and pathing flags. Thus, calculating pathValid is just a few SIMD instructions, in comparison to the expensive 9x9 loop inside AI_getPlotDanger. So that means there's also a cache for plot danger. It has a lot of dependencies on various pieces of game state, but it's handleable.

Now, I need to ensure that all the caches get all the game state change events they need, and test with verification on a more typically sized map.

*Ah, yes, use AI autoplay! Capital idea.

*Oh. Turn 46 of a more typical map: A* costs inconsistency. Parent gets improved cost, but because of unit movement points, the adjacent plot gets a worse cost. So even the path costs depend on visit order. And that's why, I guess, FAStar will update descendants of a node, and why https://github.com/karadoc/Civ4-K-M...5d86608/CvGameCoreDLL/KmodPathFinder.cpp#L451 exists. This makes costs depend on visit order, and thus the heuristic, and so hurts determinism and path verification. The True solution is 3D path coords, but that would be silly for performance. Or change the step cost function.

*Changed path cost verification to only abort if final unit turn/movement points is different.

*Found value cache verification + path verification for a 64x40 map successful. Turn 11 to turn 458 using AI autoplay, debug build, took half an hour.
The found value cache is the other piece of complex machinery. Very bug-prone. I would like to replace the found value cache with another highly optimised cache-friendly SIMD implementation, but I'm not sure if it would be fast. And there's a couple of divisions that SIMD can't do natively. Would be nice if the whole-map loop in AI_updateFoundValues could be done in 1ms per player assuming all your locally updateable values are up to date.

*1040x640 map from turn 209 to turn 243 verified. Very slow!
 
Last edited:
Back
Top Bottom