Google Play Game Services few questions

Hello everyone!
A have a few questions about google play game services extension.

  • I want to save highscore in the google cloud so, if the user decides to uninstall the game and then download it later, he doesn’t lose the data. My question : do I need to use snapshots for that?

  • I’ve tried to use silent sign-in but I get this error in my logcat: http://prntscr.com/qikosp
    Code:


local use_saved_games = sys.get_config("gpgs.use_saved_games") == "1"

function callback(self, message_id, message)
	print(message_id)
	pprint(message)
	if message_id == gpgs.MSG_SIGN_IN or message_id == gpgs.MSG_SILENT_SIGN_IN then
		if message.status == gpgs.STATUS_SUCCESS then
			print("Good")
		end
	end
end

function init(self)
	msg.post(".", "acquire_input_focus")
	if gpgs then
		gpgs.silent_login()
		gpgs.set_callback(callback)
		gpgs.set_popup_position(gpgs.POPUP_POS_TOP_CENTER)
	end
end

function update(self, dt)
	if gpgs then
		if self.is_logged_in ~= gpgs.is_logged_in() then
			self.is_logged_in = gpgs.is_logged_in()
		end
	end
end

function final(self)
	if gpgs then
		gpgs.logout()
	end
end

@AGulev may have some ideas and answers to your questions and problems.

1 Like

Yes, you should use snapshot functionality for that.
Also, it should be possible to use leaderboards for that reason (if you want to save only player’s scores), but we don’t have this feature in our plugin yet.

If silent Sign-in is failed you should request regular Sign-in. Usually, a user has to sign-in once before you can use Silent Sign-in.

2 Likes

Thank you AGulev and britzl for you answers.
So after I changed gpgs.silent_login() to gpgs.login() it worked! So if I want to use silent_login() instead of login(), should I make just like :

if message.status == gpgs.STATUS_FAILED then
   gpgs.login()
end

Or is there a better option to do this, if I want to use silent.login instead of regular login if its not the first time the user login?

And for the snapshots, it looks a bit complicated with the images, png, bytes… Is there any example how to make it without any UI? Should I only use :
gpgs.snapshot_commit_and_close()
gpgs.snapshot_get_data()
gpgs.snapshot_set_data()
?

You can read about Sign-in best practices here: https://developers.google.com/games/services/android/signin#performing_silent_sign-in

You need to do the next steps (they are async, you can’t do it in a row):

gpgs.snapshot_open() -- open or create a save
gpgs.snapshot_get_data() -- get data from the currently opened save
gpgs.snapshot_set_data() -- set data into the currently opened save
gpgs.snapshot_commit_and_close() -- commit (save) data and close the currently opened save

The full example is here: https://github.com/defold/extension-gpgs/blob/master/main/main.gui_script

2 Likes

Currently I am getting an error “Silent sign-in failed” and in my game I get google signing in loop. I know I get this loop because I made that if the silent sign-in fails, it tries to login using regular silent.login(). But I don’t know why my sign in fails? Currently I am bundling my game, and launching it on android device. Do I need to do something else for sign-in to work, or am I doing something completely wrong? My code :

local use_saved_games = sys.get_config("gpgs.use_saved_games") == "1"

function callback(self, message_id, message)
	print(message_id)
	pprint(message)
	if message_id == gpgs.MSG_SIGN_IN or message_id == gpgs.MSG_SILENT_SIGN_IN then
		if message.status == gpgs.STATUS_SUCCESS then
			print("Good")
		end
		if message.status == gpgs.STATUS_FAILED then
			gpgs.login()
		end
		if use_saved_games then
			gpgs.snapshot_open("googledata", true, gpgs.RESOLUTION_POLICY_MANUAL)
		end
		if gpgs then
			local bytes, error_message = gpgs.snapshot_get_data()
			if not bytes then
				print("snapshot_get_data ERROR:", error_message)
			else
				print("snapshot_get_data", bytes)
			end
		end
	end
end

function init(self)
	msg.post(".", "acquire_input_focus")
	if gpgs then
		gpgs.silent_login()
		gpgs.set_callback(callback)
	end
end

