Jump to content

AI API changes


Recommended Posts

Here is an example of how to use the new API. The new API is almost completely backwards compatible with the old one with the only breaking change being the removal of ownEntities.


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

When filtering from an existing entity collection the new collection will inherit the filters of the parent.

This will make this.allWorkers contain an entity collection of all units with a role of either worker or militia which will be efficiently updated. For the updating collections to work you should use the filters provided by Filters.

The special ownEntities case has been removed since this is easily implemented using Filters.byOwner.

qBot's gamestate.js gives examples of how this new system could be used

Link to comment
Share on other sites

I'm really wondering how much I should update Marilyn with the new persistent entityCollection system... It seems to rely on basically the same principle as my "unitInfoManager" (keeping track of units and adding/removing them as they appear/die). Did you do any specific optimization? I might just use it for the enemy and the attack plans/ "micromanager" managers which I plan to implement.

Link to comment
Share on other sites

I don't know, whether that's a bug or a feature, but you are aware of gameState.countFoundationsWithType(type) giving back the number of the foundations +1? Is this behavior intented? And just because I'm a little bit confused, this function returns only the number of foundation as not finished buildings. It does NOT include the number of buildings of the same type, which are already finished, does it?

Link to comment
Share on other sites

what do you think about adding a couple of external interface functions to UnitAI.js to let the entity object know which entity it is attacking and which are attacking it?

to enable something like this:

entity.underAttackByEntities() that returns an array with the ids of the entity attacking it

and

entity.attackingEntity() that returns the id of the entity that it it is trying to attack

this would make it a lot easier to develop any kind of morale system

Link to comment
Share on other sites

I've gotten a bug with the "Gamestate.getentitybiID" function as used by qBot... Apparently, you changed something, and now the Entity function wants to access "entity.template" when, in that case, it should access "entity._template._parent", unless I'm mistaken... Any information?

Link to comment
Share on other sites

I don't know, whether that's a bug or a feature, but you are aware of gameState.countFoundationsWithType(type) giving back the number of the foundations +1? Is this behavior intented? And just because I'm a little bit confused, this function returns only the number of foundation as not finished buildings. It does NOT include the number of buildings of the same type, which are already finished, does it?

Returning the number of foundations +1 is not intended, however I am looking at the function and it looks fine to me.

[b]GameState.prototype.countFoundationsWithType = function(type) {
var foundationType = "foundation|" + type;
var count = 0;
this.getOwnEntities().forEach(function(ent) {
var t = ent.templateName();
if (t == foundationType)
++count;
});
return count;
};[/b]

It is just meant to count the number of in progress foundations.

Link to comment
Share on other sites

Confirmed: you have introduced a bug between qBot and the common-api-v2: the gamestate GetEntityById function no longer works: this is because when creating an entity, it tries to access "entity.template", when it should try to access "entity.templateName" in that particular case (I think the other cases work properly).

Link to comment
Share on other sites

what do you think about adding a couple of external interface functions to UnitAI.js to let the entity object know which entity it is attacking and which are attacking it?

to enable something like this:

entity.underAttackByEntities() that returns an array with the ids of the entity attacking it

and

entity.attackingEntity() that returns the id of the entity that it it is trying to attack

This information is basically available to the AI. There are two different concepts of a unit attacking.

The UnitAI controls each unit, and is now exposed to the AI's, so you should be able to use a combination of UnitAIState and UnitAIOrderData to work out what target a unit is attacking or trying to attack. You can read simulation/components/UnitAI.js for details. This won't tell you directly which units are attacking a unit, this information isn't stored by the game, but you could construct it yourself.

Secondly there is a set of events sent each turn to the AI's, this is found in this.events if you are inheriting from the baseAI and contains a new set of events every time OnUpdate() is called. This will have an event for every time one unit does damage to another in an attack. You would again need to do some manipulation to get this information into the form you want.

Confirmed: you have introduced a bug between qBot and the common-api-v2: the gamestate GetEntityById function no longer works: this is because when creating an entity, it tries to access "entity.template", when it should try to access "entity.templateName" in that particular case (I think the other cases work properly).

Thanks, I have fixed this now.

Edit:

I'm really wondering how much I should update Marilyn with the new persistent entityCollection system... It seems to rely on basically the same principle as my "unitInfoManager" (keeping track of units and adding/removing them as they appear/die). Did you do any specific optimization? I might just use it for the enemy and the attack plans/ "micromanager" managers which I plan to implement.

