Page 1 of 2

Lua <-> AI Generalised message standard proposal

Posted: 06 Jun 2011, 15:37
by AF
Here's my proposal of generalised standard lua <-> AI message passing. I will use the example of passing a message intended for a gadget that prints out messages to the console via lua.

Sending multiple messages

Code: Select all

{
    messageTransport=multi
    framesent=64,
    messagecount=2,
    senderAI="shard",
    messages={
        {
            id=1,
            message="printmessage",
            consolestring="hello world1"
        },
        {
            id=2,
            message="printmessage",
            consolestring="hello world2"
        }
    }
-- etc
    }
}
Messages sent in batch would have IDs to allow the returned values to be mapped correctly to their messages. Messages are to be listed in their order of priority. IDs are numeric ascending and continuous, allowing data to be passed back in a nondictionary array

Where multi is a predefined constant indicating that there are multiple messages to be processed.

Sending a single message

A 'single' messageTransport would also be available to cut down on processing for when only an individual message is sent. At which point it would look more like this:

Code: Select all

{
    messageTransport=single
    framesent=64,
    senderAI="shard",
    message="printmessage",
    consolestring="hello world1"
}
framesent, and senderAI being for debug purposes, and completely optional. I would expect AIs would only include this information when necessary.

Returning data
A gadget processing a multiple message string wanting to return data might send the following back:

Code: Select all

{
    {
        returned="success"
    },
    {
        return="failure",
    }
}
Where the IDs of the messages are the indices of the returned table.

Detection

Code: Select all

If first character of string == '{'
Better suggestions that add as minimal overhead and as little to the actual content of the string as possible are welcome.

Implementation points

On the lua gadget side, I envisage there will be a standard gadget that gets shared across all games ( possibly engine bundled ) that processes these messages, and then issues its own callins on other gadgets for handling.

Unsynced widgets

This can be added to such a gadget as mentioned above, perhaps with a message key specifying if the target is Synced or Unsynced code.

Discovery

Early on in the first frame or Init call, an AI should send a message to the gadgets asking for a response with as much information as possible. This response should include the version of the processing gadget, any game information that is not a part of the standard engine archive info, a list of present gadgets, and any AI APIs that the game wishes to expose, with there chosen AI API Identifiers, and version numbers, and what messages they support. A list of possible events should also be returned and the number of parameters.

This message should only need to be sent once, and should not be requested during active gameplay save for when load/save mechanics are employed.

AI Request Mechanics

Early on in the frame processing, the AI should make a request to check if new events have occurred ( e.g. xyz has started a jumpjet, ABC has teleported across the map, or 123 has been turned into a potatoe ). This should ideally be one of the first things done on each frame. The AI may wish to issue other commands in this request in a multiple message table.

The AI should then aim to batch the commands and requests it needs then send all at once to minimize on serialisation/de-serialisation costs, and the cost of messages being routed through the engine API calls.

AIs should aim to send as few single/individual messages, and use the single message format purely as an optimisation to save processing power. This may be unrealistic in some cases, and so the AI should aim to stay within 3 messages per frame.

Messages & AI engine events

Should a message be needed on an event such as abcFinished, or xyzDied, then the message should be queued and sent in the next frame along with the initial request for events message.

Custom code execution

The AI should be able to send a message 'function', which has a parameter function, whose value is a string function that is to be executed in gadget land. It's return values are to be packaged up into the standard gadget return value format. This should allow AIs the ability to execute unsynced commands it otherwise wouldn't be able to, and to be able to interact with gadgets that may not have an AI API.

Re: Lua <-> AI Generalised message standard proposal

Posted: 06 Jun 2011, 23:15
by slind
The first problem I notice is that your strings are denoted by double quotes, which prevents double quotes from being used without processing escape sequences which requires way more processing time then is actually necessary. A simpler(and more accurate) solution is to indicate the length of a message.

Let us use the following shorthand:

A - AI Name
S - String
M - Message (contain an message ID and a string to be executed)
I - Message ID
: - Delimiter (Only used after a length number).

Thus if we wanted to identify the AI Name as 'shard' we would pass the following

Code: Select all

A5:shard
If we wanted to send a Message to lua of

Code: Select all

print("hello world")
we would pass the following

Code: Select all

M28:I1:3S20:print("Hello World")
Which breaks up into

