Interface Redesign - Page 6

Interface Redesign

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

Moderators: hoijui, Moderators

Post Reply
User avatar
Agon
Posts: 527
Joined: 16 May 2007, 18:33

Re: Interface Redesign

Post by Agon »

Looked at it and I could understand it mainly even without c or c++ knowledge.

What about the C#/Java interface? It would "connect"/use the C_AI_Interface_engine if I understand it correct. How will a .jar or managed .dll loaded?
Is the function "getLibrary"/"loadLibrary" already implemented and will it handle the loading of none c/c++ AI's?

Will this change in the AI part break sync?
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Interface Redesign

Post by hoijui »

for the engine, all AIs will be C.
the loadLibrary and related stuff works a bit different in reality then in the draft code, but that is nothing we have to worry about. the engine will load only C AIs, to support a C++, Java or C# AI, someone has to write an interface that converts the C interface to that language. (though a/the C++ interface will come with spring, cause otherwise all current AIs would not be usable anymore).
User avatar
Agon
Posts: 527
Joined: 16 May 2007, 18:33

Re: Interface Redesign

Post by Agon »

hoijui wrote:for the engine, all AIs will be C.
the loadLibrary and related stuff works a bit different in reality then in the draft code, but that is nothing we have to worry about. the engine will load only C AIs, to support a C++, Java or C# AI, someone has to write an interface that converts the C interface to that language. (though a/the C++ interface will come with spring, cause otherwise all current AIs would not be usable anymore).
Yeah, but the lobby tells spring via the start script there the AI is located. But if the AI file is a jar or a managed dll how will it handle it then?
Or do the AI (not C/C++)developer need to write a C/C++ AI which loads there .jar or managed dll?

Edit:
Is it possible to tell a AI through the start script a difficult level, like the CA chickens have?
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Interface Redesign

Post by hoijui »

..hmm good question.

currently, we have only one entry in script.txt which specifies the AI:

Code: Select all

aidll=AI/Bot-libs/hoijui.jar;
or

Code: Select all

aidll=AI/Bot-libs/AAI.dll;
for Java support, the engine had to be changed so it knows which dll to load for jar files. and also lobbies (may) have to be changed to scan for *.dll and *.jar files in the Bot-libs directory.

a more general approach would be better i think. as every suported language will alwyas need a native library (dll or so), we should keep an entry which has only the dll in it, and have an other entry for the AI implementation (which could be a jar then for example):

Code: Select all

aidll=AI/Bot-libs/JAI.dll;
aiimpl=hoijui.jar;
or

Code: Select all

aidll=AI/Bot-libs/AAI.dll;
we could have a C function on the AI side of the interface, eg:

Code: Select all

int GetPossiobleNames(char** possibleNames);
which in the case of AAI.dll would return 0, and in the case of JAI eg: "tst.jar", "hoijui.jar", "rai.jar". So the lobbies still only have to scan for dlls, and if they dont support this new way, they will just not provide the aiimpl tag, which changes nothign for AAI for example, and JAI will just chose a jar its self, when it gets no aiimpl tag value.

what do you think?
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Interface Redesign

Post by AF »

As a lobby developer the idea of yet more messing around with unitsync call outs to determine something as simple as listing AIs is not something I look forward to. Keep it as simple as possible if your going to start meddling with how the lobby specifies AIs.
User avatar
Agon
Posts: 527
Joined: 16 May 2007, 18:33

Re: Interface Redesign

Post by Agon »

hoijui wrote:..hmm good question.

currently, we have only one entry in script.txt which specifies the AI:

Code: Select all

aidll=AI/Bot-libs/hoijui.jar;
or

Code: Select all

aidll=AI/Bot-libs/AAI.dll;
for Java support, the engine had to be changed so it knows which dll to load for jar files. and also lobbies (may) have to be changed to scan for *.dll and *.jar files in the Bot-libs directory.

a more general approach would be better i think. as every suported language will alwyas need a native library (dll or so), we should keep an entry which has only the dll in it, and have an other entry for the AI implementation (which could be a jar then for example):

Code: Select all

