Sign in to follow this  
Followers 0
quantumstate

AI API changes

49 posts in this topic

Since the AI API is planned to be updated I thought that creating a thread to finalize the changes that will happen. This is marked to be done as part of the Pledgie work by Philip, I would be willing to help but I think some of the planned changes (e.g. running in a separate thread) would be best done by Philip.

I would like to have the changes below for qBot, it would be good to have feedback from other AI developers especially, feedback from everyone else is welcome of course. I have tried to mention how juBot behaves where relevant to the extent of my knowledge, I don't know enough about splitBot to comment though.

Core API

I am calling the current system the core api, these changes may break current AI scripts, depending on how they are done.

Running the AI scripts in their own threads. This should improve situations on multi core systems and also stop stuttering of the game when an AI does something expensive.

Storing entity objects persistently rather than constantly recreating them. This is fairly simple and should help the garbage collector mainly (plus a little less overhead creating the objects though this should be pretty cheap). I did a quick test by modifying the current api and have attached the code. It works with JuBot (qBot does some naughty stuff) and there seemed to be some performance improvement but it was fairly minor and my setup for measuring is rather crude, I measured about a 280ms to 230ms change at 10x speed but don't take this as an accurate figure.

Persistent entity collections.

This is what I think will deliver the largest performance increase (qBot currently uses a crude version for this reason), but will require modifying AI scripts to take advantage of them. Based on my testing JuBot spends about 98% of the time filtering through entity collections. Here is my idea of how these should work:

You would create a new entity collection by filtering an existing entity collection (I think juBot does this exclusively). You would give the filter function as an argument (see filters.js in the attachment) and it would be stored as part of the entity collection. Then if you wanted to store the entity collection, you would use some sort of registerEntityCollection() function. From this point the entity collection would be maintained by the API. The filter functions of the parent would be inherited.

(more technical details, can be ignored)

The filter function may depend on a dynamic property, for efficiency I think it would be helpful for the API to be told which it depended on. So you could have player 2's idle units which would depend on the idle and owner properties. The combination of this with the Filter.js file leads to the question of how the dynamic properties would be passed to the entity collection. To keep things neat when using Filters.js putting the function and dynamic properties list into a simple object/array would keep things neat. This makes things more messy for someone making their own filter functions from scratch since they now need to wrap it in an object. I think this method is preferred though. e.g. {'func': filter_function, 'dynamic_properties': ['owner', 'idle']}

Filtering based on position presents a potential performance problem since there can be a lot of position updates every turn, I think for now it would be worth keeping thing simple and not doing anything special and see what happens, it should be able to offload it to a C++ component without any interface changes if it is a problem.

Another possible performance factor would be storing the entity collections in a hierarchy so you could avoid looking deeper in a tree for a lot of events. This should also be possible without any API changes so isn't important as a consideration currently.

(end of technical details)

Other Stuff

Here are other helpful functions that it would be nice to have an interface for in an AI. I have put them in what I think should be their priority.

Accessibility testing, can a unit reach another point on the map from where it is currently? QBot does this already but it is one of the factors causing lag at the start of games and is based on the coarse accessibility map which has caused some issues. Also qBot's version is not dynamic for performance reasons.

UnitAI state. It is nice to know whether a unit is walking, attacking, woodcutting...

Map manipulation functions see http://www.wildfireg...89 for details. Also see map.js in qBot.

Fairly low level pathfinding access or some terrain analysis functions. See terrain-analysis.js for a rough idea of what I want to be able to do. More fancy stuff would be good as well. On a basic level giving a pathfinder using a specified custom map to route over (basically adding some more inaccessible areas).

Edit 06-04-2012: Now the code is in svn

Share this post


Link to post
Share on other sites

On map manipulation functions, are you constraining your solution to just single fading spheres? Potential fields or threat hulls could offer additional benefits as one of the "types", or alternatively a blend of many influence fields.

Berkley Overmind -- the Starcraft AI -- used this approach.

Share this post


Link to post
Share on other sites

On map manipulation functions, are you constraining your solution to just single fading spheres? Potential fields or threat hulls could offer additional benefits as one of the "types", or alternatively a blend of many influence fields.

We chatted about this on irc a while back. Basically the outline above will create a potential field, non round threat hulls would be useful to have, and should be easy to add.

