View topic - Lua<-->AI communications [in Spring 0.83+]



All times are UTC + 1 hour


Post new topic Reply to topic  [ 11 posts ] 
Author Message
PostPosted: 20 Jun 2011, 21:33 
Spring Developer

Joined: 08 Oct 2006, 15:58
Listen very carefully, I shall say this only once.

For Spring 0.83+, I have expanded the API to allow full two-way interaction between native (C{++}, Java, Python, ...) AI's and Lua gadgets and widgets. The tools at your disposal are:

Code:
    -- Lua callins (one new, one old, UNSYNCED LUA ONLY)
    -- (RecvSkirmishAIMessage was formerly known as AICallIn)
    gadget:RecvSkirmishAIMessage(number aiTeam, string aiMessage) --> string
    widget:RecvSkirmishAIMessage(number aiTeam, string aiMessage) --> string

    -- Lua callouts (new, UNSYNCED LUA ONLY)
    Spring.SendSkirmishAIMessage(number aiTeam, string aiMessage) -->
        boolean, {[1] = string, [2] = string, ...}

    // legacy C++ callins (new)
    void IGlobalAI::RecvLuaMessage(const char* inData, const char** outData);

    // legacy C++ callouts (one new, one old)
    const char* IAICallback::CallLuaRules(const char* inData, int inSize, int* outSize);
    const char* IAICallback::CallLuaUI(const char* inData, int inSize, int* outSize);


This example is for AI's using the legacy C++ interface (figuring out how to translate it to your wrapper of choice is left as an exercise):

Code:
-- some LuaUI widget
function widget:RecvSkirmishAIMessage(aiTeam, aiMessage)
    func = loadstring(aiMessage)
    if (func ~= nil) then
        func()
    end
    return ""
end

-- some LuaRules gadget
if (gadgetHandler:IsSyncedCode()) then
    function gadget:Explosion(weaponDefID, px, py, pz, ownerID)
        SendToUnsynced("Explosion", px, py, pz)
    end
else
    local function HandleExplosion(...)
        local x = arg[3]
        local y = arg[4]
        local z = arg[5]
        local aiTeam = 1
        local aiMessage = "t = {" ..
            "msgID=\"Explosion\"" .. ", " ..
            "x=" .. x .. ", " ..
            "y=" .. y .. ", " ..
            "z=" .. z .. ", " ..
        "}"
        Spring.SendSkirmishAIMessage(aiTeam, aiMessage)
    end

    local eventMap = {Explosion = HandleExplosion}

    function gadget:RecvFromSynced(...)
        local eventName = arg[2]

        if (eventMap[eventName] ~= nil) then
            eventMap[eventName](...)
        end
    end
end



// AI code
void AI::UnitDestroyed(int unitID, int attackerID) {
    static char buffer[1024];

    const float3& unitPos = callback->GetUnitPosition(unitID);
    const char* luaString = "Spring.MarkerAddPoint(%f, %f, %f, \"AI: unit %d was here\")";

    snprintf(buffer, 1024, luaString, pos.x, pos.y, pos.z, unitID);
    callback->CallLuaUI(buffer, -1, NULL);
}

void AI::RecvLuaMessage(const char* inData, const char** outData) {
   const LuaTable& table = LuaParser::Parse(inData);
   if (table.GetValue<std::string>("msgID") == "Explosion") {
       const float x = table.GetValue<float>("x");
       const float y = table.GetValue<float>("y");
       const float z = table.GetValue<float>("z");
       intelHandler->Explosion(x, y, z);
   }
}


Last edited by Kloot on 02 Feb 2012, 01:19, edited 7 times in total.

Top
 Offline Profile  
 
PostPosted: 20 Jun 2011, 21:44 
AI Coder

Joined: 09 Aug 2005, 09:04
wow, passing&parsing lua strings, seriously?


Top
 Offline Profile  
 
PostPosted: 20 Jun 2011, 21:46 
AI Coder
User avatar

Joined: 14 Sep 2004, 10:32
Location: Cookieland
If you look at the AI gadget standardisation thread you'll see why his example uses lua strings =p