aidll=AI/Bot-libs/JAI.dll;
aiimpl=hoijui.jar;
or

Code: Select all

aidll=AI/Bot-libs/AAI.dll;
we could have a C function on the AI side of the interface, eg:

Code: Select all

int GetPossiobleNames(char** possibleNames);
which in the case of AAI.dll would return 0, and in the case of JAI eg: "tst.jar", "hoijui.jar", "rai.jar". So the lobbies still only have to scan for dlls, and if they dont support this new way, they will just not provide the aiimpl tag, which changes nothign for AAI for example, and JAI will just chose a jar its self, when it gets no aiimpl tag value.

what do you think?
Sounds good.
But I would change it a bit:
Eg. for AAI:
aiInterface="AI/CPlusPlusInterface.dll";
aiLib="AI/Bot-libs/AAI.dll";

JavaAI:
aiInterface="AI/JavaInterface.dll";
aiLib="AI/Bot-libs/javaAI.jar";

CSharpAI:
aiInterface="AI/CSharpInterface.dll";
aiLib="AI/Bot-libs/CSharpAI.dll";

The problem is the lobby needs to know which interface it should choose.
C/C++/Java/CSharp(Mono). With .jar and nativ .dll it is easy to make a different but for a managed .dll the ending is the same. Maybe it is possible to look into a "header" like MS does it in Windows to decide if it is a native or managed dll.

Besides this two variables I would like to have something like the mod/map option in the lobby for an AI to set for example a difficult level or if an AI should cheat or not.
Like this:
[aioptions]
{
cheat=false;
difficultLevel=1;
}

For this the lobby needs to know what the AI can use in the aioptions.
To do this we need a script for each AI like the script.txt/ModOptions.lua only for an AI.
Also I would suggest to put the interface dll the AI file and the script in an archive, something like .sdz or .sd7.
AIs would then look like a mod and they could be handled by the archivemover to automatically moved to its predefined folder.
I know this would break all AIs but it would have some advantages.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Interface Redesign

Post by AF »

erm, the lobby developer inside me has spontaneously combusted. I dont want to have to deal with figuring out what the interface implementation dll is, and I would rather assume that anything ending in .dll is c++ and drop support for mono/.Net than have to deal with looking inside dll headers which would require me to add native binaries to my lobby project, increasing the complexity of compiling my lobby by several orders of magnitude.

Do not increase the complexity of the lobby interface in order to add features to the AI interface. Also keep in mind that script.txt may be script.lua soon.
User avatar
Agon
Posts: 527
Joined: 16 May 2007, 18:33

Re: Interface Redesign

Post by Agon »

AF wrote:erm, the lobby developer inside me has spontaneously combusted. I dont want to have to deal with figuring out what the interface implementation dll is, and I would rather assume that anything ending in .dll is c++ and drop support for mono/.Net than have to deal with looking inside dll headers which would require me to add native binaries to my lobby project, increasing the complexity of compiling my lobby by several orders of magnitude.

Do not increase the complexity of the lobby interface in order to add features to the AI interface. Also keep in mind that script.txt may be script.lua soon.
Mods and even maps can have custom options. Why not AIs?
The example with the header is silly I know but it would be a solution (a bad one).
Because of this I suggest the an archive for an AI like mods and maps have.
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Interface Redesign

Post by hoijui »

@AF
as said, this way, it would still work without any change to the lobbies. and if the lobbies want to support other languages, they only had to be changed once (querying each AI dll that has the GetPossibleNames() method for names, make these names available to the user for choosing, and add the aiimpl tag in script.txt if needed). after this change, we cold add support to an other language, lets say Ruby, have RubyAIInterface.dll in Bot-libs, and the lobbies would not have to be changed at all to support Ruby AIs.
it seems like a very simple way of doing it to me. adding one function and one tag and be future proofed.
if you have a more simple way, i am interested.

i can not imagine that it is possible to do more simple. the only way i can think of, to do it without any change to lobbies, is to have a separate config file, eg JAI.cfg, where the names of the jars to use are listed. am pretty sure you would not like that ;-) (me neither).

