Google Play Game Services - Some questions

Hi guys, 

I’d like to use gpgs but I’ve got some questions.

  • First of all will these two plugins work with each other?

    [“plugin.google.play.services”] = { publisherId = “com.coronalabs”, supportedPlatforms = { android=true } }, [“plugin.gpgs”] = { publisherId = “com.coronalabs”, supportedPlatforms = {android=true} },

The “plugin.gpgs” is for the leaderboards etc, but the only reason I’m adding the first plugin is because it was require if you are using plugins like Flurry and Applovin. It’s probably a silly question, because I’m pretty sure it would work but I’d just like to get some confirmation :slight_smile:

  • My second question is about a piece of code to save games using snapshots,:

    local function gpgsSnapshotAfterSaveListener( event ) native.showAlert( “Snapshots”, "Saving was " … ( event.isError and “unsuccessful” or “successful” ) … “.”, { “OK” } ) end local function gpgsSnapshotOpenForSaveListener( event ) if not event.isError then event.snapshot.contents.write( data ) – Write new data as a JSON string into the snapshot gpgs.snapshots.save({ snapshot = event.snapshot, description = "Save slot " … snapshotFilename, listener = gpgsSnapshotAfterSaveListener }) end end gpgs.snapshots.open({ – Open the save slot filename = snapshotFilename, create = true, – Create the snapshot if it’s not found listener = gpgsSnapshotOpenForSaveListener })

In the event.snapshot.contents.write function you have to pass in a JSON string, but I’m not entirely sure if it’s the same as a JSON table or not. I’m using Rob Miracle’s loadsave module and would like to get that data into the snapshot, how would I do that? The module saves a lua table to a json table and places it into the Documents folder of your app :slight_smile:

Thanks guys :slight_smile:

Okay so I tried doing this:

function gpgsLoginListener( event ) print( "Login event:", json.prettify(event) ) if event.phase == "logged in" then gpgs.snapshots.open({ -- Open the save slot filename = "roundySaveFile", create = true, -- Create the snapshot if it's not found listener = gpgsSnapshotOpenForSaveListener }) end end function gpgsInitListener( event ) if not event.isError then -- Try to automatically log in the user without displaying the login screen gpgs.login( { listener = gpgsLoginListener, userInitiated = true } ) end end gpgs.init( gpgsInitListener ) function gpgsSnapshotAfterSaveListener( event ) native.showAlert( "Snapshots", "Saving was " .. ( event.isError and "unsuccessful" or "successful" ) .. ".", { "OK" } ) end function gpgsSnapshotOpenForSaveListener( event ) local jsonPath = system.pathForFile( "settings.json", system.DocumentsDirectory ) if not event.isError then event.snapshot.contents.write( jsonPath ) -- Write new data as a JSON string into the snapshot gpgs.snapshots.save({ snapshot = event.snapshot, description = "Save slot " .. snapshotFilename, listener = gpgsSnapshotAfterSaveListener }) end end

But it’s doing nothing. I adjusted my build.settings and my config file with the correct keys. Am I doing something wrong?

Hi Bram,

I’m sure you already saw the recent tutorial on snapshots:

https://coronalabs.com/blog/2016/11/22/google-play-games-services-update-and-how-to-use-snapshots/

For writing to snapshots, it just needs a string. Internally a “JSON table” is still a string, at least as far as Corona/Lua is concerned. We simply suggest you use JSON if you want to convert a Lua table into a string for snapshots, then (later) re-convert (json.decode()) that JSON string back into a Lua table.

As for your code, when it comes to these kind of projects where there are different functions that need to succeed before they call another function, all leading toward some end result, I think it’s best to add print() statements in as many places as possible throughout to try to determine exactly where it might be failing or not proceeding to the next expected step in the process.

Best regards,

Brent

Hi Brent, thank you for making the json part clear, but the loadsave module saves a json table so I should be able to use that without a problem right? :slight_smile:

Also, I added some print statement and my code is looking like this at the moment:

function gpgsLoginListener( event ) print( "Login event:", json.prettify(event) ) print("login triggered") if event.phase == "logged in" then gpgs.snapshots.open({ -- Open the save slot filename = "roundySaveFile", create = true, -- Create the snapshot if it's not found listener = gpgsSnapshotOpenForSaveListener }) end end function gpgsInitListener( event ) if not event.isError then -- Try to automatically log in the user without displaying the login screen print("logging in") gpgs.login( { listener = gpgsLoginListener, userInitiated = true } ) else print("error logging in: " .. event.errorMessage) end end gpgs.init( gpgsInitListener )

So the print(“logging in”) statement is firing so the gpgs.login function should also be triggered but it is not doing anything for me. The print statement in my login listener are also not firing off so I’m getting the feeling that it is not assigning that listener correctly. But I really don’t see why :( 

Any ideas? 

The problem is here:
 

 local jsonPath = system.pathForFile( "settings.json", system.DocumentsDirectory ) if not event.isError then event.snapshot.contents.write( jsonPath ) -- Write new data as a JSON string into the snapshot

jsonPath is in effect a file name and directory. It’s not the contents of the file. You would still have to do a file open, a read from the file and a close to get the saved JSON string. But if your table that you’re saving is named:   mySettings

Then it’s just as easy to do:

event.snapshot.contents.write( json.encode( mySettings ) )

and not mess with trying to read the saved data table back in since you should still have that Lua table in memory.

Rob

Hi Rob,

So I changed that function to this:

function gpgsSnapshotOpenForSaveListener( event ) local jsonPath = system.pathForFile( "settings.json", system.DocumentsDirectory ) if not event.isError then event.snapshot.contents.write( json.encode(jsonPath) ) -- Write new data as a JSON string into the snapshot gpgs.snapshots.save({ snapshot = event.snapshot, description = "Save slot " .. snapshotFilename, listener = gpgsSnapshotAfterSaveListener }) end end

But the function is never triggered for some reason. The only bit of code that is executed is the print statement in the “gpgsInitListener”, none of the print statements in the gpgsLoginListener are executed  :unsure:

Well your snapshots are not going to work until you get logged in. Please look in your device’s console log for any messages from from GPGS. That means if you’re running “adb logcat” don’t add any extra parameters looking for Corona messages, you have to see the GPGS activity.

Rob

Hi Rob, 

I did that but I’m getting a lot of errors, could you take a look at them because I’ve got no idea on how to fix them :confused:

12-02 01:11:26.192 8704 8752 I Corona : has connection: true 12-02 01:11:26.192 8704 8752 D libGLESv2: DTS\_GLAPI : DTS is not allowed for Package : com.opportunitiesgames.Roundy 12-02 01:11:26.202 8704 8752 I Corona : nil 12-02 01:11:26.202 8704 8752 I Corona : logging in 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.inte rnal.zzqe\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.inte rnal.zzqe\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.inte rnal.zzqc$zza\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.inte rnal.zzqc$zza\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$BaseGamesApiMethodImpl\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$BaseGamesApiMethodImpl\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$GetServerAuthCodeImpl\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$GetServerAuthCodeImpl\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$4\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$4\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$BaseGamesApiMethodImpl\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$SignOutImpl\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$SignOutImpl\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$5\> 12-02 01:11:26.202 8704 8752 I art : Rejecting re-init on previously-failed class java.lang.Class\<com.google.android.gms.game s.Games$5\> 12-02 01:11:26.212 8704 8752 W System.err: com.naef.jnlua.LuaRuntimeException: java.lang.NoSuchMethodError: No direct method \<ini t\>(Ljava/lang/String;Lcom/google/android/gms/common/api/Api$zza;Lcom/google/android/gms/common/api/Api$zzf;)V in class Lcom/google/ android/gms/common/api/Api; or its super classes (declaration of 'com.google.android.gms.common.api.Api' appears in /data/app/com.o pportunitiesgames.Roundy-2/base.apk:classes2.dex) 12-02 01:11:26.212 8704 8752 W System.err: Java Stack Trace: 12-02 01:11:26.212 8704 8752 W System.err: com.google.android.gms.games.Games.\<clinit\>(Unknown Source) 12-02 01:11:26.212 8704 8752 W System.err: plugin.gpgs.Connector.init(Connector.java:67) 12-02 01:11:26.212 8704 8752 W System.err: plugin.gpgs.LuaLoader.login(LuaLoader.java:170) 12-02 01:11:26.212 8704 8752 W System.err: plugin.gpgs.LuaLoader.access$2200(LuaLoader.java:43) 12-02 01:11:26.212 8704 8752 W System.err: plugin.gpgs.LuaLoader$LoginWrapper.invoke(LuaLoader.java:707) 12-02 01:11:26.212 8704 8752 W System.err: com.naef.jnlua.LuaState.lua\_pcall(Native Method) 12-02 01:11:26.212 8704 8752 W System.err: com.naef.jnlua.LuaState.call(Unknown Source) 12-02 01:11:26.212 8704 8752 W System.err: com.ansca.corona.CoronaLua.dispatchEvent(CoronaLua.java:138) 12-02 01:11:26.212 8704 8752 W System.err: plugin.gpgs.LuaUtils$1.executeUsing(LuaUtils.java:91) 12-02 01:11:26.212 8704 8752 W System.err: com.ansca.corona.CoronaRuntimeTaskDispatcher$TaskEvent.Send(CoronaRuntimeTaskDispat cher.java:170) 12-02 01:11:26.212 8704 8752 W System.err: com.ansca.corona.events.EventManager.sendEvents(EventManager.java:91) 12-02 01:11:26.212 8704 8752 W System.err: com.ansca.corona.Controller.updateRuntimeState(Controller.java:308) 12-02 01:11:26.212 8704 8752 W System.err: com.ansca.corona.graphics.opengl.CoronaGLSurfaceView$CoronaRenderer.onDrawFrame(Cor onaGLSurfaceView.java:421) 12-02 01:11:26.212 8704 8752 W System.err: com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.ja va:1623) 12-02 01:11:26.212 8704 8752 W System.err: com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1378 ) 12-02 01:11:26.212 8704 8752 W System.err: at com.naef.jnlua.LuaState.lua\_pcall(Native Method) 12-02 01:11:26.212 8704 8752 W System.err: at com.naef.jnlua.LuaState.call(Unknown Source) 12-02 01:11:26.212 8704 8752 W System.err: at com.ansca.corona.CoronaLua.dispatchEvent(CoronaLua.java:138) 12-02 01:11:26.212 8704 8752 W System.err: at plugin.gpgs.LuaUtils$1.executeUsing(LuaUtils.java:91) 12-02 01:11:26.212 8704 8752 W System.err: at com.ansca.corona.CoronaRuntimeTaskDispatcher$TaskEvent.Send(CoronaRuntimeTaskDis patcher.java:170) 12-02 01:11:26.212 8704 8752 W System.err: at com.ansca.corona.events.EventManager.sendEvents(EventManager.java:91) 12-02 01:11:26.212 8704 8752 W System.err: at com.ansca.corona.Controller.updateRuntimeState(Controller.java:308) 12-02 01:11:26.212 8704 8752 W System.err: at com.ansca.corona.graphics.opengl.CoronaGLSurfaceView$CoronaRenderer.onDrawFrame( CoronaGLSurfaceView.java:421) 12-02 01:11:26.212 8704 8752 W System.err: at com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView .java:1623) 12-02 01:11:26.212 8704 8752 W System.err: at com.ansca.corona.graphics.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1 378)

I’ll get an engineer to look at this. But make sure you have everything setup correctly on line. Make sure you’re testing with a non-developer gmail account. GPGS has a lot of setup and testing requirements. 

Rob

Thanks Rob, be sure to let me know!

bramvbilsen, hi, do you still have “plugin.google.play.services” in build.settings? Can you please try removing it?

Hi Lerg,

it just force closes when I delete that. I needed that plugin for my “flurry” plugin and “applovin” plugin :confused:

I’m getting this log when the app starts:

12-02 12:50:13.635 5001 5001 W ResourcesManager: getTopLevelResources: /data/app/com.google.android.play.games-2/base.apk / 1.0 running in com.google.android.gms rsrc of package com.google.android.play.games 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: Handling ConnectionFailedException 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: lxo: Unable to resolve account name. 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: at lxn.a(:com.google.android.gms:6377) 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: at iws.run(:com.google.android.gms:197) 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: at kyl.run(:com.google.android.gms:450) 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: at lco.run(:com.google.android.gms:17) 12-02 12:50:13.635 5001 25935 E ClientConnectionOperation: at java.lang.Thread.run(Thread.java:818) 12-02 12:50:13.635 3171 3729 D EnterpriseController: netId is 0 12-02 12:50:13.635 3171 3729 D Netd : getNetworkForDns: using netid 641 for uid 10275 12-02 12:50:13.645 5001 25467 E ValidateServiceOp: Application ID (104901808610) must be a numeric value. Please verify that your manifest refers to the correct project ID. 12-02 12:50:13.645 25317 25317 D AndroidRuntime: Shutting down VM 12-02 12:50:13.645 25317 25317 W System.err: java.lang.IllegalStateException: A fatal developer error has occurred. Check the logs for further information. 12-02 12:50:13.645 25317 25317 W System.err: at com.google.android.gms.common.internal.zze$zza.zzc(Unknown Source) 12-02 12:50:13.645 25317 25317 W System.err: at com.google.android.gms.common.internal.zze$zza.zzv(Unknown Source) 12-02 12:50:13.645 25317 25317 W System.err: at com.google.android.gms.common.internal.zze$zze.zzauc(Unknown Source) 12-02 12:50:13.645 25317 25317 W System.err: at com.google.android.gms.common.internal.zze$zzd.handleMessage(Unknown Source) 12-02 12:50:13.645 25317 25317 W System.err: at android.os.Handler.dispatchMessage(Handler.java:102) 12-02 12:50:13.645 25317 25317 W System.err: at android.os.Looper.loop(Looper.java:158) 12-02 12:50:13.645 25317 25317 W System.err: at android.app.ActivityThread.main(ActivityThread.java:7229) 12-02 12:50:13.645 25317 25317 W System.err: at java.lang.reflect.Method.invoke(Native Method) 12-02 12:50:13.645 25317 25317 W System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 12-02 12:50:13.645 25317 25317 W System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: FATAL EXCEPTION: main 12-02 12:50:13.645 25317 25317 E AndroidRuntime: Process: com.opportunitiesgames.Roundy, PID: 25317 12-02 12:50:13.645 25317 25317 E AndroidRuntime: java.lang.IllegalStateException: A fatal developer error has occurred. Check the logs for further information. 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at com.google.android.gms.common.internal.zze$zza.zzc(Unknown Source) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at com.google.android.gms.common.internal.zze$zza.zzv(Unknown Source) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at com.google.android.gms.common.internal.zze$zze.zzauc(Unknown Source) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at com.google.android.gms.common.internal.zze$zzd.handleMessage(Unknown Source) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at android.os.Looper.loop(Looper.java:158) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:7229) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 12-02 12:50:13.645 25317 25317 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 12-02 12:50:13.645 25317 25402 W FlurryAgent: Flurry session ended 12-02 12:50:13.645 3492 3973 W ActivityManager: Force finishing activity com.opportunitiesgames.Roundy/com.ansca.corona.CoronaActivity