a M28 message that is 28 characters long. Inside that message there is an I1 which refers to an ID of 1 character long which represents the ID. This ID is 3. The second part of the Message would be a String that is 20 characters long represented by print("Hello World")

Message
- ID = 3
- String = print("Hello World")


We could then put as many message together in the string as we wanted without having to specify 'multi' or otherwise. When it ran out of things to parse from the string, it would be finished. Here is an example of 3 messages put together with an AI Name of 'shard'.

Code: Select all

A5:shardM28:I1:1S20:print("Hello World")M12:I1:2S5:x = 3M15:I1:3S8:print(x)
This would translate to

AI Name = Shard
Message
-Id = 1
-String = print("Hello World")
Message
-Id = 2
-String = x = 3
Message
-Id = 3
-String = print(x)


Please note that this is simply an example of the string format. You could change the letters to mean whatever you wanted. Messages could take as many elements as they wanted and there is no reason i used actual lua code in my strings.

The simple idea is that
[*]Spaces don't matter
[*]Quotations don't matter
[*]There is no special character that denotes the end of a message/id/anything that we cannot use.
[*]You can encode NULL (or any other value) into your string and still parse the string successfully.
[*]You could expand this to make associative arrays.
[*]Short, fast, and easy to parse.

Re: Lua <-> AI Generalised message standard proposal

Posted: 06 Jun 2011, 23:43
by AF
I completely disagree. My message format uses standard lua syntax, as such I don't need to follow the examples syntax, as long as it is syntactically correct in vanilla lua.

Your proposal would require custom parsing on the lua end, coupled with unforeseen potential bugs, as well as problems with delimiters, erroneous data, and subprotocols for structured data that needs returning that a simple key/pair or list will not suffice for.

AI <-> lua calls are not going to be cheap enough to flit back and forth messages on the spur of the moment.

What we do know is tha the biggest cost of message handling will be in the lua side of things. What better than to parse the message using standard lua APIs that have been well tested and optimised as a part of the language toolchain.

What's more, this makes things much easier for native lua AIs as there's would be a standardised AI API that could be used with zero parsing and string construction by simply bypassing the one or two lines needed to parse the string message in lua

Re: Lua <-> AI Generalised message standard proposal

Posted: 07 Jun 2011, 00:09
by slind
AF wrote:I completely disagree. My message format uses standard lua syntax, as such I don't need to follow the examples syntax, as long as it is syntactically correct in vanilla lua.
Interesting. I hadn't noticed that. You could just use a loadstring() on it.

What's more, this makes things much easier for native lua AIs as there's would be a standardised AI API that could be used with zero parsing and string construction by simply bypassing the one or two lines needed to parse the string message in lua
That's why i said it was just a framework. You could modify it so that there is a standardized lua framework for the lua ais to call/becalled by.

Regardless, I like the idea of simply passing a string the lua side could call a loadstring on, then call a function which would operate on the table that just got loaded.

How about this:

Code: Select all

{
    messageTransport=multi,
    framesent=64,
    messagecount=2,
    senderAI="shard",
    messages={
        1 = {  message="printmessage",
            consolestring="hello world1"
        },
        2 = {
            message="printmessage",
            consolestring="hello world2"
        }
    }
-- etc
    }
}
Where the id number is the key for the table. Then after the loadstring() you could simply do a

Code: Select all

returns ={}
for k,v in pairs(messages) do
    if(v.message == "printmessage")
       returns[k] = print(v.consolestring)
    end
end

returnstring = ""
for k,v, in pairs(returns) do
  returnstring = returnstring .. k .. "= {" .. v .. "}"
end

if the message in v.message was an actual lua function it would be easier to simply do

Code: Select all

for k,v in pairs(messages) do
     returns[k] = loadstring(v.message .. "(" .. v.consolestring .. ")")
end

Re: Lua <-> AI Generalised message standard proposal

Posted: 07 Jun 2011, 00:27
by AF
Because then ID is not just an identifier, it's also a priority for ordering, whereas I'd like the order of messages to be the order, and the flexibility.

But anyway, the messages sub table needn't be a dictionary type, or have numeric indices defined for your idea.

Re: Lua <-> AI Generalised message standard proposal

Posted: 07 Jun 2011, 00:29
by slind
AF wrote:Because then ID is not just an identifier, it's also a priority for ordering, whereas I'd like the order of messages to be the order, and the flexibility.