Also I have extended my prototype code, now I have updating entity collections working (I think, I didn't test thoroughly though). I am still a bit unsure about the interface, my function names could be improved and the grouping of filters and dynamic properties still feels a bit messy.

It almost maintains compatibility with juBot, changing line 65 of gamestate.js to

return this.ai._ownEntities;

makes it work. No performance benefit is achieved without changing lots of code though. Having ownEntities as a special case makes less sense with this new code, my new code just registers it as an updating EntityCollection and lets the standard code handle it from that point. I think it should be removed and left to individual AI's.

A usage example is:


if (!this.allWorkers){
var filter = Filters.or(Filters.byMetadata("role", "worker"), Filters.byMetadata("role", "militia"));
this.allWorkers = gameState.getOwnEntities().filter(filter);
}

Metadata updates instantly affect the entity collections. For efficiency, metadata filters use "metadata.{key}" as the dynamic property, using just "metadata" is supported and will catch all metadata changes.

Deleting metadata is unsupported currently, also saved games are broken.

Share this post


Link to post
Share on other sites

So, if I understand well, the main change will be in the way one can filter and keep entities organized?

What I missed in SplitBot

- persistance for the EntityCollections

- ability to put metadata on a building when you start to build it (like you do it when you start to produce a unit)

- an easy way to detect if a place is buildable with a given unit at a given position and orientation

- an easy way to detect if there is water between a unit and a position

What would really have helped me is an event system. To be able to give a callback and arguments in these cases:

- when you start to build an entity or produce a unit: onBuildComplete and onBuildStoped

- when you send a unit somewhere: onUnitArrived, onUnitBlocked

- when you send a unit to harvest, onStart, onUnitBlocked, onResourceEmpty, onDropResource, onResourceIsFarAway...

- ...

Just in case it is useful to you : in SplitBot have filtered the entities in this arrays and used a kind of "cache" system to compute the array only one time per tour :

I think that the "Filters.byMetadata" thing would make my life easier, would it be fast if done with a C function?

And last thing : I do not think it is necessary to have the {'func': filter_function, 'dynamic_properties': ['owner', 'idle']} argument to keep a selection up to date. It can be done by hand easily if there are events.

Share this post


Link to post
Share on other sites

So, if I understand well, the main change will be in the way one can filter and keep entities organized?

What I missed in SplitBot

- persistance for the EntityCollections

- ability to put metadata on a building when you start to build it (like you do it when you start to produce a unit)

- an easy way to detect if a place is buildable with a given unit at a given position and orientation

- an easy way to detect if there is water between a unit and a position

What would really have helped me is an event system. To be able to give a callback and arguments in these cases:

- when you start to build an entity or produce a unit: onBuildComplete and onBuildStoped

- when you send a unit somewhere: onUnitArrived, onUnitBlocked

- when you send a unit to harvest, onStart, onUnitBlocked, onResourceEmpty, onDropResource, onResourceIsFarAway...

- ...

Just in case it is useful to you : in SplitBot have filtered the entities in this arrays and used a kind of "cache" system to compute the array only one time per tour :

I think that the "Filters.byMetadata" thing would make my life easier, would it be fast if done with a C function?

And last thing : I do not think it is necessary to have the {'func': filter_function, 'dynamic_properties': ['owner', 'idle']} argument to keep a selection up to date. It can be done by hand easily if there are events.

The main thing is basically persistent entity collections, along with a group of preset filter functions which make it easy to use. This would be done in javascript initially, I think performance should be good enough. For performance though, the dynamic properties are important because without the automatic updating we are in exactly the same situation as now, and there are lots of position changes every turn so performance will be poor without filtering by dynamic property.

Metadata on buildings makes sense, I think we should do that.

The water information is linked to accessibility testing and pathfinding. It would be helpful to have, I think it would be best to leave this until Philip has finished the current pathfinding stuff and then come up with a decent AI interface for the whole section.

Buildability should be fairly easy to expose.

An event system would be a pretty big change. I currently can't see much use for it in qBot, but i haven't given it much thought. It should be possible to implement in the common-api code which would make it fairly straightforward to add, it would just run events at the start of your AI's turn.

Share this post


Link to post
Share on other sites

I find it good to have persistent entity collections, clearly

but for the "automatic updating" of entity collections, I believe that it is better to have an event system which lets you update your model (keep the collections up to date), than to have this "binding"-like functionality

just because in javascript and web languages it is much more common / standard

and as far as I'm concerned, after a long time of practicing this languages for building complex web applications, I even prefer the callback version. the addEventListener version of an event system has a good point : you can add several listener, you will not prevent a callback to be called. but the problem is that at the end, it is much harder to debug. and also, callbacks force you to have a cleaner and simpler architecture.

finally the preset filter functions should be useful. in splitbot i used a helper class to access these collection with a "cache" mechanism

public static var myEntities:EntityCollection;

public static var myPeopleUnits:EntityCollection;

public static var myBuilderUnits:EntityCollection;

public static var myBuildingStructures:EntityCollection;

public function getMyEntities():EntityCollection

public function getBuilders(entities:EntityCollection):EntityCollection

public function getWorkers():EntityCollection

public function getFondations():EntityCollection

public function getBuildings(allowedTemplateNames:Array<String> = null):EntityCollection

public function getResources(entities:EntityCollection, type:ResourceSupplyType = null):EntityCollection

Share this post


Link to post
Share on other sites

but for the "automatic updating" of entity collections, I believe that it is better to have an event system which lets you update your model (keep the collections up to date), than to have this "binding"-like functionality

just because in javascript and web languages it is much more common / standard

and as far as I'm concerned, after a long time of practicing this languages for building complex web applications, I even prefer the callback version. the addEventListener version of an event system has a good point : you can add several listener, you will not prevent a callback to be called. but the problem is that at the end, it is much harder to debug. and also, callbacks force you to have a cleaner and simpler architecture.

Sorry, I'm not quite sure what you mean by this. Could you elaborate a bit?

Share this post


Link to post
Share on other sites

Sorry, I'm not quite sure what you mean by this. Could you elaborate a bit?

You mean the event thing to update the collections?

For example, let's say you have a collection of all of your workers. Each time you build a unit, you would provide a "onBuildSuccess" callback. And in this callback, you could get the unit as a parameter. Anyway you could maintain the collection of your workers up to date in the code of the "onBuildSuccess" callbacks..

I hope I was more clear this time... unsure.gif Don't hesitate to challenge me and see if we can get something interesting before Ykkrosh starts his job :)

Share this post


Link to post
Share on other sites

I think it will be much better to have this happen automatically, rather than each AI having to implement entity collection maintenance. Putting it into the API also allows the code to be easily changed for performance improvements without having to change everyones AI scripts. Of course it is possible to create entity collections the old way and manage everything yourself.

Adding some form of notification about changes would be useful. Currently there is the array of events for this, but it is fairly limited.

The game is built on a turn based system so I think the AI's will always be restricted to a turn based system like they are now. Callbacks are still workable though. There are some things which you would need to consider though. The main thing is that the games' state will have changed by the time the callback is called so this might cause issues with specifying parameters for the callback.

Share this post


Link to post
Share on other sites

Not sure callbacks are actually needed for the AIs... There's updated often, and with a bit of tweaking, some "watcher" functions could be updated even more often.

I quite agree with the other changes though.

Share this post


Link to post
Share on other sites

The events would be called at the start of each turn. I was not thinking at something complicated like events called outside of the AI turn

The events are clearly a better way to go for me, because it is much more natural/standard and easy to use in javascript. And often I would use it without having a collection to update.

Share this post


Link to post
Share on other sites

The events are clearly a better way to go for me, because it is much more natural/standard and easy to use in javascript. And often I would use it without having a collection to update.

I would leave "event" handling up to the AIs, and make sure all the most meaningful events are provided on the chance they need to be used. But I also think unlike some other JavaScript applications, AIs shouldn't be sitting around waiting for events, but always active processing things, since they have enough to do already :) We can even provide a decent interface to poll the events. But I think there should be higher level data structures for the really useful data, like entities owned by the player or tile obstructions.

Share this post


Link to post
Share on other sites

Also a way to get the chat messages typed by users would be nice (see what i mean?)

Share this post


Link to post
Share on other sites

Also a way to get the chat messages typed by users would be nice (see what i mean?)

Indeed it would be good just as an extra option for the AI developers.

I'm interested in creating AIs, but i know little of the API and i'm not much familiar with Javascript (even though it's similar to Java). When you guys get these changes done, i'd like to see the new API and try to do anything, so please post a link on this topic to it.

Share this post


Link to post
Share on other sites

Indeed it would be good just as an extra option for the AI developers.

I'm interested in creating AIs, but i know little of the API and i'm not much familiar with Javascript (even though it's similar to Java). When you guys get these changes done, i'd like to see the new API and try to do anything, so please post a link on this topic to it.

There is some existing documentation here: http://trac.wildfiregames.com/wiki/TDD_AI , and some of the new changes are likely to be documented there. The main source will most likely be the code itself though, http://trac.wildfiregames.com/browser/ps/trunk/binaries/data/mods/public/simulation/ai and then the individual folders for the main API/individual AIs. As far as I can tell from a quick look the code is pretty well documented, so if you have at least some JavaScript knowledge it's probably best to jump right in :) Of course, given that the API will change, it might be just as well to wait a while before starting, but if nothing else you can spend the time improving your general JavaScript knowledge ;)

Share this post


Link to post
Share on other sites

Getting access to at least the "high level pathfinder" for a set of entities would be nice... Sending armies could be dealt with more easily, analyzing the map can likely be done easier with the current AI API.

(I'm thinking for example some sort of A* function that would return a path, possibly every x "cells" or at each turn.)

I forgot about the UnitAI stuff. It would really be useful, particularly to know which unit is attacking who.

Edited by wraitii

Share this post


Link to post
Share on other sites

Currently there are the "Core Api" changes and UnitAI is exposed to the AI's.

Share this post


Link to post
Share on other sites

But the first version of common-api will stay where it is now, won't it? Because I play around and try myself out on an own bot and probably need it as a school porject. So will the regular common-api stay the way it is, at least for the next half year?

Edited by Almin

Share this post


Link to post
Share on other sites

But the first version of common-api will stay where it is now, won't it? Because I play around and try myself out on an own bot and probably need it as a school porject. So will the regular common-api stay the way it is, at least for the next half year?

I have no plans to remove the old common-api. The common-api-v2 is pretty backwards compatible. I think the only breaking change is that ownEntities was removed. That is assuming that your code doesn't use nasty tricks like qBot did. Though if you only do that you don't get any of the benefits of the new API.

6 months is quite a long time though and there might be things happening like threading the AI scripts which might change some stuff, so it isn't guaranteed that the your AI won't break. Any changes should be fairly easy to cope with though.

Share this post


Link to post
Share on other sites

You can of course also use an old version of 0 A.D. for your AI development (the easiest way is probably just to have a separate SVN checkout of a specific version of 0 A.D. that's just for your AI development, and another/the release version for playing the game). It depends a bit on the objectives for the school project, and for your AI development. If you just want to try things out and play around it depends on how much time you're willing to put into it. If you might want to keep on working on it/release it for others it's definitely recommended to stay on top of the development, but if you just want to play around a bit in the short term using a specific, unchanging, version of the AI API is probably easier. For a school project that may even be required, to make it easier for the teachers to follow it if nothing else, but on the other hand it's more realistic to have to be able to keep up with changing APIs, so hopefully it could work either way. (Also, Jonathan et al are after all not going to change things "just because"/to make things harder, so hopefully the improvements will even make further development easier, and should be worth staying on top of :) )

Share this post


Link to post
Share on other sites

Thanks, both of you. Can anyone tell me whether JuBot is still maintained, as I used it's gamestate, or shall I rather switch to the gamestate of qbot instead?

Share this post


Link to post
Share on other sites

JuBot is not being maintained very actively. It is likely to be kept compatible with the game for a while but the main author Jubal hasn't been around for a while and I don't know of anyone else interested in working on it.

The qBot gamestate is likely to change in the near future as I do more work to convert to the new api. If you want to switch to the new api it would be good to switch, otherwise it probably won't be of much benefit.

Share this post


Link to post
Share on other sites

Thank you very much, quantumstate! I switched to your gamestate and common-api-vs2 and it works! For the case that you didn't know it until now: You're awesome! Keep up the good work!

by the way: Nice new avatar-picture of yours!

Edited by Almin

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0