Pushing an Array of Tables to Lua From Java Plugin

Hello Corona Gurus,

This weekend I really buckled down and spent a good 8 hours seeing how involved an Amazon Game Circle plugin was.  I have successfully implemented a great deal of the leaderboard functionality.  I still have an outstanding question concerning the manifest, which I posted here.  Additionally I have another question.

Presently I am able to return the current player score to the LUA module via a table.  So the result you get in your LUA listener looks like this: 

local msg

if (event.name == “get_your_score_from_leaderboard”) then

      msg=“score:”…event.response.score…" rank:"…event.response.rank

      native.showAlert( event.name, msg, { “OK” } )

end

I accomplish that with the following java dispatch event code:

final LuaState luaState = coronaRuntime.getLuaState();

CoronaLua.newEvent(luaState, eventType);

luaState.pushBoolean(false);

luaState.setField(-2, CoronaLuaEvent.ISERROR_KEY);

GetPlayerScoreResponse player = (GetPlayerScoreResponse) result;

luaState.newTable(0, 3);

int idx = luaState.getTop();

luaState.pushString(“local_player”);

luaState.setField(idx, “name”);

luaState.pushNumber(player.getScoreValue());

luaState.setField(idx, “score”);

luaState.pushNumber(player.getRank());

luaState.setField(idx, “rank”);

luaState.setField(-2, CoronaLuaEvent.RESPONSE_KEY);

CoronaLua.dispatchEvent(luaState, amazonGamesClientListener, 0);

 

But now I need to return an array of tables in event.response that represents the scores of multiple players. So instead of accessing the data in LUA as: event.response.score something more like: event.response.player[n].score (and of course an event.response.length).

 

I really don’t have a good idea how to make that happen.  I’d appreciate any hints.  Right now I have implemented the following plugin functions for Amazon’s GameCircle:

 

initialize(listener)

showLeaderboards()

postScoreToLeaderboard(leaderboardId, score)

getLocalPlayerScore(leaderboardId)

getAllPlayersScores(leaderboardId)

 

It’s the last call that I need to return the array of tables for.  I have the data ready to go in the Java layer, just need to package it up and ship it off to LUA.  My hope is next weekend to knock out achievements and then see if there is any interest from the folks at Corona of just adding the plugin to the general build so we can all use it from the Pro SDK.  If not I guess I will have to convert my trial of the Enterprise edition to a paid version and then I will have to charge for the plugin to try and recoup some of my cash :slight_smile:

 

This is how you would do it from C, you should be able to get some implementation tips from it though.http://lua-users.org/lists/lua-l/2009-10/msg00417.html

@TheBrooster I appreciate the link.  Looks like it should get me going.  Will be tomorrow before I get to give it a try but will definitely let you know.

@TheBrooster  Thanks!  The link you sent was a big help and I have it working now.

No problem. I was going to tackle the Amazon GameCircle next, would be interested in taking a look at your implementation. Could send you my Amazon Ads implementation, if you are interested? PM me at bruce@binarypumpkin.com if you want GameCircle tested??

@TheBrooster  I have a few more items I am trying to clean up in the plugin and then I will just attach the source to this forum for anyone who wants it.  If you want to share your ads implementation privately you can reach me via admin@cluckeyetea.com.  No hurry.  It will be at least Sunday before I am ready to post my plugin.

I’ve been scouring the web for a couple days now but haven’t been able to
get it worked out. I made some good headway thanks the link @TheBrooster
shared.  I’ve got event, response, leaderboard, count, and desc going.

But now I am trying to nest an array of tables called score and I’m still not quite there. 

My goal is to return a response to the lua program that looks something like
this:

{event { response { leaderboard { desc = “xyz”, count = 2, scores{ {alias =
“player1”, score = 200}, {alias=“player2”, score=100} }}}}}}

But the nested tables are killing me. This is what I have right now.

if (eventType.equals(EVENT_TYPE_GET_ALL_SCORES_FROM_LEADERBOARD)) {
        luaState.newTable(0, 4);
        int idx = luaState.getTop();
        luaState.pushString(“leaderboard”);
        luaState.setField(idx, “name”);
        Leaderboard leaderboard = ((GetScoresResponse)result).getLeaderboard();
        String leaderboardName = leaderboard.getDisplayText();
        luaState.pushString(leaderboardName);
        luaState.setField(idx, “desc”);
        int num = ((GetScoresResponse)result).getNumScores();
        luaState.pushNumber(num);
        luaState.setField(idx, “count”);
        List<Score> scores = ((GetScoresResponse)result).getScores();
        luaState.newTable(0, scores.size()+1);
        int scoresIdx = luaState.getTop();
        luaState.pushString(“scores”);
        luaState.setField(scoresIdx, “name”);
        int i = 0;
        for (Score score : scores){
            luaState.newTable(0, 5);
            int innerIdx = luaState.getTop();
            Player player = score.getPlayer();
            String alias = player.getAlias();
            String id = player.getPlayerId();
            int rank = score.getRank();
            long points = score.getScoreValue();
            luaState.pushString(alias);
            luaState.setField(innerIdx, “alias”);
            luaState.pushString(id);
            luaState.setField(innerIdx, “id”);
            luaState.pushNumber(rank);
            luaState.setField(innerIdx, “rank”);
            luaState.pushNumber(points);
            luaState.setField(innerIdx, “score”);
            i++;
            luaState.pushInteger(i);
            luaState.setField(innerIdx, “name”);
        }
        luaState.setField(-2, CoronaLuaEvent.RESPONSE_KEY);
}
CoronaLua.dispatchEvent(luaState, amazonGamesClientListener, 0);