@Agon
As i though of it, all DLLs in Bot-libs would directly suport the C interface (all the ones that use the C++ interface would have it Compiled in). jars and C# dlls could be in an other directory, and only JavaAIInterfcace.dll and CSharpAIInterface.dll would be in Bot-libs, together with AAI.dll, NTai.dll, and the others.

if it is not done that way, but all AI libs are put directly into Bot-libs, also C# and Java ones, then we had to do something like you said yeah :/
is it possible to load a CSharp.dll with C and see if it exports a certain C function? if not, it should give an error, which would serve as well, right?

about AI options and the other suggestions:
i would like to have that too, but this would mean quite some changes to lobbies and the engine. ;-)
but if you convince everyone... i wont say no!
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Interface Redesign

Post by AF »

Well I like the idea of AIs in archives as long as you sort out a way for unitsync to detect and root out the incompatible AIs, as well as a parameter to ignore compatibility, as well as ignoring the hashes of the AI so that they don't interfere with sync testing.

grrr this is getting complicated. Even if you do add in fancy AI options like the mods and maps it would be quite a while before any AI actually used them, or before any lobby implemented the controls needed.


Also may I point out that your all making a huge gigantic assumption that the lobbies are all native code. My lobby is java, and I'm telling you that if I am to query dlls I need native code, which means I need to add a new build system to my project, I have to write JNI interfaces, proxy dlls, then there's cross platform tools for actually building it, do I use cmake or scons? What about Autotools? I have no experience with any of these so which do I use and how do I use them? How am I supposed to handle these? Should I just use JNA and call directly the dlls? How do I use JNA?

So I can tell you right now that I am not implementing anything that requires me to call AIs directly. As a lobby developer the only dll interface I will call is unitsync.dll and only because I already have an interface built for it that can be added to in the svn that is not part of my own project.
User avatar
Agon
Posts: 527
Joined: 16 May 2007, 18:33

Re: Interface Redesign

Post by Agon »

AF wrote:Well I like the idea of AIs in archives as long as you sort out a way for unitsync to detect and root out the incompatible AIs, as well as a parameter to ignore compatibility, as well as ignoring the hashes of the AI so that they don't interfere with sync testing.

grrr this is getting complicated. Even if you do add in fancy AI options like the mods and maps it would be quite a while before any AI actually used them, or before any lobby implemented the controls needed.


Also may I point out that your all making a huge gigantic assumption that the lobbies are all native code. My lobby is java, and I'm telling you that if I am to query dlls I need native code, which means I need to add a new build system to my project, I have to write JNI interfaces, proxy dlls, then there's cross platform tools for actually building it, do I use cmake or scons? What about Autotools? I have no experience with any of these so which do I use and how do I use them? How am I supposed to handle these? Should I just use JNA and call directly the dlls? How do I use JNA?

So I can tell you right now that I am not implementing anything that requires me to call AIs directly. As a lobby developer the only dll interface I will call is unitsync.dll and only because I already have an interface built for it that can be added to in the svn that is not part of my own project.
Yeah, your right. Calling an AI .dll is not a good solution.

We could create a branch and develop there and besides the lobby developer could integrate it.

@hoijui:
It seems possible to call managed dll from native applications:
http://support.microsoft.com/kb/828736
http://www.mono-project.com/Embedding_Mono
I took only a short look at it.
I think Hughperkins has more experience in this as I.

I would like to hear some more feed back from the two other lobby projects (SpringLobby/TASClient) about the archives for AIs.
And yeah it would require more work as "only" rewriting an interface.
But if we are going to rewrite/redesign the AI why not completely?
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Interface Redesign

Post by hoijui »

unitsync could call the AIs, no?
JNA is very simple, i'd write you the class.

if we had archives, then they would contains files that the lobby has to load which contain a list of options with types, which are available in the lobby then?
sure, that is a more comfortable way, if everyone is going to do that.

though i would rather want that as an addition to my option, not as a replacement. in the end, the user should not have to select JAI, and then go to the options and select hoijui.jar, the user does not care or not know that hoijui is a Java ai and therefore needs JAI.
User avatar
Agon
Posts: 527
Joined: 16 May 2007, 18:33