Kloot, thanks for this, what are the performance overheads on this API?


Top
 Offline Profile  
 
PostPosted: 20 Jun 2011, 23:40 
Spring Developer

Joined: 08 Oct 2006, 15:58
The cost of paSsing a message from either end to the other is the same as that of any regular callin or callout, plus the time needed to cross the border from the engine into or out of Lua land (which mostly gets taken up by stack management).

The cost of paRsing a message is much more significant (Lua's loadstring _compiles_ code on the fly, and on the AI side your LuaParser implementation will probably use luaL_loadstring which just runs the same algorithms). That means you need to batch and keep crosstalk to a minimum.


Top
 Offline Profile  
 
PostPosted: 20 Jun 2011, 23:51 
Moderator
User avatar

Joined: 22 Feb 2006, 01:02
Location: cheap kitchen
Kloot wrote:
Listen very carefully, I shall say this only once.
Would you (or anybody else who is familiar with AI stuff) mind putting that into the wiki?


Top
 Offline Profile  
 
PostPosted: 20 Jun 2011, 23:59 
AI Coder
User avatar

Joined: 14 Sep 2004, 10:32
Location: Cookieland
Kloot wrote:
The cost of paRsing a message is much more significant (Lua's loadstring _compiles_ code on the fly, and on the AI side your LuaParser implementation will probably use luaL_loadstring which just runs the same algorithms). That means you need to batch and keep crosstalk to a minimum.


Would a different data format such as json or xml be faster in this regard due to the lack of compilation? Or would it be exchanging one overhead for another?


Top
 Offline Profile  
 
PostPosted: 21 Jun 2011, 12:49 
Spring Developer

Joined: 08 Oct 2006, 15:58
It depends on what a JSON parser does under the hood to turn strings back into JavaScript objects (a really bad implementation could just call eval, which is the JS interpreter equivalent of Lua's loadstring), but the process is probably more lightweight than for Lua. The JSON object representation is also fairly close to how a Lua table would look in string form (unlike any XML scheme), so that simplifies writing** the Lua-side (de)serialization code.

** there already are bidirectional (encoding&decoding) JSON parser modules available for Lua, see eg. http://json.luaforge.net


Top
 Offline Profile  
 
PostPosted: 21 Jun 2011, 13:35 
AI Coder
User avatar

Joined: 14 Sep 2004, 10:32
Location: Cookieland
I mean from a C++ perspective. Java should be able to load json data quite efficiently in comparison to anything C/C++ or lua could muster anyway.

In principle, since the json or xml parser needs only to pick apart the datas structure and assign a dom or OO representation in the native language, is this always going to have an advantage performance wise over lua strings pushed through lua into bytecode and out back through the lua API?


Top
 Offline Profile  
 
PostPosted: 21 Jun 2011, 16:55 
Spring Developer

Joined: 08 Oct 2006, 15:58
In most cases yes, because that (pulling the string apart into some internal tree representation) is just a basic form of lexing & parsing, which a compiler also has to do _plus a lot more_ to produce (byte / machine)code.

Reading any kind of XML format still involves copious amounts of string operations though which are never exactly fast, so avoid that.


Top
 Offline Profile  
 
PostPosted: 01 Apr 2012, 13:59 
Moderator
User avatar

Joined: 29 Apr 2005, 00:14
Location: #moddev - join it!
knorke wrote:
Kloot wrote:
Listen very carefully, I shall say this only once.
Would you (or anybody else who is familiar with AI stuff) mind putting that into the wiki?


In the process of updating the wiki with a whole heap of stuff since 83, kloot, where is the best place to put SendSkirmishAIMessage?

http://springrts.com/wiki/Lua_UnsyncedCtrl#SendMessage

http://springrts.com/wiki/Lua_UnsyncedC ... LuaMessage

http://springrts.com/wiki/Lua_UnsyncedCtrl#Misc

?


Top
 Offline Profile  
 
PostPosted: 01 Apr 2012, 16:48 
Spring Developer
User avatar

Joined: 28 Jun 2007, 06:30
new section after SendLuaMessage


Top
 Offline Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group

Site layout created by Roflcopter et al.