function update(self, dt)
	if gpgs then
		if self.is_logged_in ~= gpgs.is_logged_in() then
			self.is_logged_in = gpgs.is_logged_in()
		end
		if use_saved_games then
			if self.snapshot_is_opened ~= gpgs.snapshot_is_opened() then
				self.snapshot_is_opened = gpgs.snapshot_is_opened()
			end
		end
	end
end

function on_message(self, message_id, message, sender)
	if message_id == hash("set_data") then
		if gpgs then
			local success, error_message = gpgs.snapshot_set_data("googledata")
			if not success then
				print("snapshot_set_data ERROR:", error_message)
			end
		end
	end
end

function final(self)
	if gpgs then
		gpgs.snapshot_commit_and_close()
	end
	if gpgs then
		gpgs.logout()
	end
end

P.S What I have noticed is that on https://github.com/defold/extension-gpgs/blob/master/game.project
in gpgs section there is #client_id so should I paste there my OAuth2 Client ID?
I haven’t done that because in this : https://defold.com/extension-gpgs/ example there are only these fields :

[gpgs]
app_id = 1234567890
use_saved_games = 1
request_server_auth_code = 0
request_id_token = 0

To avoid this loop you should process gpgs.MSG_SIGN_IN and gpgs.MSG_SILENT_SIGN_IN messages separately.

Yes, check this section step by step once again:

Google App Setup

In order to use Google Play Game Services your application needs to be added to the Google Play store. It doesn’t have to be published but it must be registered. Read more about how to sign up for and use the Google Play store in the official documentation.

Once the application is registered you also need to enable Google Play Game Services for the application. Follow the official documentation to enable Google Play Game Services.


If something wrong with Google Console settings GPGS should notify you in logcat when you make initialization with instructions on how to fix your problem.

2 Likes

Thank you AGulev for helping me!
It worked!! What I did was : change bundle from debug to release and use the certificate and keys that I used for publishing my game to app stores. I always tested it with debug bundle and no certificate and keys! :slight_smile:

1 Like

Now I test if snapshots work (install game, set new highscore, uninstall game, check if the highscore is previous one). But it doesn’t work :confused:
Logcat : http://prntscr.com/qjajwo
gpgs script file :

local use_saved_games = sys.get_config("gpgs.use_saved_games") == "1"

function callback(self, message_id, message)
	print(message_id)
	pprint(message)
	if message_id == gpgs.MSG_SIGN_IN or message_id == gpgs.MSG_SILENT_SIGN_IN then
		if message.status == gpgs.STATUS_SUCCESS then
			
		end
		if message.status == gpgs.STATUS_FAILED then
			gpgs.login()
		end
		if use_saved_games then
			gpgs.snapshot_open("googledata", true, gpgs.RESOLUTION_POLICY_MANUAL)
		end
	end
end

function init(self)
	msg.post(".", "acquire_input_focus")
	if gpgs then
		gpgs.set_callback(callback)
		gpgs.silent_login()
	end
	if gpgs then
		local bytes, error_message = gpgs.snapshot_get_data()
		if not bytes then
			print("snapshot_get_data ERROR:", error_message)
		else
			print("snapshot_get_data", bytes)
		end
	end
end

function update(self, dt)
	if gpgs then
		if self.is_logged_in ~= gpgs.is_logged_in() then
			self.is_logged_in = gpgs.is_logged_in()
		end
		if use_saved_games then
			if self.snapshot_is_opened ~= gpgs.snapshot_is_opened() then
				self.snapshot_is_opened = gpgs.snapshot_is_opened()
			end
		end
	end
end

function on_message(self, message_id, message, sender)
	if message_id == hash("set_data") then -- lose screen sends this message in init
		if gpgs then
			local success, error_message = gpgs.snapshot_set_data("googledata")
			if not success then
				print("snapshot_set_data ERROR:", error_message)
			end
		end
	end
end

function final(self)
	if gpgs then
		gpgs.snapshot_commit_and_close()
	end
	if gpgs then
		gpgs.logout()
	end
end

I have tried to move gpgs.snapshot_commit_and_close() near the save data, but then, after I lose my game crashes.

First of all, it’s not necessary to check gpgs.snapshot_is_opened() in update() method (In my example I did that only for the test reason). Instead, you are able to use gpgs.MSG_LOAD_SNAPSHOT.