But anyway, the messages sub table needn't be a dictionary type, or have numeric indices defined for your idea.
No, but it makes it easier for converting back into c++ to maintain integer ordered tables. (strictly speaking its faster in Lua too).

Also, why can't the id be the priority as well? This would make it easy for c++ to setup the order of calls and the order of the return values.

Re: Lua <-> AI Generalised message standard proposal

Posted: 07 Jun 2011, 10:01
by hoijui
what about the OSC protocol?
http://en.wikipedia.org/wiki/Open_Sound_Control#Design
  • very simple
  • no need for type conversion on either side
we would just need to define some standard names like the ones AF suggested: id, message(content)
we can make use of the pattern machting mechanisms to filter and route messages.
(this is from my initial proposal, btw)


btw slind:

Code: Select all

[list]
[*] foo
[*] bar
[/list]

Re: Lua <-> AI Generalised message standard proposal

Posted: 07 Jun 2011, 12:42
by SpliFF
There's room to simplify this.

1.)

Code: Select all

messagecount=2
is equivalent to

Code: Select all

#messages
2.)

Code: Select all

messageTransport
... adds complexity and overhead because 'messageTransport=XXXXX' is actually a longer string than messages={..}. There won't be any performance benefits either because ...

Code: Select all

for i = 1,#messages do
... has less overhead than ...

Code: Select all

if messageTransport == 'single' do
... because the former is math and the later requires a string compare. Its also redundant because ...

Code: Select all

if msg.messages do
   -- multi
else if msg.message do
   -- single
else
   -- error
end
3.)

Code: Select all

{
    message="printmessage",
    consolestring="hello world1"
}
Didn't you say 'message' is supposed to be a function? (this example seems to imply it). If so the field names are confusing and ...

Code: Select all

{
    function="printmessage",
    args={"hello world1"}
}
... would appear to make more sense.

Re: Lua <-> AI Generalised message standard proposal

Posted: 07 Jun 2011, 16:33
by AF
String Comparison and messageType

When I wrote the first post I envisaged these would not be strings, rather constants, just as one might define magic numbers in C. String comparison is unnecessary here, and would seem just as ludicrous as putting "CMD_FIGHT" instead of using #define CMD_FIGHT 9000 in the engine.

The reasoning was flexibility (e.g. message types that are neither single or multiple that we have yet to foresee), and simplification (ruled out by an example in your post).


Eitherway re-reading your points, I agree, I shall make modifications later this evening and repost the spec as mkII in this thread.

Message parameter