The updating entity collections handle updates to properties, not just unit creation/death, this will be especially important when we have unit conversion happening since most of the time you filter by owner. There isn't an real optimization currently, but if it runs too slowly then I was thinking of adding a hierarchical system to help with filtering.

Link to comment
Share on other sites

I'm not sure if morale would be an efficient system for an AI to use; what I'm working on is a system whereby it can run at the start of a battle, but if it commits it commits. Running away mid-battle is likely to lead to heavier losses for less gain/pain on the part of the enemy. Morale-based retreats happen in real life where people don't want to die; the AI has no such considerations really, it cares about whether its losses are efficient but not the life of any individual trooper.

(This is incidentally why apparently, when a team of computer gamers controlled the enemy in a war-simulation to train US officer staff, the gamers won by miles. The US officers, trained to fight a real war, were careful to avoid un-necessary losses. The gamers, only used to playing games where efficiency trumps loss of life, happily ran some of their best squads in on a suicide mission, losing most of their best fighters but managing to destroy all the US supply bases and thus effectively winning the war as their opponents had no supply lines).

Link to comment
Share on other sites

(This is incidentally why apparently, when a team of computer gamers controlled the enemy in a war-simulation to train US officer staff, the gamers won by miles. The US officers, trained to fight a real war, were careful to avoid un-necessary losses. The gamers, only used to playing games where efficiency trumps loss of life, happily ran some of their best squads in on a suicide mission, losing most of their best fighters but managing to destroy all the US supply bases and thus effectively winning the war as their opponents had no supply lines).

It's amazing what you can do when your soldiers have no fear of death.
Link to comment
Share on other sites

I'm not sure if morale would be an efficient system for an AI to use; what I'm working on is a system whereby it can run at the start of a battle, but if it commits it commits. Running away mid-battle is likely to lead to heavier losses for less gain/pain on the part of the enemy. Morale-based retreats happen in real life where people don't want to die; the AI has no such considerations really, it cares about whether its losses are efficient but not the life of any individual trooper.

(This is incidentally why apparently, when a team of computer gamers controlled the enemy in a war-simulation to train US officer staff, the gamers won by miles. The US officers, trained to fight a real war, were careful to avoid un-necessary losses. The gamers, only used to playing games where efficiency trumps loss of life, happily ran some of their best squads in on a suicide mission, losing most of their best fighters but managing to destroy all the US supply bases and thus effectively winning the war as their opponents had no supply lines).

In my AI I've tried a very simple approach (mainly to test how efficient my agent system was), making units escape a fight if engaged in an unfair fight (by number of enemy units) or if severely injured.

The agent's plan was to escape into a safe location like a base, a tower or a regroup point with another group of units.

In all the tests I did once the units escaped a difficult fight with minimal losses and their retreat to buildings or friendly units not only scattered my army but also turned the fight in their favour.

What you are saying may be right in a clean contest where no other factors come into play, but in a game like this, where you can exploit buildings and movement, I think it could work.

Link to comment
Share on other sites

Thanks for the answer Quantumstate... I guess I'll have to copy the code in a modified way for my unit/building managers, but i'll use entitycollections for the enemyWatchers.

Retreat must be dealt with for small raids if you want to keep the army... For anything else, unless a specific unit must be preserved, it can be overlooked, I think.

Link to comment
Share on other sites

I suggest, in entity.js, replacing the "ressourceSupplyAmount" and "RessourceCarrying" function by those, who check whether those parameters are defined:

	resourceSupplyAmount: function() {
if(this._entity.resourceSupplyAmount == undefined)
return undefined;
return this._entity.resourceSupplyAmount;
},

resourceCarrying: function() {
if(this._entity.resourceCarrying == undefined)
return undefined;
return this._entity.resourceCarrying;
},

Link to comment
Share on other sites

I suggest, in entity.js, replacing the "ressourceSupplyAmount" and "RessourceCarrying" function by those, who check whether those parameters are defined:

	resourceSupplyAmount: function() {
if(this._entity.resourceSupplyAmount == undefined)
return undefined;
return this._entity.resourceSupplyAmount;
},

resourceCarrying: function() {
if(this._entity.resourceCarrying == undefined)
return undefined;
return this._entity.resourceCarrying;
},

You have used a weak equality check so null, 0, ""and false will be changed to undefined, is that intentional and why would you want that to happen? If it wasn't intentional then you have basically inserted a null operation (though from a quick search we do seem to have some of these checks in the entity.js file already).

