Global AI Interface - Page 10

Global AI Interface

Here is where ideas can be collected for the skirmish AI in development

Moderators: hoijui, Moderators

User avatar
Peet
Malcontent
Posts: 4384
Joined: 27 Feb 2006, 22:04

Re: Global AI Interface

Post by Peet »

LOrDo wrote:Epic freaking ressurection?
Necroing a sticky? More likely than you think.
User avatar
aegis
Posts: 2456
Joined: 11 Jul 2007, 17:47

Re: Global AI Interface

Post by aegis »

User avatar
Aether_0001
Posts: 228
Joined: 25 Feb 2008, 03:41

Re: Global AI Interface

Post by Aether_0001 »

That's a huge list, so i didn't read all of it. I have one, but i'm not sure if it has been said before: DPS/cost ratio. It would help the AI calculate which units would be best to spam and kill things with.
User avatar
jcnossen
Former Engine Dev
Posts: 2440
Joined: 05 Jun 2005, 19:13

Re: Global AI Interface

Post by jcnossen »

Since lua based mods came along, DPS is not something you can calculate from unit/weapon properties...
zenzike
Posts: 77
Joined: 12 Apr 2008, 13:19

Re: Global AI Interface

Post by zenzike »

One missing callback feature is the ability to give away resources (metal/energy), and units. I'm currently building AIs that work with allies, it would be nice to be able to do this, given that human players can.

On that note make sure UnitCreated() and UnitFinished() are called when a unit is given to an AI player, and if transferring units is allowed, make sure UnitDestroyed() gets called too.

I realize this thread is pretty old now: is this still the right place to post such suggestions to the devs?
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: Global AI Interface

Post by Kloot »

AI's are told when a unit is given through the HandleEvent() call-in,
but you have to call UnitCreated() and UnitFinished() manually. I'm
not sure why you'd want UnitDestroyed() to be called when sharing
units though, since the AI that performs the sharing action already
knows about their impending "destruction" (unless the command
fails for some reason, but I think the chance of that happening can
be neglected). ;)

Sharing resources sounds like a very good addition, would a simple

Code: Select all

void ShareResource(int receivingTeam, int type, float amount);
callback suffice for your needs?

PS. yeah IMO using this thread is fine, it's still about the global AI
interface after all.
zenzike
Posts: 77
Joined: 12 Apr 2008, 13:19

Re: Global AI Interface

Post by zenzike »

Thanks for the fast response!
Kloot wrote:AI's are told when a unit is given through the HandleEvent() call-in
Ah, I assumed the HandleEvent function was still unimplemented, the source has a comment next to it that's a bit misleading:

Code: Select all

virtual int HandleEvent (int msg, const void *data)=0; // general messaging function to be used for future API extensions.
Kloot wrote: but you have to call UnitCreated() and UnitFinished() manually.
I'm guessing this means I detect a ChangeTeamEvent in the HandleEvent function, and act accordingly ... fine :)

Kloot wrote: I'm
not sure why you'd want UnitDestroyed() to be called when sharing
units though, since the AI that performs the sharing action already
knows about their impending "destruction". ;)
Well, I thought it would be good practice - when a unit disappears from a team, the callback mechanism is usually through UnitDestroyed(); having this called when a transfer is done would mean that whatever cleanup is normally done would be performed as per normal. You're right though, the UnitDestroyed() could be manually called if so desired, since some side-effects might not be wanted after a transfer.
Kloot wrote: Sharing resources sounds like a very good addition, would a simple

Code: Select all

void ShareResource(int receivingTeam, int type, float amount);
callback suffice for your needs?
Yes, that would be fine, though I recommend

Code: Select all

virtual void SendResource(int type, float amount, int receivingPlayer)
virtual void SendUnit(int unit, int receivingPlayer)
since that's in keeping with

Code: Select all

virtual void SendTextMsg(const char* text, int zone)
and

Code: Select all

virtual void GotChatMsg(const char* msg,int player)=0;		
where the player/zone are the last argument, and the object sent/received is in the first. Also, using the word Send rather than Share makes it a little clearer which way the resource is going. Incidentally, maybe GotChatMsg and SendTextMsg should be a bit more uniform - either both use Chat or Text, but not mixed. I'm also pretty fond of dual words used maybe GotChatMsg should become ReceiveChatMsg (since send and receive go together).

Finally, is there any good reason why ChangeTeamEvent is the way to handle a unit transfer? Shouldn't it be like receiving a message: having a RecieveUnit() function seems more natural to me.
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: Global AI Interface

Post by Kloot »

The interface doesn't have one strict naming convention no. ;) But,
because it's an interface, renaming all those functions would affect
existing AI's, so they're pretty much just left alone.