I am afraid at this point you have to choose between flurry+apploving and the new gpgs plugin until we resolve all dependency issues with the old plugins.

Hi Lerg, any information on when that’d be? And are there some good alternatives that you know of?

Thanks for the help!

bramvbilsen, that is being worked on, can’t provide any specific dates. For ads you can use Corona Ads, for analytics there are several options like Kochava or GameAnalytics.

I was planning on using Corona Ads but no video interstitials are available at the moment :frowning:

Okay so I tried doing this:

function gpgsLoginListener( event ) print( "Login event:", json.prettify(event) ) if event.phase == "logged in" then gpgs.snapshots.open({ -- Open the save slot filename = "roundySaveFile", create = true, -- Create the snapshot if it's not found listener = gpgsSnapshotOpenForSaveListener }) end end function gpgsInitListener( event ) if not event.isError then -- Try to automatically log in the user without displaying the login screen gpgs.login( { listener = gpgsLoginListener, userInitiated = true } ) end end gpgs.init( gpgsInitListener ) function gpgsSnapshotAfterSaveListener( event ) native.showAlert( "Snapshots", "Saving was " .. ( event.isError and "unsuccessful" or "successful" ) .. ".", { "OK" } ) end function gpgsSnapshotOpenForSaveListener( event ) local jsonPath = system.pathForFile( "settings.json", system.DocumentsDirectory ) if not event.isError then event.snapshot.contents.write( jsonPath ) -- Write new data as a JSON string into the snapshot gpgs.snapshots.save({ snapshot = event.snapshot, description = "Save slot " .. snapshotFilename, listener = gpgsSnapshotAfterSaveListener }) end end

But it’s doing nothing. I adjusted my build.settings and my config file with the correct keys. Am I doing something wrong?

Hi Bram,

I’m sure you already saw the recent tutorial on snapshots:

https://coronalabs.com/blog/2016/11/22/google-play-games-services-update-and-how-to-use-snapshots/

For writing to snapshots, it just needs a string. Internally a “JSON table” is still a string, at least as far as Corona/Lua is concerned. We simply suggest you use JSON if you want to convert a Lua table into a string for snapshots, then (later) re-convert (json.decode()) that JSON string back into a Lua table.

As for your code, when it comes to these kind of projects where there are different functions that need to succeed before they call another function, all leading toward some end result, I think it’s best to add print() statements in as many places as possible throughout to try to determine exactly where it might be failing or not proceeding to the next expected step in the process.

Best regards,

Brent

Hi Brent, thank you for making the json part clear, but the loadsave module saves a json table so I should be able to use that without a problem right? :slight_smile:

Also, I added some print statement and my code is looking like this at the moment:

function gpgsLoginListener( event ) print( "Login event:", json.prettify(event) ) print("login triggered") if event.phase == "logged in" then gpgs.snapshots.open({ -- Open the save slot filename = "roundySaveFile", create = true, -- Create the snapshot if it's not found listener = gpgsSnapshotOpenForSaveListener }) end end function gpgsInitListener( event ) if not event.isError then -- Try to automatically log in the user without displaying the login screen print("logging in") gpgs.login( { listener = gpgsLoginListener, userInitiated = true } ) else print("error logging in: " .. event.errorMessage) end end gpgs.init( gpgsInitListener )

So the print(“logging in”) statement is firing so the gpgs.login function should also be triggered but it is not doing anything for me. The print statement in my login listener are also not firing off so I’m getting the feeling that it is not assigning that listener correctly. But I really don’t see why :( 

Any ideas? 

The problem is here:
 

 local jsonPath = system.pathForFile( "settings.json", system.DocumentsDirectory ) if not event.isError then event.snapshot.contents.write( jsonPath ) -- Write new data as a JSON string into the snapshot

jsonPath is in effect a file name and directory. It’s not the contents of the file. You would still have to do a file open, a read from the file and a close to get the saved JSON string. But if your table that you’re saving is named:   mySettings

Then it’s just as easy to do:

event.snapshot.contents.write( json.encode( mySettings ) )

and not mess with trying to read the saved data table back in since you should still have that Lua table in memory.

Rob