Link to comment
Share on other sites

Mh, no, actually, should either be === "undefined" or === undefined, not sure which one works.

I did that because if it is undefined, it will send a warning. It's not a huge problem ,I think it still works properly, but it can be a bit baffling.

Edited by wraitii
Link to comment
Share on other sites

Mh, no, actually, should either be === "undefined" or === undefined, not sure which one works.

I did that because if it is undefined, it will send a warning. It's not a huge problem ,I think it still works properly, but it can be a bit baffling.

Interesting, I didn't think that would happen but it does as you say. I will make the changes you suggest. It is === undefined.

Edit: I also think I have introduced a save/load bug with the new api, I will try and get this fixed soon.

Link to comment
Share on other sites

Hi Quantumstate... A few more questions about the API.

First, I'd recommend adding the "NOT" filter. It can be useful to check something like "Not a worker".

Filters["not"] = 
function(filter1){
return {"func": function(ent){
return !filter1.func(ent);
},
"dynamicProperties": filter1.dynamicProperties};
};

Secondly: you give every entity collection a "this._ai" property... It works as a reference and not as a copy, right? Javascript is messing with my brain about those things.

Third: I sometimes get a "length NAN" error with entity collections if I don't ask for the length immediately after the entityCollection's creation. I guess that's an initialization error somewhere.

Finally, and this is perhaps more of a general question, it seems that after some times, using a lot of entity collections, I get a "out of memory" error in GUI/sessio.js, in an (eval) or something... It doesn't always happen, and judging from the profiler, the AI script doesn't seem to overload. And there is no following crash. Any idea what this error is?

edit: oh, and any ETA on AI support for technologies?

Edited by wraitii
Link to comment
Share on other sites

Hi Quantumstate... A few more questions about the API.

First, I'd recommend adding the "NOT" filter. It can be useful to check something like "Not a worker".

Thanks I added this.

Secondly: you give every entity collection a "this._ai" property... It works as a reference and not as a copy, right? Javascript is messing with my brain about those things.

Yes, all assignments with objects or array in javascript are by reference.

Third: I sometimes get a "length NAN" error with entity collections if I don't ask for the length immediately after the entityCollection's creation. I guess that's an initialization error somewhere.

Thanks, I have fixed this. It happened when the entity collection had a unit added or removed before the length was requested. Trying to increment or decrement 'undefined' is a bad idea.

Finally, and this is perhaps more of a general question, it seems that after some times, using a lot of entity collections, I get a "out of memory" error in GUI/sessio.js, in an (eval) or something... It doesn't always happen, and judging from the profiler, the AI script doesn't seem to overload. And there is no following crash. Any idea what this error is?

Out of memory is a nasty one to debug, currently there isn't a good way I know to debug them. One that I came across before which hit some GUI javascript was a mismatched profiler start/stop which lead to the profiler tree continuously growing.

edit: oh, and any ETA on AI support for technologies?

Not currently, I am fairly busy at the moment. I also don't know quite how ti will be implemented.

Link to comment
Share on other sites

Yes, all assignments with objects or array in javascript are by reference.

Good to know, thanks!

Out of memory is a nasty one to debug, currently there isn't a good way I know to debug them. One that I came across before which hit some GUI javascript was a mismatched profiler start/stop which lead to the profiler tree continuously growing.

Allright, I'll keep watching.

No problem about the technologies, take all the time you need, better done well than rushed.

Another thing about the API: I see you use "VectorDistance" for "ByDistance" filtering... I've done checks in the past, and at least on my computer (but I'd expect on most), it was faster using SquareVectorDistance, even with the added multiplying (though by very little). Since afaik this will trigger for every position change for every entity in any entitycollection that requires it, I think it could be a, however little, welcome addition (if for some reason, one comes to do it 1000 times per turn in some extreme cases, it could make a difference).

Link to comment
Share on other sites

Another thing about the API: I see you use "VectorDistance" for "ByDistance" filtering... I've done checks in the past, and at least on my computer (but I'd expect on most), it was faster using SquareVectorDistance, even with the added multiplying (though by very little). Since afaik this will trigger for every position change for every entity in any entitycollection that requires it, I think it could be a, however little, welcome addition (if for some reason, one comes to do it 1000 times per turn in some extreme cases, it could make a difference).

Thanks. I have changed my local copy. I will not commit right now because we are in feature freeze.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...