How to implement GPGS plugin

Hi everyone   :slight_smile:

_ UPDATED: 03/10/2017  _

After going through this tutorial you will be able to implement Google Play Game Services (GPGS) with the following functionalities:

  • Successful sign up/sign in
  • Achievements
  • Leaderboards
  • Cloud syncing across devices
  • License check

First activate the GPGS plugin from Corona Marketplace when you are signed in to coronalabs.
Then, set up you Google Play Game Services from your developer console. You can check out this official guide from Google.

NOTE: GPGS does not work for iOS as support has been removed for that platform.

Now comes the coding part, it may look long but it is really very easy to implement the GPGS plugin.

-build.settings

You get your googlePlayGamesAppId when you press the ADD NEW GAME to create a service for your new game in your developer console under Game services. Once you complete the procedure you should get the number under your game name. REMEMBER to create the game application at first then game services since game services needs to be linked to your application.

android = {                   usesPermissions = {                                       "com.android.vending.CHECK\_LICENSE",                   },                        googlePlayGamesAppId = "GET YOUR APP ID FROM DEV CONSOLE",                         plugins = {                               ["plugin.gpgs"] = {                                               publisherId = "com.coronalabs",                                                   supportedPlatforms = {android = true}                                                 },                   } }

-config.lua

To find the key for license go to your developer console then select the application from All application tab, then go to Development tools and press Services & APIs. Under Licensing & in-app billing you should get that long RSA public key. 

application = {   license = {     google = {       key = "YOUR APP ID FROM DEVELOPER CONSOLE",       policy = "serverManaged", }, },  }

-main.lua

loadsaveis a module to save table and load table for Lua. You can save you game data easily all in one place. 

local loadsave = require("loadsave") local gpgs = require( "plugin.gpgs" ) local licensing = require( "licensing" ) licensing.init( "google" ) local gpgsData = loadsave.loadTable( "gpgsData.json" ) if ( gpgsData  == nil ) then   gpgsData  = {}   gpgsData.userPref = "logged out"    gpgsData.firstTime = true   gpgsData.firstCheck = true   loadsave.saveTable( gpgsData, "gpgsData.json" ) end -- gpgsData nil conditional END local function gpgsLoginListener( event )   gpgsData.userPref = event.phase   loadsave.saveTable( gpgsData, "gpgsData.json" )     end local function gpgsInitListener( event )   if not event.isError then     -- Try to automatically log in the user with displaying the login screen     if (gpgsData.firstTime == true ) then       gpgs.login( { userInitiated = true, listener = gpgsLoginListener } )       gpgsData.firstTime = false       loadsave.saveTable( gpgsData, "gpgsData.json" )     else       if (gpgsData.userPref == "logged in" ) then         gpgs.login( { listener = gpgsLoginListener } )       elseif (gpgsData.userPref == "logged out") then         -- DO NOTHING                   end -- userPref conditional END     end -- gpgs.firstTime conditional END   end -- event.iserror conditional END end -- gpgsInitListener func END local function licensingListener( event )   if not ( event.isVerified ) then     -- Failed to verify app from the Google Play store; print a message     gameSettings.googLicensed = false     loadsave.saveTable( gameSettings, "gameSettings.json" )     local function onComplete( event )       if ( event.action == "clicked" ) then          local i = event.index         if ( i == 1 ) then           -- Do nothing; dialog will simply dismiss           local appStoreTarget = system.getInfo( "targetAppStore" )           if (appStoreTarget == "google") then             local options =             {               supportedAndroidStores = { "google"}             }             native.showPopup( "appStore", options )           end -- appstore target conditional END         end -- i==1 conditional END       end -- event.action == clicked conditional END     end -- onComplete func END     native.showAlert( "Header", "Your message to your user when licensing fails or when app is not licensed", { "OK(button name)" }, onComplete )     if (gpgs.isConnected()) then       gpgs.logout()       gpgsData.userPref = "logged out"       loadsave.saveTable( gpgsData, "gpgsData.json" )     end --logout user if logged in   else     gameSettings.googLicensed = true     loadsave.saveTable( gameSettings, "gameSettings.json" )     gpgs.init( gpgsInitListener )   end -- not event.isverified conditional END end -- licensinglistener func END if (gameSettings.googLicensed == false or gameSettings.googLicensed == nil) then   licensing.verify( licensingListener )   else   gpgs.init( gpgsInitListener ) end -- licenseCheck if false END