Clearly I just don’t understand how the LuaState stack works here but in my
defense I’ve failed to find any documentation on the website or in the
folders of the SDK demo I am working with. Thanks for any help anyone can spare. 

As I posted previously once I have the GC code all cleaned up I plan to attach it

to this thread for any other Enterprise users who could make use of it.

I’m currently on vacation but am returning home over the weekend. I’ll take a look then

Had a VERY quick look … are you not missing calls to settable after you push your variables?

luaState.pushString(alias);
luaState.setField(innerIdx, “alias”);
luaState.pushString(id);.
…HERE…

http://docs.coronalabs.com/daily/native/android/html/com/naef/jnlua/LuaState.html#setTable(int

@TheBrooster  I appreciate you taking a closer look when you have minute.  I am absolutely sure you are right about me missing a set table call.  But even with the java docs I am just guessing as to how this works.  I’m not able to visualize what this lua stack looks like so I don’t have any good idea what methods should get called when.

Trying to copy the document you linked me to earlier, I was successful in returning a single table like this:

if (eventType.equals(EVENT_TYPE_GET_YOUR_SCORE_FROM_LEADERBOARD)) {

     GetPlayerScoreResponse player = (GetPlayerScoreResponse) result;

     luaState.newTable(0, 3);

     int idx = luaState.getTop();

     luaState.pushString(“local_player”);

     luaState.setField(idx, “name”);

     luaState.pushNumber(player.getScoreValue());

     luaState.setField(idx, “score”);

     luaState.pushNumber(player.getRank());

     luaState.setField(idx, “rank”);

     luaState.setField(-2, CoronaLuaEvent.RESPONSE_KEY);

}

 

The result in my LUA app is {event.response{score=100, rank=1}}  But honestly it was more trial and error than anything.  I’d love to see Corona write a tutorial on how this works that goes beyond the java doc annotations.  I will continue plugging away at it as I get a chance over the weekend and will keep an eye out in case you find some time to show me the light :slight_smile:

Give me until Monday to respond…I am travelling from Tunisia back to the UK tomorrow.

If you reply to this message tomorrow, i will get a notification and will be back at my computer and will post up an example for you.

FYI: http://www.lua.org/pil/24.2.html

As promised, here is an example:

// Event task private static class LuaCallBackListenerTask implements CoronaRuntimeTask&nbsp; { &nbsp; &nbsp; private int fLuaListenerRegistryId; &nbsp; &nbsp; private String fPhase = null; &nbsp; &nbsp; &nbsp; public LuaCallBackListenerTask( int luaListenerRegistryId, String phase )&nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; fLuaListenerRegistryId = luaListenerRegistryId; &nbsp; &nbsp; &nbsp; &nbsp; fPhase = phase; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; @Override &nbsp; &nbsp; public void executeUsing( CoronaRuntime runtime ) &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Fetch the Corona runtime's Lua state. &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final LuaState L = runtime.getLuaState(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Dispatch the lua callback &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ( CoronaLua.REFNIL != fLuaListenerRegistryId )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Create event table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.newTable(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Create event.data table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.newTable(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Key/Value pair &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.pushString( "Hello" ); // Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.setField( -2, "personName" ); // Key &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Another Key/Value pair &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.pushNumber( 28 ); // Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.setField( -2, "age" ); // Key &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Set data table - this becomes event.data from the Lua side (with key value pairs of personName and age, defined above) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.setField( -2, "data" ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Event name - this is set on the outer table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.pushString( "myEventName" ); // Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.setField( -2, "name" ); // Key &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Event Type - this is set on the outer table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.pushString( "myEventType" ); // Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.setField( -2, "type" ); // Key &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Event Phase - this is set on the outer table &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.pushString( fPhase ); // Value &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; L.setField( -2, "phase" ); // Key &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Dispatch the event &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CoronaLua.dispatchEvent( L, fLuaListenerRegistryId, 1 ); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; catch ( Exception ex )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ex.printStackTrace(); &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; } }

@TheBrooster & Gremlin Interactive --> You guys are awesome.

Here is a zip of my GC plugin.  It is implemented inside the default Corona Enterprise template structure.  The main.lua file acts as a container to test out the functionality.  It is not all inclusive by any means but I have all the leaderboard and achievement functionality is in place that I require for my current Kindle Fire project.  I haven’t done a whole lot of testing at this point so expect to run into some bugs along the way.

If you want to pull down the source I’ve uploaded it here for the time being: http://www.thingerjiggy.com/downloads/AGC.zip

If it makes since at some point I can make it into a bitbucket repo but right now I just need to get it into my own project and back on schedule to meet my commitments.  Thanks again everyone for helping me out with this.

Glad to hear it is all up and running. I am now back at work, I’ill take a look at the plugin after I have caught up on things here, probably first thing next week.

Nice one!

This is how you would do it from C, you should be able to get some implementation tips from it though.http://lua-users.org/lists/lua-l/2009-10/msg00417.html

@TheBrooster I appreciate the link.  Looks like it should get me going.  Will be tomorrow before I get to give it a try but will definitely let you know.

@TheBrooster  Thanks!  The link you sent was a big help and I have it working now.

No problem. I was going to tackle the Amazon GameCircle next, would be interested in taking a look at your implementation. Could send you my Amazon Ads implementation, if you are interested? PM me at bruce@binarypumpkin.com if you want GameCircle tested??