Re: Interface Redesign

Post by Agon »

hoijui wrote:unitsync could call the AIs, no?
JNA is very simple, i'd write you the class.

if we had archives, then they would contains files that the lobby has to load which contain a list of options with types, which are available in the lobby then?
sure, that is a more comfortable way, if everyone is going to do that.

though i would rather want that as an addition to my option, not as a replacement. in the end, the user should not have to select JAI, and then go to the options and select hoijui.jar, the user does not care or not know that hoijui is a Java ai and therefore needs JAI.
Yeah, a script in the archive would contain all necessary informations for the lobby's.

If we use archives the user do not need to select a interface because it is set in the script (in the archive).
And you can give the AI the name you like over the script in the archive.
Archives also reduces the files size of AIs. And if an AI uses a library it could be bundled into the archive.
I would like to use archives for AIs or if someone has a better idea to handle interfaces, custom options and extra libraries besides the AI library I will listen to it :wink: .
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Interface Redesign

Post by AF »

In that case if you can make everything run through unitsync and it isn't that complicated then do so. I should try and move from JNI to JNA anyway for my lobby so that I don't have to mess around with keeping packages and class names and updating the java bindings any more.

However are you sure you know how to load dlls from the VFS yet?
zenzike
Posts: 77
Joined: 12 Apr 2008, 13:19

Re: Interface Redesign

Post by zenzike »

If we could keep this forum topic specific to the engine / AI interface then things won't get so messy. I think this talk about lobby development is useful, but maybe a different thread would be better, since it's a different issue, and there is still plenty to clear up here.

Hoijui's done a lot of work specing up some code for us all. I think we need to discuss it a little:
hoijui wrote:what do you think?
Most of it is good, but there are a few things that I think aren't quite right. This is what I think the interface should look like:

IAIInterface.h

Code: Select all

#ifndef IAIINTERFACE_H_
#define IAIINTERFACE_H_

DLL_EXPORT int interfaceVersion();
DLL_EXPORT int handleEvent(int teamID, int messageID, void* message);

#define NULL_EVENT      0
#define INIT_EVENT      1
#define UPDATE_EVENT    2
// ...


struct SNullEvent { 
};

struct SInitEvent {
    int myTeamId;
    AIContext aiContext;
};

struct SUpdateEvent {
    int frame;
};

// ...

#endif /*IAIINTERFACE_H_*/
IAIInterface.cpp

Code: Select all

DLL_EXPORT int handleEvent(int teamID, int messageID, void* message) {
    switch (messageID) {
        case NULL_EVENT:
            // The coder does what they want here!
            // See example for UNIT_CREATED_EVENT
            break;
        case INIT_EVENT:
            // ...
            break;            
        case UPDATE_EVENT:
            // ...
            break;
        case UNIT_CREATED_EVENT:
            // A simple way to unpack the information is like this:
            // SUnitCreatedEvent e = (SUnitCreatedEvent) message;
            
            // A slightly better way is to create an object with
            // the appropriate information, and then we can use methods
            // as we wish, like this:
            UnitCreatedEvent event(message);
            eventHandler[teamID].handle(event);
            break;
        default:
            // Maybe we want to log a warning here.
            break;
    }
}
Where eventHandler is an array of class EventHandler, with an EventHandler for each team handled by the AI. EventHandler would be something like:

Code: Select all

class EventHandler {
    void handle(Event event);
}
and we can use full type checking on the Event called event, with polymorphism on our side. This means we can do clever things like making UnitCreatedEvent a subclass of Event, where Event has the following spec (or anything similar):

Code: Select all

class Event {
  public:
    virtual void execute();
}
The great thing is that now in the handle method of the EventHandler we can execute the Event if we wish, or could choose not to. We can do plenty of other things in the handle method, like logging events for debugging and profiling, etc. We could even call interfaceVersion() to make sure we have the version we support.

Notice that we first had to create structs SUnitCreatedEvent. Why? Because we can't pass C++ type classes around in our API, but we can pass a struct as data that will then fill in the body of the C++ class with the type UnitCreatedEvent.