The message parameter is not a function call to be made in lua land, but more a subject. Though I am thinking that putting the other parameters of a message ( it's payload ) inside an arguments or data sub table might be a good idea after looking at your post. Does everyone else agree?

Data would be the payload of a message, and 'message' would be the identifier telling us the kind of message, be it a command, an event, a request, a debugging message, or a purely informative notification.

Messagecount

This is for debugging purposes, e.g. if messageCount != #messages then the data is not suitable and a warning should show and the developer should open his debugger. This would be an optional value, that should not be relied on, and in practise would only be sent when necessary.

OSC

Hoijui can you post a link to your original proposal? I don't know about OSC but I'm curious to see exactly what such a message would be like

Return format

It may be of use for the AI to specify that it wishes the returned string to be in an xml/json format not lua. This would be perfectly feasible since the gadgets serialisation code could be modified to suit, but we need to factor this into the standards if we're to do it.

Reasons for doing this would be to ease the transition for those AIs built in languages for which putting a lua parser in would not be trivial, and to lower the barrier to entry. Some AI developers may not link to lua and feel uneasy about adding it as a dependency, or may wish to use lighter weight parsers they're more familiar with.

Re: Lua <-> AI Generalised message standard proposal

Posted: 07 Jun 2011, 17:42
by hoijui
what such a message would be like is visible on wiki link i posted.
i can't find the original proposal either, guess it was not in its own thread.

Re: Lua <-> AI Generalised message standard proposal

Posted: 08 Jun 2011, 01:13
by slind
AF wrote: Does everyone else agree?

Data would be the payload of a message, and 'message' would be the identifier telling us the kind of message, be it a command, an event, a request, a debugging message, or a purely informative notification.
Yes
Messagecount

This is for debugging purposes
Then make it optional.
Return format

It may be of use for the AI to specify that it wishes the returned string to be in an xml/json format not lua. This would be perfectly feasible since the gadgets serialisation code could be modified to suit, but we need to factor this into the standards if we're to do it.

Reasons for doing this would be to ease the transition for those AIs built in languages for which putting a lua parser in would not be trivial, and to lower the barrier to entry. Some AI developers may not link to lua and feel uneasy about adding it as a dependency, or may wish to use lighter weight parsers they're more familiar with.
If they are going to use the Lua format to pass the string then why not use it to return it? Besides writing a parser for this should be trivial.

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 00:58
by AF
Then make it optional.
It is, but I wanted it in the example so it was somewhere, and I did state not all of the parameters were required in the original post.
If they are going to use the Lua format to pass the string then why not use it to return it? Besides writing a parser for this should be trivial.
Because I imagine it would be easier to use a json parser in the standard Java API than it would be to write a custom lua data only parser, or to embed lua in a Java app.

Afterall why write a parser when you can grab some code and have a readymade one thats been tested for you?

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 02:17
by slind
Afterall why write a parser when you can grab some code and have a readymade one thats been tested for you?
You have a point, but I was under the impression that we wanted the Lua side to be as efficient and short as possible. As long as the code is vetted and efficiency tested prior to use on the Lua side I don't have a problem with it.

Hand-rolling our own serializer would also mean that we only implement the functionality we need and no extraneous execution would be performed. Also, once the a parser is written it could be provided through the wiki/forums.

Honestly I don't know which would provide more efficient processing. When I think about it, it seems that any situation where we serialize into json or xml would result in extra wasted processing time doing the extra stuff json/xml needs to be correctly formatted. Maybe this intuition is wrong.

We could profile each and come up with a comparison?

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 12:28
by AF
Well we would specify as an AI at the beginning what format we need things returned in, so that the necessary steps to setup in gadget land for speed can be made. We should only need to do the comparison to decide what to call once when the AI sends its initial message, then store the necessary functions or objects in a variable so that we just call it later on and trust we are calling the correct serialiser.

Messages sent to lua for the moment should be in lua, we can discuss the possibility of AIs sending json/xml messages of the same structure but the first message identifying the AI and asking for a response should be lua. Its the simplest message and can be done with no serialisation at all ( it can be hardcoded on the AI end )

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 16:49
by slind
I was a bit confused at first.

You are saying that Lua would return a Lua formatted string, unless the AI specifically asked for a certain type of return format.

So the XML/JSON thing could be optional. Right?

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 17:03
by AF
Ofcourse, there's nothing stopping you from constructing a lua table in string form in any language using basic string appending, but parsing it is quite a bit more work for most people.

Ofcourse we could provide for lua to accept json etc from the AI as specified in the initial message, but I would consider that to be a use at your own risk performance wise.

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 18:53
by slind
Right. Sending to lua should be in lua. We agreed on that. We are talking about the return string. Correct?



Writing an XML/JSON serializer in Lua for the return string is what I have been talking about.

I don't know if an XML/JSON serializer is faster than a hand-rolled custom lua format serializer would be. It is possible that it is, but I don't know. Thats why I suggested profiling them before we decide.

If the XML/JSON serialize is faster or nearly as fast as a custom lua serializer then obviously the XML/JSON route is the way to go because the parsers are already written.

If the XML/JSON serializers are significantly slower then it is possible that writing custom serializers AND custom parsers for a variety of languages is the way to go.

If we don't care about the speed of the serialization on the lua side then lets go with the xml/json for the return value.

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 19:38
by AF
Mesages sent to lua: lua ( and always lua )
Messages recieved from lua: lua by default (unless otherwise specified)

Serialising lua in lua and serialising json/xml shouldn't be too different. But Lua should be returned unless otherwise specified.

The reaosn I suggest this is not for performance reasons, but for API design reasons, and ease of adoption. Those choosing XML or JSON would do so not for speed, but for other reasons, such as:
  • Being able to rely on native APIs, such as the XML and Json parsers in the Java API, or the .Net runtime
  • Not having to add lua as a dependency
Having to parse lua in c++ or python isn't the nicest thing especially if your new and just starting out. Grabbing a single file json parser and having a pretty OO interface you can use in other projects, or any other API of your own choosing, would be a vast improvement for some people.

I know if when starting out with NTai I had to deal with embedding a lua VM or writing a parser, I wouldn't have bothered.

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 19:51
by slind
Now I am on board completely with what you are saying.

Re: Lua <-> AI Generalised message standard proposal

Posted: 09 Jun 2011, 21:01
by AF
Spec V2

Here's my proposal of generalised standard lua <-> AI message passing. I will use the example of passing a message intended for a gadget that prints out messages to the console via lua.

Sending multiple messages

Code: Select all

{
    framesent=64, -- optional for debugging
    messagecount=2, -- optional for debugging
    senderAI="shard", -- optional for debugging
    messages={
        {
            message="printmessage",
            data = {
                consolestring="hello world1"
            }
        },
        {
            message="printmessage",
            data = {
                consolestring="hello world2"
            }
        }
    }
-- etc
    }
}
Messages are to be listed in order of execution/processing by lua, and their order int he messages table determines the order of their replies in the replies table ( see below ).