-menuscreen.lua

inGameAnalytics is file name for saving game data. You can choose whatever name you choose for handling your game data. snapshotFileName variable name should be same across all the lua modules in your game.  

local loadsave = require("loadsave") local gpgs = require( "plugin.gpgs" ) local gpgsLoggedInButton local gpgsLoggedOutButton local gpgsData local snapshotFileName = "YOU CAN NAME ANYTHING FOR SAVING GAME DATA" local function toggleGPGSToLogin( self, event ) &nbsp; if ( gpgs.isConnected() ) then &nbsp; &nbsp; gpgsLoggedOutButton.isVisible = false &nbsp; &nbsp; gpgsLoggedInButton.isVisible = true &nbsp; &nbsp; local tempInGameAnalytics = loadsave.loadTable( "inGameAnalytics.json" ) &nbsp; &nbsp; -- download snapshot &nbsp; &nbsp; local function gpgsSnapshotOpenForReadListener( event ) &nbsp; &nbsp; &nbsp; if not event.isError then &nbsp; &nbsp; &nbsp; &nbsp; local retrievedData = event.snapshot.contents.read()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local inGameAnalytics, pos, msg = json.decode( retrievedData ) &nbsp; &nbsp; &nbsp; &nbsp; if not inGameAnalytics then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; toast.show('Decoding failed.' ..tostring(pos)..": "..tostring(msg) )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ( tempInGameAnalytics.totalGamePlayed \< inGameAnalytics.totalGamePlayed ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- save table from the gpgs server &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadsave.saveTable( inGameAnalytics, "inGameAnalytics.json" ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- upload the offline gameplayed to GPGS server &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local inGameAnalytics = loadsave.loadTable( "inGameAnalytics.json" ) -- loading inGameAnalytics from phone &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- save snapshots &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local function gpgsSnapshotOpenForSaveListener( event ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if not event.isError then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event.snapshot.contents.write( json.encode(inGameAnalytics ) )&nbsp; -- Write new data as a JSON string into the snapshot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.save({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; snapshot = event.snapshot, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; description = "Precious", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; image = { filename = "SentioTapEmojiShare.png", baseDir = system.ResourceDirectory }, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- gpgsSnapshotOpenForSaveListener func END &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({&nbsp; -- Open the save slot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create = true,&nbsp; -- Create the snapshot if it's not found &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForSaveListener &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- (tempInGameAnalytics.totalGamePlayed \< inGameAnalytics.totalGamePlayed)&nbsp; conditional END &nbsp; &nbsp; &nbsp; &nbsp; end -- not inGameAnalytics conditional END &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; -- DO NOTHING &nbsp; &nbsp; &nbsp; end -- event.iserror conditional END &nbsp; &nbsp; end --gpgsSnapshotOpenForReadListener func END &nbsp; &nbsp; gpgs.snapshots.open({ &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForReadListener &nbsp; &nbsp; &nbsp; }) &nbsp; end -- gpgs.isConnected() conditional END end -- toggleGPGSToLogin func END local function gpgsLoginListener( event ) &nbsp; gpgsData.userPref = event.phase &nbsp; loadsave.saveTable( gpgsData, "gpgsData.json" ) &nbsp; toggleGPGSToLogin() &nbsp; if event.isError then &nbsp; &nbsp; toast.show('Problem signing in') &nbsp; end -- event.isError conditional END end local function handleButton(event) &nbsp; if (event.target.id == "inGameLeaderboards" and event.phase == "ended") then &nbsp; &nbsp; if (gpgs.isConnected()) then &nbsp; &nbsp; &nbsp; gpgs.leaderboards.show() &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; gpgs.login( { userInitiated = true, listener = gpgsLoginListener } ) &nbsp; &nbsp; &nbsp; gpgs.leaderboards.show() &nbsp; &nbsp; end -- gpgs is connected check outer END &nbsp; elseif (event.target.id == "inGameAchievements" and event.phase == "ended") then &nbsp; &nbsp; if (gpgs.isConnected()) then &nbsp; &nbsp; &nbsp; gpgs.achievements.show() &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; gpgs.login( { userInitiated = true, listener = gpgsLoginListener } ) &nbsp; &nbsp; &nbsp; gpgs.achievements.show() &nbsp; &nbsp; end -- gpgs is connected check outer END &nbsp; end -- button selection conditional END end -- handlebutton func END gpgsData = loadsave.loadTable( "gpgsData.json" ) &nbsp; &nbsp; if ( gpgsData&nbsp; == nil ) then &nbsp; &nbsp; &nbsp; gpgsData&nbsp; = {} &nbsp; &nbsp; &nbsp; gpgsData.userPref = "logged out"&nbsp; &nbsp; &nbsp; &nbsp; gpgsData.firstTime = true &nbsp; &nbsp; &nbsp; gpgsData.firstCheck = true &nbsp; &nbsp; &nbsp; loadsave.saveTable( gpgsData, "gpgsData.json" ) &nbsp; &nbsp; end -- gpgsData nil conditional END local function googVerify () &nbsp; &nbsp; &nbsp; if ( ( gameSettings.googLicensed == true ) and (composer.getSceneName( "current" ) == "menuScreen" ) ) then &nbsp; &nbsp; &nbsp; &nbsp; local inGameLeaderboards = widget.newButton( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id = "inGameLeaderboards", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sheet = mainMenuButtonsImageSheet, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defaultFrame = 5, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; overFrame = 6, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onEvent = handleButton &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; ) &nbsp; &nbsp; &nbsp; &nbsp; sceneGroup:insert(inGameLeaderboards) &nbsp; &nbsp; &nbsp; &nbsp; inGameLeaderboards.x = display.contentWidth \* 0.18 &nbsp; &nbsp; &nbsp; &nbsp; inGameLeaderboards.y = display.contentHeight \* 0.71 &nbsp; &nbsp; &nbsp; &nbsp; inGameLeaderboards:scale(display.contentWidth \* 0.0001, display.contentWidth \* 0.0001) &nbsp; &nbsp; &nbsp; &nbsp; transition.scaleTo( inGameLeaderboards, { xScale= display.contentWidth \* 0.0014, yScale= display.contentWidth \* 0.0014 ,time=100 } ) &nbsp; &nbsp; &nbsp; local inGameAchievements = widget.newButton( &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id = "inGameAchievements", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sheet = mainMenuButtonsImageSheet, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defaultFrame = 1, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; overFrame = 2, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onEvent = handleButton &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; ) &nbsp; &nbsp; &nbsp; &nbsp; sceneGroup:insert(inGameAchievements) &nbsp; &nbsp; &nbsp; &nbsp; inGameAchievements.x = display.contentWidth \* 0.82 &nbsp; &nbsp; &nbsp; &nbsp; inGameAchievements.y = display.contentHeight \* 0.71 &nbsp; &nbsp; &nbsp; &nbsp; inGameAchievements:scale(display.contentWidth \* 0.0001, display.contentWidth \* 0.0001) &nbsp; &nbsp; &nbsp; &nbsp; transition.scaleTo( inGameAchievements, { xScale= display.contentWidth \* 0.0014, yScale= display.contentWidth \* 0.0014 ,time=100 } ) &nbsp; &nbsp; &nbsp; &nbsp; local gpgsLoggedInWidth = mainMenuButtonsSheetInfo.sheet.frames[3].width &nbsp; &nbsp; &nbsp; &nbsp; local gpgsLoggedInHeight = mainMenuButtonsSheetInfo.sheet.frames[3].height &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton = display.newImageRect(mainMenuButtonsImageSheet, 3, gpgsLoggedInWidth, gpgsLoggedInHeight) &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton.isVisible = false &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton.x = display.contentWidth \* 0.50 &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton.y = display.contentHeight \* 0.70 &nbsp; &nbsp; &nbsp; &nbsp; sceneGroup:insert( gpgsLoggedInButton ) &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton:scale(display.contentWidth \* 0.0015, display.contentWidth \* 0.0015) &nbsp; &nbsp; &nbsp; &nbsp; local gpgsLoggedOutWidth = mainMenuButtonsSheetInfo.sheet.frames[4].width &nbsp; &nbsp; &nbsp; &nbsp; local gpgsLoggedOutHeight = mainMenuButtonsSheetInfo.sheet.frames[4].height &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton = display.newImageRect(mainMenuButtonsImageSheet, 4, gpgsLoggedOutWidth, gpgsLoggedOutHeight) &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton.isVisible = false &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton.x = display.contentWidth \* 0.50 &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton.y = display.contentHeight \* 0.70 &nbsp; &nbsp; &nbsp; &nbsp; sceneGroup:insert( gpgsLoggedOutButton ) &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton:scale(display.contentWidth \* 0.0014, display.contentWidth \* 0.0014)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local function gpgsDataSync (self, event) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsData = loadsave.loadTable( "gpgsData.json" ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ( gpgs.isConnected() ) then&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton.isVisible = true &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsData.userPref = "logged in" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadsave.saveTable( gpgsData, "gpgsData.json" ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local tempInGameAnalytics = loadsave.loadTable( "inGameAnalytics.json" ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- download snapshot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local function gpgsSnapshotOpenForReadListener( event ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if not event.isError then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local retrievedData = event.snapshot.contents.read()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local inGameAnalytics, pos, msg = json.decode( retrievedData ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if not inGameAnalytics then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; toast.show('Decoding failed.' ..tostring(pos)..": "..tostring(msg) )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ( tempInGameAnalytics.totalGamePlayed \< inGameAnalytics.totalGamePlayed ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- save table from the gpgs server &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadsave.saveTable( inGameAnalytics, "inGameAnalytics.json" ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- upload the offline gameplayed to GPGS server &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local inGameAnalytics = loadsave.loadTable( "inGameAnalytics.json" ) -- loading inGameAnalytics from phone &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- save snapshots &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local function gpgsSnapshotOpenForSaveListener( event ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if not event.isError then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event.snapshot.contents.write( json.encode(inGameAnalytics ) )&nbsp; -- Write new data as a JSON string into the snapshot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.save({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; snapshot = event.snapshot, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; description = "Precious", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; image = { filename = "SentioTapEmojiShare.png", baseDir = system.ResourceDirectory }, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- gpgsSnapshotOpenForSaveListener func END &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({&nbsp; -- Open the save slot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create = true,&nbsp; -- Create the snapshot if it's not found &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForSaveListener &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- (tempInGameAnalytics.totalGamePlayed \< inGameAnalytics.totalGamePlayed) conditional END &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- not inGameAnalytics conditional END &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -- DO NOTHING&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- event.iserror conditional END &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end --gpgsSnapshotOpenForReadListener func END &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForReadListener &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton.isVisible = true &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- gpgsData.userPref == "logged in" and gpgs.isConnected() conditional END outer &nbsp; &nbsp; &nbsp; &nbsp; end -- gpgsDataSync func END &nbsp; &nbsp; &nbsp; &nbsp; if ( gpgsData.firstCheck == false ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ( gpgs.isConnected() ) then&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton.isVisible = true &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsDataSync() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton.isVisible = true &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsDataSync() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsData.firstCheck = false &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadsave.saveTable( gpgsData, "gpgsData.json" ) &nbsp; &nbsp; &nbsp; &nbsp; end -- first time game opening check to prevent gpgs button overlap &nbsp; &nbsp; &nbsp; &nbsp; local function onGpgsLoginButtonTap( self, event ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (gpgs.isConnected()) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; --logout &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.logout() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsData.userPref = "logged out" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadsave.saveTable( gpgsData, "gpgsData.json" ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton.isVisible = true &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton.isVisible = false &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; --login &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.login( { userInitiated = true, listener = gpgsLoginListener } ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end -- login or logout conditional END &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true &nbsp; &nbsp; &nbsp; &nbsp; end -- onGpgsLoginButtonTap func END &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedInButton:addEventListener( "tap", onGpgsLoginButtonTap ) &nbsp; &nbsp; &nbsp; &nbsp; gpgsLoggedOutButton:addEventListener( "tap", onGpgsLoginButtonTap ) &nbsp; &nbsp; &nbsp; end -- googLicensed END &nbsp; &nbsp; end -- googVerify func END googVerify() -- googVerify function call

-playscreen.lua

local loadsave = require("loadsave") local gpgs = require( "plugin.gpgs" ) local json = require( "json" ) scene:destroy if ( gpgs.isConnected() ) then &nbsp; &nbsp; &nbsp; &nbsp; gpgs.leaderboards.submit( {leaderboardId = "ID FROM DEV CONSOLE" , score = gamescore variable you want to upload } ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.achievements.increment( {achievementId = "ID FROM DEV CONSOLE", steps = 1, } ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (A CONDITIONAL TO ENTER ) then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.achievements.unlock( { achievementId = "ID FROM DEV CONSOLE", } ) &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; gpgs.achievements.increment( {achievementId = "ID FROM DEV CONSOLE", steps = ANY VARIABLE YOU WERE KEEPING TRACK OF, } ) &nbsp; &nbsp; &nbsp; &nbsp; -- save snapshots &nbsp; &nbsp; &nbsp; &nbsp; local snapshotFileName = "SAME NAME OF THE FILE NAME YOU WANT TO SAVE GAME DATA TO" &nbsp; &nbsp; &nbsp; &nbsp; local function gpgsSnapshotOpenForSaveListener( event ) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if not event.isError then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event.snapshot.contents.write( json.encode(inGameAnalytics ) )&nbsp; -- Write new data as a JSON string into the snapshot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.save({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; snapshot = event.snapshot, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; description = "Precious", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; playedTime = system.getTimer(), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; image = { filename = "IMAGE NAME WITH EXTENSION.png", baseDir = system.ResourceDirectory }, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; &nbsp; end -- gpgsSnapshotOpenForSaveListener func END &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({&nbsp; -- Open the save slot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create = true,&nbsp; -- Create the snapshot if it's not found &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForSaveListener &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; end -- gpgs is connected conditional END

-settings.lua

toast plugin allows you to display toast messages to the user. It needs to be activated from the Corona Marketplace to use it.

local loadsave = require("loadsave") local gpgs = require( "plugin.gpgs" ) local json = require( "json" ) local toast = require('plugin.toast') local gpgsData local snapshotFileName = "SAME NAME OF THE FILE GAME DATA IS BEING SAVED TO" local function gpgsLoginListener( event ) &nbsp; gpgsData.userPref = event.phase &nbsp; loadsave.saveTable( gpgsData, "gpgsData.json" ) &nbsp; if event.isError then &nbsp; &nbsp; toast.show('Problem signing in') &nbsp; end -- event.isError conditional END end local function handleButton (event) &nbsp; if (event.target.id == "cloudUpload" and event.phase == "ended") then &nbsp; &nbsp; -- save snapshots &nbsp; &nbsp; local function gpgsSnapshotOpenForSaveListener( event ) &nbsp; &nbsp; &nbsp; if not event.isError then &nbsp; &nbsp; &nbsp; &nbsp; event.snapshot.contents.write( json.encode(inGameAnalytics ) )&nbsp; -- Write new data as a JSON string into the snapshot &nbsp; &nbsp; &nbsp; &nbsp; gpgs.snapshots.save({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; snapshot = event.snapshot, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; description = "Precious", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; image = { filename = "IMAGE NAME WITH EXTENSION.png", baseDir = system.ResourceDirectory }, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; end -- gpgsSnapshotOpenForSaveListener func END &nbsp; &nbsp; if (gpgs.isConnected()) then &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({&nbsp; -- Open the save slot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create = true,&nbsp; -- Create the snapshot if it's not found &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForSaveListener &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.load( {reload = true, }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.show( {title = "TITLE OF TO SHOW", disableAdd = true, }) &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; gpgs.login( { userInitiated = true, listener = gpgsLoginListener } ) &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({&nbsp; -- Open the save slot &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create = true,&nbsp; -- Create the snapshot if it's not found &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForSaveListener &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.load( {reload = true, }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.show( {title = "TITLE TO SHOW", disableAdd = true, }) &nbsp; &nbsp; end -- gpgs is connected check outer END &nbsp; elseif (event.target.id == "cloudDownload" and event.phase == "ended") then &nbsp; &nbsp; -- download snapshot &nbsp; &nbsp; local function gpgsSnapshotOpenForReadListener( event ) &nbsp; &nbsp; &nbsp; if not event.isError then &nbsp; &nbsp; &nbsp; &nbsp; local retrievedData = event.snapshot.contents.read()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local inGameAnalytics, pos, msg = json.decode( retrievedData ) &nbsp; &nbsp; &nbsp; &nbsp; if not inGameAnalytics then &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; toast.show('Decoding failed.' ..tostring(pos)..": "..tostring(msg) )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loadsave.saveTable( inGameAnalytics, "inGameAnalytics.json" ) &nbsp; &nbsp; &nbsp; &nbsp; end &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; -- DO NOTHING &nbsp; &nbsp; &nbsp; end -- event.iserror conditional END &nbsp; &nbsp; end --gpgsSnapshotOpenForReadListener func END &nbsp; &nbsp; if (gpgs.isConnected()) then &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForReadListener &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.load( {reload = true, }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.show( {title = "SentioTap Emoji", disableAdd = true, }) &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; gpgs.login( { userInitiated = true, listener = gpgsLoginListener } ) &nbsp; &nbsp; &nbsp; gpgs.snapshots.open({ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; filename = snapshotFileName, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conflictPolicy = "most recently modified", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; listener = gpgsSnapshotOpenForReadListener &nbsp; &nbsp; &nbsp; &nbsp; }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.load( {reload = true, }) &nbsp; &nbsp; &nbsp; gpgs.snapshots.show( {title = "SentioTap Emoji", disableAdd = true, }) &nbsp; &nbsp; end -- gpgs.isconnected END &nbsp; end -- button choosing conditional END end -- handleButton func END scene:show if (gameSettings.googLicensed == true) then &nbsp; &nbsp; &nbsp; local cloudUpload = widget.newButton( &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id = "cloudUpload", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sheet = settingButtonsImageSheet , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defaultFrame = 3, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; overFrame = 4, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; label = translations["Save"][language], &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fontSize = 30, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; labelYOffset = 90, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; font = native.systemFont, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; labelColor = { default={ 0.9, 0, 0.42 }, over={ 0.9, 0, 0.42, 0.6 } }, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onEvent = handleButton &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; ) &nbsp; &nbsp; &nbsp; -- Center the button &nbsp; &nbsp; &nbsp; sceneGroup:insert(cloudUpload) &nbsp; &nbsp; &nbsp; cloudUpload.x = display.contentWidth \* 0.20 &nbsp; &nbsp; &nbsp; cloudUpload.y = display.contentHeight \* 0.30 &nbsp; &nbsp; &nbsp; cloudUpload:scale(display.contentWidth \* 0.002, display.contentWidth \* 0.002) &nbsp; &nbsp; &nbsp; local cloudDownload = widget.newButton( &nbsp; &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id = "cloudDownload", &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sheet = settingButtonsImageSheet , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defaultFrame = 1, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; overFrame = 2, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; label = translations["Restore"][language], &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fontSize = 30, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; labelYOffset = 90, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; font = native.systemFont, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; labelColor = { default={ 0.9, 0, 0.42 }, over={ 0.9, 0, 0.42, 0.6 } }, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onEvent = handleButton &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; ) &nbsp; &nbsp; &nbsp; -- Center the button &nbsp; &nbsp; &nbsp; sceneGroup:insert(cloudDownload) &nbsp; &nbsp; &nbsp; cloudDownload.x = display.contentWidth \* 0.78 &nbsp; &nbsp; &nbsp; cloudDownload.y = display.contentHeight \* 0.30 &nbsp; &nbsp; &nbsp; cloudDownload:scale(display.contentWidth \* 0.002, display.contentWidth \* 0.002) &nbsp; &nbsp; end -- googLicensed END

Hi, unfortunately I cannot answer your question but I have another question :wink:

First: Thanks for the code. I am really missing a example project which shows the implementation.

So I can only test GPGS functionality if it is installed via Play Store? What if I build it in Corona Simulator and copy the .apk to my phone?

@hoffmann Thank you for taking a look at the code. Happy to share some code. :slight_smile:

 
You don’t need to upload the app each time you improve your game. You can simply copy the apk to your phone but when you open the app there will always be an alert message you can simply cancel that by clicking the back button of your phone and continue as usual. But for gpgs to work properly you need to setup from your developer console the game service and add your personal email to allow you to use the gpgs features. 

Note: You don’t need to publish your game services you can still use it when testing your game. 

@Sheekore

Thanks, I missed adding my gmail account as tester in developer console and had some minor bugs in my code. Now it works :wink:

Hello, in the config.lua file you stated Key, is it the long one with like 50 characters or which key is it, because there are a lot of keys.

thank you

In the new developer console select the app, then go to Developement_ tools_ - Services & APIs and under Licensing & in-app billing you should see the base-64 RSA public key. That’s the key. 

 

Question for you - do you have to make sure the user is logged in before using gpgs.events.increment?  I only want to track some of the usage of various items, I don’t really care about the user info.  Do I still them to login?

Thanks!

To use any gpgs features you need to have user logged in beforehand in every instance of your app.

Roger that, I appreciate the response and thanks for the code above- I am sure it will help a great deal.

Hi, unfortunately I cannot answer your question but I have another question :wink:

First: Thanks for the code. I am really missing a example project which shows the implementation.

So I can only test GPGS functionality if it is installed via Play Store? What if I build it in Corona Simulator and copy the .apk to my phone?

@hoffmann Thank you for taking a look at the code. Happy to share some code. :slight_smile:

 
You don’t need to upload the app each time you improve your game. You can simply copy the apk to your phone but when you open the app there will always be an alert message you can simply cancel that by clicking the back button of your phone and continue as usual. But for gpgs to work properly you need to setup from your developer console the game service and add your personal email to allow you to use the gpgs features. 

Note: You don’t need to publish your game services you can still use it when testing your game. 

@Sheekore

Thanks, I missed adding my gmail account as tester in developer console and had some minor bugs in my code. Now it works :wink:

The above code has been updated with all the needed modifications. The code may look a bit big at a first glance but once you read through it, you will find it simple as I have tried to use descriptive words and commenting hence very few explanations are given. Hope this updated post helps everyone  :) .

Have you noticed any delays in the listener for leaderboard score submission?  I have have all kinds of problems trying to display messages based on the high score.  I had moments where it would return a value, but not consistently. And now, as I try to fix it, I cannot get anything.  Manually setting a value  for myGlobalData.isleaderboardworthy shows me that the rest of my code seems to work, but I cannot get the listener to set the value…  Here is the listener function, and the scoreSubmit function - can you see anything amiss?  Maybe I am looking for the wrong event?

local function submitScoreListener( event ) print("in the submitScoreListener function") -- Google Play Games Services score submission if ( myGlobalData.gpgs ) then -- if not event.isError then --local isBest = nil if ( event.scores["all time"].isNewBest ) then myGlobalData.isleaderboardworthy = "alltime" print("in playerM.checkscore ALLTIME myGlobalData.isleaderboardworthy = "..myGlobalData.isleaderboardworthy) elseif ( event.scores["weekly"].isNewBest ) then myGlobalData.isleaderboardworthy = "weekly" print("in playerM.checkscore WEEKLY myGlobalData.isleaderboardworthy = "..myGlobalData.isleaderboardworthy) elseif ( event.scores["daily"].isNewBest ) then myGlobalData.isleaderboardworthy = "daily" print("in playerM.checkscore DAILY myGlobalData.isleaderboardworthy = "..myGlobalData.isleaderboardworthy) else myGlobalData.isleaderboardworthy = "no high score" print("in playerM.checkscore NO HIGH SCORE myGlobalData.isleaderboardworthy = "..myGlobalData.isleaderboardworthy) end -- Apple Game Center score submission elseif ( myGlobalData.gameCenter ) then if ( event.type == "setHighScore" ) then -- Congratulate player on a high score myGlobalData.isleaderboardworthy = "applehigh" native.showAlert( "Congratulations", "You set a high score!", { "OK" } ) else -- Encourage the player to do better native.showAlert( "Sorry...", "No high score, Better luck next time!", { "OK" } ) end end end local function submitScore( score ) print("in the submitScore function") -- manually setting the leaderboard value to trigger response in simulator myGlobalData.isleaderboardworthy = "daily" print("in playerM.checkscore SUBMITSCORE manually set myGlobalData.isleaderboardworthy = "..myGlobalData.isleaderboardworthy) if ( myGlobalData.gpgs ) then -- Submit a score to Google Play Games Services if mode == "reg" then myGlobalData.gpgs.leaderboards.submit( { leaderboardId = "CgkIosnt-cwwwwwww", score = score, listener = submitScoreListener }) elseif mode == "plow" then myGlobalData.gpgs.leaderboards.submit( { leaderboardId = "CgkIosnt-cwwwwwww", score = score, listener = submitScoreListener }) end elseif ( myGlobalData.gameCenter ) then -- Submit a score to Apple Game Center if mode == "reg" then myGlobalData.gameCenter.request( "setHighScore", { localPlayerScore = { category = "com.yourdomain.yourgame.leaderboard", value = score }, listener = submitScoreListener }) elseif mode == "plow" then myGlobalData.gameCenter.request( "setHighScore", { localPlayerScore = { category = "com.yourdomain.yourgame.leaderboard", value = score }, listener = submitScoreListener }) end end end

@sonyayllc. Can you post a new thread linking this tutorial by coronalabs so that coronalabs moderator can check up on you. 

the score does get submitted and stored on the leaderboard, but I can’t get the listener working… 

Thanks for taking a look!

I am not seeing any errors in the listener function. Please open a new topic so that others might help you. Sorry couldn’t be of any help. 

thanks again, using adb I was able to see that the listener is setting the variable, but my screen using it is already built/generated and not being refreshed - i have some timing issues to work through

Hello!

We are making a realtime multiplayer game that uses gpgs. We can make the room succesfully, but when we need to send the another player a reliable message using sendReliably() and he does not receive it. We used adb logcat and found this error message

 

E libjingle: Error(basicpacketsocketfactory.cc:67): UDP bind failed with error 22

 

could anyone help please?

 

The problem could occur because we do not have participantID in sendReliably() params. So how can we get the participantID

I am sorry I never worked with gpgs multiplayer. Check the official concept explanations GPGS multiplayer from Google and you can get the participant id from corona documentation.