wraitii Posted May 6, 2019 Report Share Posted May 6, 2019 Just had this idea, and I think it's good, so I wanted to share this... Current situation As you may know, the AI is currently designed to ultimately be run in an asynchronous manner, in the background, over possibly n turns. A reference is this interview of @quantumstate for example, but it's also quite obvious from the architecture. The Idea was that thus the AI wouldn't be blocking for the simulation even if it was slow. Based on the fact it currently runs once per 8 in-game turn (about 1.5 seconds in SP, about 4 seconds in MP), we can assume that this is a reasonable time-frame for such a threaded AI. To support this, the AI receives a copy of the simulation state, through AI Proxy components on most entities and AI Interface. Consequences This is nice in theory - I've never questioned it and I don't think anyone questioned it in the past few years. However it has several significant drawbacks: The AI wouldn't be able to be run more than once every n turns (n=8 right now). That makes it basically impossible-by-design to micro efficiently, for example. Note that our synchronous AI can, but that's not how it should work (and it doesn't leverage that). Copying the simulation state is slow. AIProxy listens to most messages, all entities have one. It can easily take up several ms per turn (in fact I had a diff for that which I didn't keep as it was kinda broken.). Copying the simulation state is error prone. We have to do it manually. Techs in particular were a real pain to handle. Mitigations for multiple AIs (the common-API) are a mess. Copying the simulation state is greedy and custom. If the AI wants new information, we have to add it to its state. If it doesn't care about some information that we've added, we've payed the price anyways. The above flaws are all fundamental to the design. The second and first can be mitigated, but at great cost, and only up to a point. Proposed Change The biggest change is simple conceptually: we run the AI synchronously. It fixes all the fundamental design flaws above: we can run it every turn if we want to. This fixes point 1. we no longer need a copy of the whole simulation state. This fixes points 2/3/4. The AI can call into the Engine directly (using QueryInterface or something similar) - in a read-only manner. This can be by setting a flag or by copying only that relevant bit of data it's asking for. If the AI remains in its own context, we can use structured clones. The problem of this design is that if the AI wants to do something slow (and it does sometimes), it will lag. There is a solution. We let the AI run specific computations asynchronously, over a specific number of turns, using an interface similar to worker threads. Then if the computation isn't done, we block, otherwise we return the result and process it synchronously and deterministically. For these computations only, we copy whatever state is necessary. What I hope this achieves A speed-up of several ms per turn on both SP and MP. A much simpler AI interface (basically no interface). Still the ability to run longer computations asynchronously. 2 2 Quote Link to comment Share on other sites More sharing options...
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.