Returning data
A gadget processing a multiple message string wanting to return data might send the following back:

Code: Select all

{
    replies = {
        {
            returned="success"
        },
        {
            returned="failure",
        }
    },
    messages = {
        -- mesages for the AI
    },
    -- optional errors table
    errors = {
        --
    }
}
Here the indices of messages are tied to their return messages in the replies table, so message 1 will map onto the first reply 1 etc.

Return messages take the same format as those being sent, but here the 'message' key/value pair is optional in the reply unless necessary as the AI may already know what the message is based on the original message sent.

If no reply is to be sent, then an empty table is to be used as the reply value.

Lua may wish to provide events or messages ro queries of its own, for which the messages table is provided. Lua should not expect a reply unless dictated by a protocol overlaid on this spec.

If lua has nothing to send back, and all messages had no reply other than null, then a null/empty string may be returned.

An optional errors table can be included by lua for the AI, though not necessary. This is purely optional and for debug purposes.

Detection

Detection should not be necessary, as unless the AI has specified an alternate format, lua is to be assumed.

Code: Select all

If first character of string == '{'
Better suggestions that add as minimal overhead and as little to the actual content of the string as possible are welcome.



Implementation points

On the lua gadget side, I envisage there will be a standard gadget that gets shared across all games ( possibly engine bundled ) that processes these messages, and then issues its own callins on other gadgets for handling.

Unsynced widgets

This can be added to such a gadget as mentioned above, perhaps with a message key specifying if the target is Synced or Unsynced code.

Discovery

Early on in the first frame or Init call, an AI should send a message to the gadgets asking for a response with as much information as possible. This response should include the version of the processing gadget, any game information that is not a part of the standard engine archive info, a list of present gadgets, and any AI APIs that the game wishes to expose, with there chosen AI API Identifiers, and version numbers, and what messages they support. A list of possible events should also be returned and the number of parameters.

This message should only need to be sent once, and should not be requested during active gameplay save for when load/save mechanics are employed.

AI Request Mechanics

Early on in the frame processing, the AI should make a request to check if new events have occurred ( e.g. xyz has started a jumpjet, ABC has teleported across the map, or 123 has been turned into a potatoe ). This should ideally be one of the first things done on each frame. The AI may wish to issue other commands in this request in a multiple message table.

The AI should then aim to batch the commands and requests it needs then send all at once to minimize on serialisation/de-serialisation costs, and the cost of messages being routed through the engine API calls.

AIs should aim to send as few single/individual messages, and use the single message format purely as an optimisation to save processing power. This may be unrealistic in some cases, and so the AI should aim to stay within 3 messages per frame.

Messages & AI engine events

Should a message be needed on an event such as abcFinished, or xyzDied, then the message should be queued and sent in the next frame along with the initial request for events message.

Custom code execution

The AI should be able to send a message 'function', which has a parameter function, whose value is a string function that is to be executed in gadget land. It's return values are to be packaged up into the standard gadget return value format. This should allow AIs the ability to execute unsynced commands it otherwise wouldn't be able to, and to be able to interact with gadgets that may not have an AI API.

Lua Format vs others

The syntax of messages sent from AIs to lua must always be lua, with no exceptions.

Lua will always return lua formatted replies, however, an AI may negotiate on startup for an alternative format to be returned. JSON and XML are the likely candidates. No guarantees about the performance of other formats/syntaxes are to be made.