The point is that an AI developer can choose to do this if they want: I don't think we should burden the current spring developers with these details since they have better things to worry about. If we all want a common way of doing things past the interface that's fine -- but it's a different concern, and the AI devs should do it amongst themselves. (I'm happy to do the maintenance for this, but we'd need clearance from the spring devs).

I won't bore everybody with the details of handleCommand, since it's exactly the same game but on the other side.

One thing we still haven't sorted out is the callback for the getState().
Tobi wrote: However, this is contrary to what everyone wants, and I also think it's over-design/over-generalization.

So, I think the quicker solution to make functions like float GetUnitHealth(int unitid) etc. is the way to go.
I'm inclined to agree with Tobi here. I know that AF has concerns that we're not being generic enough, but I guess at some point we need a concrete set of states that we can demand from the engine.

The only suggestion I have is something like this:

Code: Select all

void* callback(int callbackID);
But Tobi has already mentioned the problems with this approach:
Tobi wrote:A generic callback function seems like a useless complication to me for the callback interface, not in the least because of the trouble of returning a pointer to an object:

* it can't just be created on the stack in the engine because then pointer would be dangling on return of the callback function.
* It can't be allocated on the heap without a bunch of code to automatically garbage collect it a later frame.
* It can't be allocated on the heap and freed in the AI because they may use a different C runtime (ie. different heaps).
* It can only be made a global variable engine side (or member of the object representing the AI, but that's still pretty much global), with accompanying issues of people still trying to free the pointer, callbacks being non-reentrant, etc.
These are serious issues, but I think we need to do things this way because we gain the following:
* granularity is no longer an issue: the engine can be as course or fine as the AI needs it to be.
* complete forward/backward compile compatibility between engine and AI.
* future extensions trivial to create.
* generic interface means the engine is *completely free* to change internal representations (so long as it provides appropriate adaptors).
The trouble is in designing appropriate callback IDs and structs, and of course the dangling pointer problem, which is the more serious concern.

I think the dangling pointers can be avoided if we use a struct like:

Code: Select all

struct IntState {
    int i;
}
That is only guaranteed to exist and be correct between its initial callback, and the next call to callback(). This is dangerous if the AI dev doesn't know what is going on, and is why I'm not 100% sure this is correct.

Of course, we'd also need UnitDef, and other fundamentals, but these would be nothing more than passing these (constish) structs, with a callbackID of UnitDefState.

Let's get back on track to answering this one question since it's the last theoretical aspect we need to think about before code can be rolled out:
What is the best way of implementing getState()?
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Interface Redesign

Post by hoijui »

@AF & Agon
see new thread

@zenzike
the name changes you did: the structs are ok for me, with S in front. function names in C are lower case? and in C++ the standard is upper case?
the names i used seem more appropriate during the discussion to me, as they are long but quite eliminate confusion (C_AI_Interface_ai instead of IAIInterface eg.), but i did not assume that these names will be used for real. ;-)

i don't understand what you want with the NULL_EVENT. when would the engine send one of these?

why do you want to remove the fromId? we said this could be used for AI->AI communication in the future.

why do you want to remove the eventId? we said this could be used for asynchronous communication in the future.
zenzike wrote:

Code: Select all

DLL_EXPORT int handleEvent(int teamID, int messageID, void* message) {
    switch (messageID) {
        case NULL_EVENT:
            // The coder does what they want here!
            // See example for UNIT_CREATED_EVENT
            break;
        case INIT_EVENT:
            // ...
            break;            
        case UPDATE_EVENT:
            // ...
            break;
        case UNIT_CREATED_EVENT:
            // A simple way to unpack the information is like this:
            // SUnitCreatedEvent e = (SUnitCreatedEvent) message;
            
            // A slightly better way is to create an object with
            // the appropriate information, and then we can use methods
            // as we wish, like this:
            UnitCreatedEvent event(message);
            eventHandler[teamID].handle(event);
            break;
        default:
            // Maybe we want to log a warning here.
            break;
    }
}
Where eventHandler is an array of class EventHandler, with an EventHandler for each team handled by the AI. EventHandler would be something like:

Code: Select all

class EventHandler {
    void handle(Event event);
}
and we can use full type checking on the Event called event, with polymorphism on our side. This means we can do clever things like making UnitCreatedEvent a subclass of Event, where Event has the following spec (or anything similar):

Code: Select all

class Event {
  public:
    virtual void execute();
}
The great thing is that now in the handle method of the EventHandler we can execute the Event if we wish, or could choose not to. We can do plenty of other things in the handle method, like logging events for debugging and profiling, etc. We could even call interfaceVersion() to make sure we have the version we support.

Notice that we first had to create structs SUnitCreatedEvent. Why? Because we can't pass C++ type classes around in our API, but we can pass a struct as data that will then fill in the body of the C++ class with the type UnitCreatedEvent.

The point is that an AI developer can choose to do this if they want: I don't think we should burden the current spring developers with these details since they have better things to worry about. If we all want a common way of doing things past the interface that's fine -- but it's a different concern, and the AI devs should do it amongst themselves. (I'm happy to do the maintenance for this, but we'd need clearance from the spring devs).

I won't bore everybody with the details of handleCommand, since it's exactly the same game but on the other side.
here you show an alternative C++ interface for AIs (the AI side). seems good to me. the question is, as we have to have the old way of the C++ interface reproduced as well, to support the current AIs:
will the old C++ interface be built up directly on the C interface, or use your new C++ interface underneath?

zenzike wrote: One thing we still haven't sorted out is the callback for the getState().
Tobi wrote: However, this is contrary to what everyone wants, and I also think it's over-design/over-generalization.

So, I think the quicker solution to make functions like float GetUnitHealth(int unitid) etc. is the way to go.
I'm inclined to agree with Tobi here. I know that AF has concerns that we're not being generic enough, but I guess at some point we need a concrete set of states that we can demand from the engine.

The only suggestion I have is something like this:

Code: Select all

void* callback(int callbackID);
But Tobi has already mentioned the problems with this approach:
Tobi wrote:A generic callback function seems like a useless complication to me for the callback interface, not in the least because of the trouble of returning a pointer to an object:

* it can't just be created on the stack in the engine because then pointer would be dangling on return of the callback function.
* It can't be allocated on the heap without a bunch of code to automatically garbage collect it a later frame.
* It can't be allocated on the heap and freed in the AI because they may use a different C runtime (ie. different heaps).
* It can only be made a global variable engine side (or member of the object representing the AI, but that's still pretty much global), with accompanying issues of people still trying to free the pointer, callbacks being non-reentrant, etc.
These are serious issues, but I think we need to do things this way because we gain the following:
* granularity is no longer an issue: the engine can be as course or fine as the AI needs it to be.
* complete forward/backward compile compatibility between engine and AI.
* future extensions trivial to create.
* generic interface means the engine is *completely free* to change internal representations (so long as it provides appropriate adaptors).
The trouble is in designing appropriate callback IDs and structs, and of course the dangling pointer problem, which is the more serious concern.

I think the dangling pointers can be avoided if we use a struct like:

Code: Select all

struct IntState {
    int i;
}
That is only guaranteed to exist and be correct between its initial callback, and the next call to callback(). This is dangerous if the AI dev doesn't know what is going on, and is why I'm not 100% sure this is correct.

Of course, we'd also need UnitDef, and other fundamentals, but these would be nothing more than passing these (constish) structs, with a callbackID of UnitDefState.

Let's get back on track to answering this one question since it's the last theoretical aspect we need to think about before code can be rolled out:
What is the best way of implementing getState()?
I am still pro functions (things like making a struct for an int ... :/ ).
the most likely change in the callback interface is that new events/functions get added. the way of retrieving something will most likely not change. eg getting the position of a unit needs the unitId, and never will need more or less.
if we add a new function pointer to the end of AIContext (a new event), the AIContext struct can still be used by old AIs, no? if i understand it right, an new AI will always crash with an old engine, and vise versa not, wether we use functions or events, no?
adding an event(= future extension) is more trivial with functions.
i dont understand the last point, about internal representation of the engine. as we pass only primitives through the functions, this applies to functions aswell (a float3 will be passed as float[3] through the C interface eg, wether we use functions or events).
User avatar
Agon
Posts: 527
Joined: 16 May 2007, 18:33

Re: Interface Redesign

Post by Agon »

If we use archives we will break the compatibly to old AIs, too.
So why not breaking it in the code, too if a implementation of the new interface is easy and provides more futures than we old one?
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Interface Redesign

Post by AF »

I think we should build the compatibility layer ontop of the C interface, and then start designing the OO c++ layer that replaces it. The OO C++ API we build will need a lot of design considerations as it will have a far greater impact on how the AIs built with it are structured.

As it is most new AIs are not just using the IGlobal AI interface to interface with the engine, they're using it in order to derive an initial architecture. For example, SAI was initially built almost entirely within the IGlobalAI interface derived class the engine made calls to. The same is true of the initial KAI before krogothe started his numerous rewrites, NTai 0.2 was almost entirely CGlobalAI.

As such I think discussion of this should not be in this thread and we should focus on getting to a C API.

In my design there is only 1 C++ class defined CAIObject, and the AI and the rest of the C++ SDK is built on top of this CAIObject class. We should not spend too much time looking beyond CAIObject and simply see the C API as a means for transporting data between the CAIObject on the AI end of the divide, with the CAIObject on the engine end of the divide.

As such I would define the most primitive C++ API available to eb the following:

Code: Select all

class CMessage{
public:
    CAIObject* GetSource();
    int GetMessageType();
};

class CAIObject {
public:
    CAIObject(CAIObject* parent){}
    ~CAIObject(){}

    CMessage* HandleMessage(CMessage* m){}
protected:
private:
};
With the parent of the first CAIObject being a CAIObject representing the engine itself that the AI can use to callback. The parent of the other AI objects could be a global object representing the AI or another object in a heirarchy, or perhaps a dedicated class whose sole pupose is to handle messages and link everything together, thats all up to the developer to decide.

Thus classes in an AI or at least the starting object would be classes inheriting from CAIObject.

HandleMessage returns a CMessage* as a means of querying without using an asynchonous design, however Id expect this to return a null pointer for most calls.

CMessage itself is a base class and as such one would call GetMessageType() and use that to cast the pointer to the appropriate class type.

Everything underneath this layer is C API land, and the C++ API sits directly on top of this layer. The current existing C++ interface should use the C API although someone may wish to lift it up another notch to sit ontop of the CAIObject layer.

The CAIObject layer is to be as small as possible and should only concern itself with taking the C API and presenting a simple C++ OO interface which we can build an AI framework with.
User avatar
AF
AI Developer
Posts: 20687
Joined: 14 Sep 2004, 11:32

Re: Interface Redesign

Post by AF »

Agon wrote:If we use archives we will break the compatibly to old AIs, too.
So why not breaking it in the code, too if a implementation of the new interface is easy and provides more futures than we old one?
Because restructuring and refactoring the current AIs is more work than building a compatibility layer. We have KAI RAI AAI NTai aswell as a number of other projects we may not be aware of and the current AIs that are not under active development that would need large swathes of their foundations refactored.

It would also nuke the long term survivability of the project in that a slow gradual shift would no longer be possible. We would have either a C++ or a C interface, there's no slowly shifting bit by bit over time. The current way allows us to continue after long pauses should any of us be hit by a bus or die in a freak accident.
User avatar
hoijui
Former Engine Dev
Posts: 4344
Joined: 22 Sep 2007, 09:51

Re: Interface Redesign

Post by hoijui »

(whats a freak accident? :D )

i am a little confused AF...
all you explained in your post (about CAIObject), is on the AI side of the interface, right? using the C interface. (in this case i would understand)
if it is on the engine side (before the C interface) i would not understand.

if i understand, then i am absolutely pro this idea (first rebuilding the current C++ interface on top pf the C interface, and later do the new C++ interface). as i would not care about the new C++ interface, and leave it up to you ;-)
Post Reply

Return to “AI”