I don’t know what you want to do, but final() will not be called when you close application.
It would be better to call this method when something happens in the game or every time you set data (but then you need to re-open your save if you want to use it one more time during the game session).
If it crashes, please provide the crash log.

1 Like

I just want to save high score, so if the user uninstalls my game and downloads it again, he doesn’t lose the high score.

I moved

if gpgs then
	gpgs.snapshot_commit_and_close()
end

from final() to the

function on_message(self, message_id, message, sender)
	if message_id == hash("set_data") then
		if gpgs then
			local success, error_message = gpgs.snapshot_set_data("googledata")
			if not success then
				print("snapshot_set_data ERROR:", error_message)
			end
		end
		if gpgs then
			gpgs.snapshot_commit_and_close()
		end
	end
end

On logcat I saw that I get error : http://prntscr.com/qjazr6
Although I still get info from my googledata file : http://prntscr.com/qjb19h
Now, after I die in the game my game crash and I get this error : http://prntscr.com/qjb05t

As I mentioned in the previous reply, I just want to save the highscore.

What is the result of opening your file gpgs.MSG_LOAD_SNAPSHOT ?

-- in callback
if message_id == gpgs.MSG_LOAD_SNAPSHOT then
        pprint(message)
end
-- in callback
if message_id == gpgs.MSG_LOAD_SNAPSHOT then
        pprint(message)
end

I added this in my callback function. But I don’t get any message in the logcat.


This is hard to take all these pieces of information and get the whole picture

Please, re-read the documentation and carefully check your logic.

One more time, how it should be (I didn’t check this code, sorry, it’s just an explanation):


local function open_snapshot()
  gpgs.snapshot_open("googledata", true, gpgs.RESOLUTION_POLICY_MANUAL)
end

local function save_data(data)
 local success, error_message = gpgs.snapshot_set_data(data)
  if success then
    gpgs.snapshot_commit_and_close({progressValue = get_progres_value()}) --would be better to set data for the automatic conflict solver
  else
   print("snapshot_set_data ERROR:", error_message)
 end
end

local function callback(self, message_id, message)
  if message_id == gpgs.MSG_SILENT_SIGN_IN then
    if message.status == gpgs.STATUS_SUCCESS then
      open_snapshot()
    else
      gpgs.login()
    end
  elseif message_id == gpgs.MSG_SIGN_IN then
    if message.status == gpgs.STATUS_SUCCESS then
      open_snapshot()
    else
      print("can't login")
    end
  elseif message_id == gpgs.MSG_LOAD_SNAPSHOT then
      if message.status == gpgs.STATUS_SUCCESS then
        local bytes, error_message = gpgs.snapshot_get_data()
        if not bytes then
           print("snapshot_get_data ERROR:", error_message)
        else
          self.my_save = bytes
          print("snapshot_get_data", bytes)
          -- if we have the not saved data, let's try to save it
          if self.not_saved_data then
            save_data(self.non_saved_data)
            self.not_saved_data = nil
          end
        end
      else -- a few more elseif
        --error handler or conflict solver
      end
  end
end

function init()
  if gpgs then
    gpgs.set_callback(callback)
    gpgs.silent_login()
  end
end

function on_message(self, message_id, message, sender)
  if message_id == hash("set_data") then
      if gpgs then
       if gpgs.snapshot_is_opened() then
         save_data(message .data)
       else
         -- your snapshot has already closed (or wasn't open)
        -- let's save your data locally in `self` and try to save it when the snapshot will be opened again
        self.not_saved_data = message.data
        open_snapshot()
       end
      end
  end
end

2 Likes

Also do I need to specify highscore in data like in the “defsave”, or does snapshot record all the information of the game?

local function save_data(data)
 local success, error_message = gpgs.snapshot_set_data(data)

For example in this place, now I get error because data is nil value. Should data be the highscore?

You need to specify data you want to save. in your case data should be your highscore.

And what causes this crash? : http://prntscr.com/qjcxe9
I get crash when I die in my game. Is it because I send msg.post(“controller:/gpgs#gpgs”, “set_data”) ?

I don’t know, your screenshot is uninformative.
Would be nice if you can provide a full log from logcat as txt file and _crash file

I am very sorry for that.
Here is the txt file from logcat. log.txt (6.2 KB)