The HandleEvent() call-in was added so that the interface could be
extended in the future without breaking binary compatibility all the
time (which requires AI's to be recompiled), but there haven't been
many since then. ChangeTeamEvent was simply one of the few new
extensions that made use of it.
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Global AI Interface

Post by hoijui »

CAICallback::SendStartPos(bool ready, float3 pos)
but no
IAICallback::SendStartPos(bool ready, float3 pos)

how is it meant to be used?
has it to do with struct AIHCSendStartPos (in IAICallback.h)?
Kloot
Spring Developer
Posts: 1867
Joined: 08 Oct 2006, 16:58

Re: Global AI Interface

Post by Kloot »

Like this:

Code: Select all

AIHCSendStartPos myStartPos;
myStartPos.ready = true;
myStartPos.pos = float3(1.0f, 2.0f, 3.0f);
cb->HandleCommand(AIHCSendStartPosId, &myStartPos);
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Global AI Interface

Post by hoijui »

UFF!
thanks!
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Global AI Interface

Post by hoijui »

is it true, that UnitDefs never change during a game?
cause if so, it would be good to load all their values into Java at the beginning. This would save a JNI call every time one wants to fetch anything from a UnitDef.

an other, comparable question, concerning float3:
should the Java interface spit out and accept something like Vector3f instead of float3, so the implementation can do vector calculations Java internally, without JNI calls?

(edit: added second part about float3)
zenzike
Posts: 77
Joined: 12 Apr 2008, 13:19

Re: Global AI Interface

Post by zenzike »

That's a good question -- I've assumed that the answer is yes, but confirmation from up above would be good!

I think that the Java interface ought to be able to handle float3 calculations itself, so yes, a Vector3f would make sense. If this wasn't provided, I'd expect that people would start implementing their own anyway, so it may as well be supported at the JNI level.
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Global AI Interface

Post by hoijui »

ok...
am currently working on the Vector3f thing.
some things that float3 supports are not available in Vector3f, namely:

Code: Select all

float Distance2D();
float Length2D();
float SqLength2D(); // squared length

static float maxxpos
static float maxypos
static float maxzpos
bool CheckInBounds()
i could write/use a class that extends Vector3, and adds these things.
the max-positions get set when the map is loaded, so i could set them when the AI loads, as the map is loaded already then.
so this seems to be possible, with .. in my eyes.. better overall performance in the end, maybe.

The problem with UnitDef is...
whenever something changes in UnitDef, i have to adjust the Java class as well then, as i have to write one by hand, which reflects the C++ one, if i want to keep the values in Java.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Global AI Interface

Post by AF »

Yes a UnitDef *should* be constant and never change once it's set, however when trepan was fiddling with lua gadgets he added the ability to change unit definitions via lua.

So far AIs are not notified when they change and AIs work under the assumption that they never change. I don't know of anyone that uses the callbacks in lua to change unit definition unless they're modders and they're using it for development purposes.

If possible extend Vector3f as float3 and give it an identical interface/API so its easier to shift code across between java and c++
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Global AI Interface

Post by hoijui »

thanks AF
(will do that with Vector3f)
well...
With UnitDef...
i think i will do it this way:
when the first AI is loaded, it loads all UnitDefs. this list will contains UnitDef Java objects, which call native methods whenever something is requested from them. then i'll make an other list, containing JUnitDef objects, which have fields (in Java) for all the things contained in a UnitDef. and then fill second lit with values gotten from the first one.

if .. somehow, somewhen, it will be needed to get access to changed values, it could still be done relatively easy through the UnitDef objects, which would then call to native.
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Global AI Interface

Post by hoijui »

the values in UnitResourceInfo do change frequently, right?
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Global AI Interface

Post by AF »

I would assume so depending on which unit is being queried
User avatar
SpliFF
Posts: 1224
Joined: 28 Jul 2008, 06:51

Re: Global AI Interface

Post by SpliFF »

I know I'm coming to this discussion late, and that it's already been taken over by a 5 page rant on the merits of disclosure but since I intend to begin work on a Spring AI later this year I would like to see a useable API in place so I can work mostly in Lua.

I am currently working on an AI framework for Supreme Commander. SupCom exposes a lot of the engine to Lua so it serves as a good example (though it is far from perfect):

SupCom Lua Docs

Unfortunately it is only useful as an overview because it is almost entirely undocumented. Most of my work has been through guessing and trial-and-error.

I realise a lot of the Spring AI code is currently in C++ however I would like to see these functions included as a Lua interface as well. It should work something like this:

event -> C_Callback -> Lua_Callback.

Both the C++ and Lua interfaces should be passed the same data (or nearest approximation). Most of the time this will be at minimum a pointer to a unit. I also recommend the callbacks be implemented, where possible, as methods to avoid name conflicts between, unit, squad and army functions.

Anyway here are my recommendations. I've stuck to common functions that require the speed of C++. More complex functions can be implemented by the AI author in C++ or Lua as needed. My apologises if some/most of these have been suggested or implemented already:

UNIT CALLBACKS
Unit callbacks can be used for unit or squad AIs. They should account for the possibility that the events may be triggered by a player or AI sharing control of the army (support AI). In other words don't assume the AI will know why the event happened (particularly with OnCommand). In the case of events under AI control (like issuing orders) the AI must be able to abort the event by returning false from the handler. In some cases (like OnHit) the army may not have seen the attacker on radar. In this case the unit passed as 'attacker' should be a special value to indicate 'unknown'.

OnCreate(unit) -- Unit built or spawned
OnActivate(unit) -- Unit switched on
OnDeactivate(unit) -- Unit switched off
OnCaptured(unit) -- Unit captured from enemy
OnKilled(unit, killer)
OnHit(unit, attacker) -- attacker may be unknown
OnFire(unit, target) -- target may be ground
OnMove(unit) -- not just move order but any reason (like getting out the way)
OnBuild(unit, unitBeingBuilt) -- For shift/alt build call once per structure
OnBuildComplete(unit, unitBeingBuilt)
OnBuildCancelled(unit, unitBeingBuilt)
OnOrder(unit, order, args...)
OnOrderComplete(unit, order_id)
OnOrderCancelled(unit, order_id)
OnIdle(unit) -- Idle means orders queue finished
OnGrouped(unit,group_id)
OnUngrouped(unit,group_id)
OnLoad(unit, transport)
OnUnload(unit, transport)

ARMY CALLBACKS

OnFrame() -- called when game state changes
OnStartGame()
OnEndGame()
OnEnemySighted(enemy)
OnEnemyDetectedByRadar(blip)
OnAllianceChanged(army1, army2, old, new) -- when diplomacy happens
OnArmyKilled(army)
OnIntelUpdate() -- every time radar/jamming is calculated

INTEL FUNCTIONS
Functions to query intel data from the engine. Intel 'maps' should be defined as a grid of 100m2 rectangles (cells). The functions below should combine in many ways to form precise queries like ('find the combined threat level of all anti-air units or structures in the top right corner of the map owned by enemy armies') or ('find all enemies along this route')

GetThreatMap(type) -- Array containing each map grid square with a relative threat level. Type should be something like 'air', 'surface' or 'sub' to indicate what units are being threatened.
GetResourceMap(type) -- Array containing the desirability of a location for a given resource type (metal or energy or mod-defined type)
FilterMapByThreat(map, level, comparison) -- Filter a threat or resource map by threat level, ie. only return cells matching the query
FilterMapByTerrainType(map, type)
FilterMapByRect(map, rect) -- return cells inside or touching rect
FilterMapByCircle(map, pos, radius) -- return cells inside or touching circle
FilterMapByLine(map, pos1, pos2) -- only return cells that line passes through
FilterMapByPoint(pos) -- given a standard position vector return the cell surrounding it.
SortUnitsByThreat(map, dir) -- where direction is 'ASC' or 'DESC'
SortMapByThreat(map, dir) -- Reorder map cells based on threat instead of grid position

UNIT SELECTION
The AI will need to find or group units according to a range of properties. SupCom enumerates these properties in the unit definition and then allows
them to be combined into queries eg. TECH2 + LAND - ANTIAIR gives you all tier 2 tanks except anti-air.

GetUnitsByType(type) -- All units matching category or class id.
GetUnitsInRect(type, rect) -- List of units in a rectangle
GetUnitsInCircle(type, pos, radius) -- List of units in a circle
GetNearestUnit(unit_list) -- Get closest unit based on category or class id.
FilterUnitsByType(unit_list, type) -- Return units of 'type' only. Types should be 'land','water','air' or a more complex enumeration such as 'structure|missile|water' (a floating missile launcher).
FilterUnitsByAllegiance(unit_list, alliegance) -- Return only 'allied' or 'enemy' or 'own' units
FilterUnitsByThreat(unit_list, level, comparison) -- Return units related to the threat level by comparison where comparison is a string operator like '=', '>', etc..


PATHING
Path calculations are always slow. The AI should always leave it to the engine.

CanMoveTo(unit, pos, terrain_only) -- true if unit can reach destination (optionally ignoring barriers and structures)
GetRouteTo(unit, pos, terrain_only) -- Return a set of lines indicating best guess at unit route to reach pos.
GetETA(unit, pos) -- best guess at time to arrive at pos (assuming uninterrupted move)
GetTerrainType(pos) -- given a location return 'land' or 'water'
GetTerrainHeight(pos)
GetNearestTerrainByType(type) -- given 'land' or 'water' get the closest point. Useful for transports or starting naval construction.
trepan
Former Engine Dev
Posts: 1200
Joined: 17 Nov 2005, 00:52

Re: Global AI Interface

Post by trepan »

You might want to take a ook at System/EventHandler.h and
System/EventClient.h in SVN. The lua scripts are subclassed
from EventClient, which could also be done for AIs (that's why
LuaCallInHandler was moved to EventHandler).

The version in SVN only separates permissions based on
the 'synced' state. My local version separates permissions
based on canCtrlSynced and canReadUnsynced (such that
you could add EventClients that handle both synced and
unsynced data).

Something else to look at:
http://spring.clan-sy.com/wiki/Lua_Scripting

The interface does not use objects for units, etc... That was
done intentionally to keep things simple (and fast).
Post Reply

Return to “AI”