Page 1 of 1

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

Posted: 20 Jun 2011, 22:33
by Kloot
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: Select all

    -- 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: Select all

-- 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);
	}
}


*** WARNING: http://springrts.com/phpbb/viewtopic.ph ... 92#p546792

Re: Lua<-->AI communications

Posted: 20 Jun 2011, 22:44
by cain
wow, passing&parsing lua strings, seriously?

Re: Lua<-->AI communications

Posted: 20 Jun 2011, 22:46
by AF
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?

Re: Lua<-->AI communications

Posted: 21 Jun 2011, 00:40
by Kloot
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.

Re: Lua<-->AI communications

Posted: 21 Jun 2011, 00:51
by knorke
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?

Re: Lua<-->AI communications

Posted: 21 Jun 2011, 00:59
by AF
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?

Re: Lua<-->AI communications [in Spring 0.83+]

Posted: 21 Jun 2011, 13:49
by Kloot
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

Re: Lua<-->AI communications [in Spring 0.83+]

Posted: 21 Jun 2011, 14:35
by AF
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?

Re: Lua<-->AI communications [in Spring 0.83+]

Posted: 21 Jun 2011, 17:55
by Kloot
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.

Re: Lua<-->AI communications

Posted: 01 Apr 2012, 14:59
by FLOZi
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

?

Re: Lua<-->AI communications [in Spring 0.83+]

Posted: 01 Apr 2012, 17:48
by jK
new section after SendLuaMessage