├── gpgs ├── ext.manifest ├── ext.properties ├── manifests │ └── android │ │ ├── build.gradle │ │ └── AndroidManifest.xml ├── src │ ├── com_defold_gpgs_GpgsJNI.h │ ├── private_gpgs_callback.h │ ├── gpgs_extension.h │ ├── gpgs_callback.cpp │ └── java │ │ └── com │ │ └── defold │ │ └── gpgs │ │ └── GpgsJNI.java └── api │ └── gpgs.script_api ├── main ├── logo.atlas ├── images │ └── logo.png ├── main.script ├── menu.collection ├── snapshot.collection ├── events.collection ├── achievements.collection ├── authentication.collection ├── leaderboards.collection ├── menu.gui_script ├── authentication.gui_script ├── events.gui_script ├── achievements.gui_script ├── leaderboards.gui_script ├── authentication.gui ├── menu.gui ├── snapshot.gui_script ├── main.collection ├── events.gui ├── achievements.gui ├── leaderboards.gui └── snapshot.gui ├── input └── game.input_binding ├── .github ├── FUNDING.yml └── workflows │ ├── bob.yml │ └── trigger-site-rebuild.yml ├── .gitignore ├── README.md ├── LICENSE.md ├── game.project ├── generated.appmanifest └── docs └── index.md /gpgs/ext.manifest: -------------------------------------------------------------------------------- 1 | name: GpgsExt -------------------------------------------------------------------------------- /main/logo.atlas: -------------------------------------------------------------------------------- 1 | images { 2 | image: "/main/images/logo.png" 3 | } 4 | -------------------------------------------------------------------------------- /main/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defold/extension-gpgs/HEAD/main/images/logo.png -------------------------------------------------------------------------------- /input/game.input_binding: -------------------------------------------------------------------------------- 1 | mouse_trigger { 2 | input: MOUSE_BUTTON_1 3 | action: "touch" 4 | } 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: defold 2 | patreon: Defold 3 | custom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=NBNBHTUW4GS4C'] 4 | -------------------------------------------------------------------------------- /.github/workflows/bob.yml: -------------------------------------------------------------------------------- 1 | name: Build with bob 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | uses: defold/github-actions-common/.github/workflows/bob.yml@master 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.internal 2 | /build 3 | .externalToolBuilders 4 | .DS_Store 5 | Thumbs.db 6 | .lock-wscript 7 | *.pyc 8 | .project 9 | .cproject 10 | builtins 11 | _site 12 | /.editor_settings -------------------------------------------------------------------------------- /gpgs/ext.properties: -------------------------------------------------------------------------------- 1 | [gpgs] 2 | group = Runtime 3 | title = GPGS 4 | help = Settings for Google Play Game Services extension 5 | 6 | app_id.type = string 7 | 8 | client_id.type = string 9 | 10 | use_saved_games.type = bool 11 | 12 | request_server_auth_code.type = bool 13 | -------------------------------------------------------------------------------- /main/main.script: -------------------------------------------------------------------------------- 1 | local monarch = require "monarch.monarch" 2 | 3 | function init(self) 4 | msg.post(".", "acquire_input_focus") 5 | if gpgs then 6 | for k,v in pairs(gpgs) do 7 | print("gpgs." .. tostring(k)) 8 | end 9 | end 10 | timer.delay(0, false, function() 11 | monarch.show("menu") 12 | end) 13 | end 14 | -------------------------------------------------------------------------------- /gpgs/manifests/android/build.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | mavenCentral() 3 | } 4 | 5 | dependencies { 6 | // https://developers.google.com/android/guides/setup#split 7 | implementation 'com.google.android.gms:play-services-base:18.5.0' 8 | implementation 'com.google.android.gms:play-services-auth:21.3.0' 9 | implementation 'com.google.android.gms:play-services-games-v2:21.0.0' 10 | } 11 | -------------------------------------------------------------------------------- /gpgs/manifests/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Actions Status Alpha](https://github.com/defold/extension-gpgs/actions/workflows/bob.yml/badge.svg)](https://github.com/defold/extension-gpgs/actions) 2 | 3 | # Google Play Game Services for Defold 4 | 5 | Defold [native extension](https://www.defold.com/manuals/extensions/) which provides access to Google Play Game Services functionality on Android devices. 6 | 7 | [Manual, API and setup instructions](https://www.defold.com/extension-gpgs/) is available on the official Defold site. 8 | -------------------------------------------------------------------------------- /gpgs/src/com_defold_gpgs_GpgsJNI.h: -------------------------------------------------------------------------------- 1 | #include 2 | /* Header for class com_defold_gpgs_GpgsJNI */ 3 | 4 | #ifndef COM_DEFOLD_GPGS_GPGSJNI_H 5 | #define COM_DEFOLD_GPGS_GPGSJNI_H 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | /* 10 | * Class: com_defold_gpgs_GpgsJNI 11 | * Method: gpgsAddToQueue_first_arg 12 | * Signature: (ILjava/lang/String;I)V 13 | */ 14 | JNIEXPORT void JNICALL Java_com_defold_gpgs_GpgsJNI_gpgsAddToQueue 15 | (JNIEnv *, jclass, jint, jstring); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | #endif 21 | -------------------------------------------------------------------------------- /.github/workflows/trigger-site-rebuild.yml: -------------------------------------------------------------------------------- 1 | name: Trigger site rebuild 2 | 3 | on: [push] 4 | 5 | jobs: 6 | site-rebuild: 7 | runs-on: ubuntu-latest 8 | 9 | steps: [ 10 | { 11 | name: 'Repository dispatch', 12 | uses: defold/repository-dispatch@1.2.1, 13 | with: { 14 | repo: 'defold/defold.github.io', 15 | token: '${{ secrets.SERVICES_GITHUB_TOKEN }}', 16 | user: 'services@defold.se', 17 | action: 'extension-gpgs' 18 | } 19 | }] 20 | -------------------------------------------------------------------------------- /gpgs/src/private_gpgs_callback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "gpgs_extension.h" 5 | 6 | struct GPGS_callback 7 | { 8 | GPGS_callback() : m_L(0), m_Callback(LUA_NOREF), m_Self(LUA_NOREF) {} 9 | lua_State* m_L; 10 | int m_Callback; 11 | int m_Self; 12 | }; 13 | 14 | struct CallbackData 15 | { 16 | MESSAGE_ID msg; 17 | char* json; 18 | }; 19 | 20 | void gpgs_set_callback(lua_State* L, int pos); 21 | void gpgs_callback_initialize(); 22 | void gpgs_callback_finalize(); 23 | void gpgs_callback_update(); 24 | void gpgs_add_to_queue(MESSAGE_ID msg, const char*json); 25 | -------------------------------------------------------------------------------- /main/menu.collection: -------------------------------------------------------------------------------- 1 | name: "menu" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "go" 5 | data: "components {\n" 6 | " id: \"gui\"\n" 7 | " component: \"/main/menu.gui\"\n" 8 | " position {\n" 9 | " x: 0.0\n" 10 | " y: 0.0\n" 11 | " z: 0.0\n" 12 | " }\n" 13 | " rotation {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " w: 1.0\n" 18 | " }\n" 19 | "}\n" 20 | "" 21 | position { 22 | x: 0.0 23 | y: 0.0 24 | z: 0.0 25 | } 26 | rotation { 27 | x: 0.0 28 | y: 0.0 29 | z: 0.0 30 | w: 1.0 31 | } 32 | scale3 { 33 | x: 1.0 34 | y: 1.0 35 | z: 1.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /main/snapshot.collection: -------------------------------------------------------------------------------- 1 | name: "snapshot" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "go" 5 | data: "components {\n" 6 | " id: \"snapshot\"\n" 7 | " component: \"/main/snapshot.gui\"\n" 8 | " position {\n" 9 | " x: 0.0\n" 10 | " y: 0.0\n" 11 | " z: 0.0\n" 12 | " }\n" 13 | " rotation {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " w: 1.0\n" 18 | " }\n" 19 | "}\n" 20 | "" 21 | position { 22 | x: 0.0 23 | y: 0.0 24 | z: 0.0 25 | } 26 | rotation { 27 | x: 0.0 28 | y: 0.0 29 | z: 0.0 30 | w: 1.0 31 | } 32 | scale3 { 33 | x: 1.0 34 | y: 1.0 35 | z: 1.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /main/events.collection: -------------------------------------------------------------------------------- 1 | name: "events" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "go" 5 | data: "components {\n" 6 | " id: \"monarch\"\n" 7 | " component: \"/main/events.gui\"\n" 8 | " position {\n" 9 | " x: 0.0\n" 10 | " y: 0.0\n" 11 | " z: 0.0\n" 12 | " }\n" 13 | " rotation {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " w: 1.0\n" 18 | " }\n" 19 | "}\n" 20 | "" 21 | position { 22 | x: 0.0 23 | y: 0.0 24 | z: 0.0 25 | } 26 | rotation { 27 | x: 0.0 28 | y: 0.0 29 | z: 0.0 30 | w: 1.0 31 | } 32 | scale3 { 33 | x: 1.0 34 | y: 1.0 35 | z: 1.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /main/achievements.collection: -------------------------------------------------------------------------------- 1 | name: "achievements" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "go" 5 | data: "components {\n" 6 | " id: \"achievements\"\n" 7 | " component: \"/main/achievements.gui\"\n" 8 | " position {\n" 9 | " x: 0.0\n" 10 | " y: 0.0\n" 11 | " z: 0.0\n" 12 | " }\n" 13 | " rotation {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " w: 1.0\n" 18 | " }\n" 19 | "}\n" 20 | "" 21 | position { 22 | x: 0.0 23 | y: 0.0 24 | z: 0.0 25 | } 26 | rotation { 27 | x: 0.0 28 | y: 0.0 29 | z: 0.0 30 | w: 1.0 31 | } 32 | scale3 { 33 | x: 1.0 34 | y: 1.0 35 | z: 1.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /main/authentication.collection: -------------------------------------------------------------------------------- 1 | name: "authentication" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "go" 5 | data: "components {\n" 6 | " id: \"authentication\"\n" 7 | " component: \"/main/authentication.gui\"\n" 8 | " position {\n" 9 | " x: 0.0\n" 10 | " y: 0.0\n" 11 | " z: 0.0\n" 12 | " }\n" 13 | " rotation {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " w: 1.0\n" 18 | " }\n" 19 | "}\n" 20 | "" 21 | position { 22 | x: 0.0 23 | y: 0.0 24 | z: 0.0 25 | } 26 | rotation { 27 | x: 0.0 28 | y: 0.0 29 | z: 0.0 30 | w: 1.0 31 | } 32 | scale3 { 33 | x: 1.0 34 | y: 1.0 35 | z: 1.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /main/leaderboards.collection: -------------------------------------------------------------------------------- 1 | name: "leaderboards" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "go" 5 | data: "components {\n" 6 | " id: \"monarch\"\n" 7 | " component: \"/main/leaderboards.gui\"\n" 8 | " position {\n" 9 | " x: 0.0\n" 10 | " y: 0.0\n" 11 | " z: 0.0\n" 12 | " }\n" 13 | " rotation {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " w: 1.0\n" 18 | " }\n" 19 | "}\n" 20 | "" 21 | position { 22 | x: 0.0 23 | y: 0.0 24 | z: 0.0 25 | } 26 | rotation { 27 | x: 0.0 28 | y: 0.0 29 | z: 0.0 30 | w: 1.0 31 | } 32 | scale3 { 33 | x: 1.0 34 | y: 1.0 35 | z: 1.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Defold 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /main/menu.gui_script: -------------------------------------------------------------------------------- 1 | local dirtylarry = require "dirtylarry.dirtylarry" 2 | local monarch = require "monarch.monarch" 3 | 4 | function init(self) 5 | msg.post(".", "acquire_input_focus") 6 | self.popup_pos = 3 7 | 8 | if gpgs and gpgs.is_supported() then 9 | gui.set_text(gui.get_node("support_status"), "Is Supported") 10 | else 11 | gui.set_text(gui.get_node("support_status"), "Not Supported") 12 | end 13 | end 14 | 15 | 16 | function on_input(self, action_id, action) 17 | dirtylarry:button("authentication", action_id, action, function () 18 | monarch.show("authentication") 19 | end) 20 | 21 | dirtylarry:button("snapshot", action_id, action, function () 22 | monarch.show("snapshot") 23 | end) 24 | 25 | dirtylarry:button("achievements", action_id, action, function () 26 | monarch.show("achievements") 27 | end) 28 | 29 | dirtylarry:button("leaderboards", action_id, action, function () 30 | monarch.show("leaderboards") 31 | end) 32 | 33 | dirtylarry:button("events", action_id, action, function () 34 | monarch.show("events") 35 | end) 36 | end -------------------------------------------------------------------------------- /game.project: -------------------------------------------------------------------------------- 1 | [project] 2 | title = extension-gpgs 3 | version = 0.2 4 | dependencies#0 = https://github.com/andsve/dirtylarry/archive/master.zip 5 | dependencies#1 = https://github.com/britzl/defold-screenshot/archive/master.zip 6 | dependencies#2 = https://github.com/britzl/monarch/archive/3.1.0.zip 7 | 8 | [bootstrap] 9 | main_collection = /main/main.collectionc 10 | 11 | [input] 12 | game_binding = /input/game.input_bindingc 13 | 14 | [display] 15 | width = 1280 16 | height = 720 17 | 18 | [physics] 19 | scale = 0.02 20 | 21 | [script] 22 | shared_state = 1 23 | 24 | [android] 25 | package = com.defold.extension.gpgs 26 | minimum_sdk_version = 21 27 | target_sdk_version = 34 28 | 29 | [ios] 30 | bundle_identifier = com.defold.extension.gpgs 31 | infoplist = /builtins/manifests/ios/Info.plist 32 | 33 | [gpgs] 34 | app_id = 741832396715 35 | client_id = 741832396715-sl2dn4pjiqop78t1pgflb6ob4aqsvom5.apps.googleusercontent.com 36 | use_saved_games = 1 37 | request_server_auth_code = 0 38 | 39 | [library] 40 | include_dirs = gpgs 41 | 42 | [osx] 43 | bundle_identifier = com.defold.extension.gpgs 44 | 45 | [native_extension] 46 | app_manifest = /generated.appmanifest 47 | 48 | -------------------------------------------------------------------------------- /main/authentication.gui_script: -------------------------------------------------------------------------------- 1 | local dirtylarry = require "dirtylarry.dirtylarry" 2 | local monarch = require "monarch.monarch" 3 | 4 | 5 | local function gpgs_callback(self, message_id, message) 6 | if message_id == gpgs.MSG_SIGN_IN or message_id == gpgs.MSG_SILENT_SIGN_IN then 7 | if message.status == gpgs.STATUS_SUCCESS then 8 | gui.set_text(gui.get_node("id"), gpgs.get_id()) 9 | gui.set_text(gui.get_node("name"), gpgs.get_display_name()) 10 | 11 | if sys.get_config_int("gpgs.request_server_auth_code") == 1 then 12 | print("auth_code: ", gpgs.get_server_auth_code()) 13 | end 14 | end 15 | end 16 | gui.set_text(gui.get_node("authorized"), "is_logged_in: " .. tostring(gpgs.is_logged_in())) 17 | end 18 | 19 | function init(self) 20 | msg.post(".", "acquire_input_focus") 21 | if gpgs then 22 | gpgs.set_callback(gpgs_callback) 23 | gpgs.silent_login() 24 | end 25 | end 26 | 27 | function on_input(self, action_id, action) 28 | dirtylarry:button("login", action_id, action, function () 29 | print("LOGIN was pressed") 30 | if gpgs then 31 | gpgs.login() 32 | end 33 | end) 34 | 35 | dirtylarry:button("back", action_id, action, function () 36 | monarch.back() 37 | end) 38 | end 39 | 40 | function on_reload(self) 41 | -- Add input-handling code here 42 | -- Remove this function if not needed 43 | end 44 | -------------------------------------------------------------------------------- /main/events.gui_script: -------------------------------------------------------------------------------- 1 | local dirtylarry = require "dirtylarry.dirtylarry" 2 | local monarch = require "monarch.monarch" 3 | 4 | 5 | local function gpgs_callback(self, message_id, message) 6 | print(message_id) 7 | pprint(message) 8 | if message_id == gpgs.MSG_GET_EVENTS then 9 | local s = "" 10 | for _,event in ipairs(message) do 11 | event = json.decode(event) 12 | s = s .. ("%s (%s) = %s\n"):format(event.name, event.id, event.value) 13 | end 14 | gui.set_text(gui.get_node("events"), s) 15 | end 16 | end 17 | 18 | function init(self) 19 | msg.post(".", "acquire_input_focus") 20 | if gpgs then 21 | gpgs.set_callback(gpgs_callback) 22 | end 23 | end 24 | 25 | function on_input(self, action_id, action) 26 | dirtylarry:button("kill_zombie", action_id, action, function () 27 | gpgs.event_increment("CgkIq5-gxcsVEAIQAw", 1) 28 | end) 29 | 30 | dirtylarry:button("earn_gold", action_id, action, function () 31 | gpgs.event_increment("CgkIq5-gxcsVEAIQBA", 1) 32 | end) 33 | 34 | dirtylarry:button("spend_gold", action_id, action, function () 35 | gpgs.event_increment("CgkIq5-gxcsVEAIQBQ", 1) 36 | end) 37 | 38 | dirtylarry:button("get", action_id, action, function () 39 | gpgs.event_get() 40 | end) 41 | 42 | dirtylarry:button("back", action_id, action, function () 43 | monarch.back() 44 | end) 45 | end 46 | 47 | function on_reload(self) 48 | -- Add input-handling code here 49 | -- Remove this function if not needed 50 | end 51 | -------------------------------------------------------------------------------- /main/achievements.gui_script: -------------------------------------------------------------------------------- 1 | local dirtylarry = require "dirtylarry.dirtylarry" 2 | local monarch = require "monarch.monarch" 3 | 4 | 5 | local function gpgs_callback(self, message_id, message) 6 | print(message_id) 7 | pprint(message) 8 | end 9 | 10 | function init(self) 11 | msg.post(".", "acquire_input_focus") 12 | if gpgs then 13 | gpgs.set_callback(gpgs_callback) 14 | end 15 | end 16 | 17 | function on_input(self, action_id, action) 18 | dirtylarry:button("reveal", action_id, action, function () 19 | if gpgs then 20 | gpgs.achievement_reveal("CgkIq5-gxcsVEAIQAQ") 21 | end 22 | end) 23 | 24 | dirtylarry:button("unlock", action_id, action, function () 25 | if gpgs then 26 | gpgs.achievement_unlock("CgkIq5-gxcsVEAIQAQ") 27 | end 28 | end) 29 | 30 | dirtylarry:button("increment", action_id, action, function () 31 | if gpgs then 32 | gpgs.achievement_increment("CgkIq5-gxcsVEAIQAQ", 1) 33 | end 34 | end) 35 | 36 | dirtylarry:button("set", action_id, action, function () 37 | if gpgs then 38 | gpgs.achievement_set("CgkIq5-gxcsVEAIQAQ", 10) 39 | end 40 | end) 41 | 42 | dirtylarry:button("show", action_id, action, function () 43 | if gpgs then 44 | gpgs.achievement_show() 45 | end 46 | end) 47 | 48 | dirtylarry:button("get", action_id, action, function () 49 | if gpgs then 50 | gpgs.achievement_get() 51 | end 52 | end) 53 | 54 | dirtylarry:button("back", action_id, action, function () 55 | monarch.back() 56 | end) 57 | end 58 | 59 | function on_reload(self) 60 | -- Add input-handling code here 61 | -- Remove this function if not needed 62 | end 63 | -------------------------------------------------------------------------------- /main/leaderboards.gui_script: -------------------------------------------------------------------------------- 1 | local dirtylarry = require "dirtylarry.dirtylarry" 2 | local monarch = require "monarch.monarch" 3 | 4 | local function gpgs_callback(self, message_id, message) 5 | print(message_id) 6 | pprint(message) 7 | if message_id == gpgs.MSG_GET_PLAYER_SCORE then 8 | local text = ("%s (%s)"):format(message.display_score, message.display_rank) 9 | gui.set_text(gui.get_node("score"), text) 10 | elseif message_id == gpgs.MSG_GET_PLAYER_CENTERED_SCORES 11 | or message_id == gpgs.MSG_GET_TOP_SCORES then 12 | local s = "" 13 | for _,score in ipairs(message) do 14 | score = json.decode(score) 15 | s = s .. ("%s - %s (%s)\n"):format(score.score_holder_name, score.display_score, score.display_rank) 16 | end 17 | gui.set_text(gui.get_node("scores"), s) 18 | end 19 | end 20 | 21 | function init(self) 22 | msg.post(".", "acquire_input_focus") 23 | if gpgs then 24 | gpgs.set_callback(gpgs_callback) 25 | end 26 | self.clicks = 0 27 | end 28 | 29 | function on_input(self, action_id, action) 30 | if action_id == hash("touch") and action.released then 31 | self.clicks = self.clicks + 1 32 | print(self.clicks) 33 | gui.set_text(gui.get_node("clicks"), tostring(self.clicks)) 34 | end 35 | 36 | dirtylarry:button("submit_score", action_id, action, function () 37 | gpgs.leaderboard_submit_score("CgkIq5-gxcsVEAIQAg", self.clicks) 38 | end) 39 | 40 | dirtylarry:button("top_scores", action_id, action, function () 41 | gpgs.leaderboard_get_top_scores("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC, 10) 42 | end) 43 | 44 | dirtylarry:button("player_centered_scores", action_id, action, function () 45 | gpgs.leaderboard_get_player_centered_scores("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC, 10) 46 | end) 47 | 48 | dirtylarry:button("player_score", action_id, action, function () 49 | gpgs.leaderboard_get_player_score("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC) 50 | end) 51 | 52 | dirtylarry:button("show_leaderboard", action_id, action, function () 53 | gpgs.leaderboard_show("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC) 54 | end) 55 | 56 | dirtylarry:button("back", action_id, action, function () 57 | monarch.back() 58 | end) 59 | end 60 | 61 | function on_reload(self) 62 | end 63 | -------------------------------------------------------------------------------- /gpgs/src/gpgs_extension.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient#RESOLUTION_POLICY_HIGHEST_PROGRESS 4 | enum ResolutionPolicy 5 | { 6 | RESOLUTION_POLICY_MANUAL = -1, 7 | RESOLUTION_POLICY_LONGEST_PLAYTIME = 1, 8 | RESOLUTION_POLICY_LAST_KNOWN_GOOD = 2, 9 | RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED = 3, 10 | RESOLUTION_POLICY_HIGHEST_PROGRESS = 4 11 | }; 12 | 13 | // https://developers.google.com/android/reference/com/google/android/gms/games/GamesClientStatusCodes.html 14 | enum ERROR 15 | { 16 | ERROR_STATUS_SNAPSHOT_NOT_FOUND = 26570, 17 | ERROR_STATUS_SNAPSHOT_CREATION_FAILED = 26571, 18 | ERROR_STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE = 26572, 19 | ERROR_STATUS_SNAPSHOT_COMMIT_FAILED = 26573, 20 | ERROR_STATUS_SNAPSHOT_FOLDER_UNAVAILABLE = 26575, 21 | ERROR_STATUS_SNAPSHOT_CONFLICT_MISSING = 26576, 22 | }; 23 | 24 | // https://developers.google.com/android/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant#TIME_SPAN_DAILY 25 | enum LeaderboardTimeSpan 26 | { 27 | TIME_SPAN_DAILY = 0, 28 | TIME_SPAN_WEEKLY = 1, 29 | TIME_SPAN_ALL_TIME = 2 30 | }; 31 | 32 | // https://developers.google.com/android/reference/com/google/android/gms/games/leaderboard/LeaderboardVariant#public-static-final-int-collection_public 33 | enum LeaderboardCollection { 34 | COLLECTION_PUBLIC = 0, 35 | COLLECTION_SOCIAL = 1 36 | }; 37 | 38 | 39 | // Internal to the extension 40 | enum SNAPSHOT_TYPE 41 | { 42 | SNAPSHOT_CURRENT = 1, 43 | SNAPSHOT_CONFLICTING = 2 44 | }; 45 | 46 | // Internal to the extension 47 | enum MESSAGE_ID 48 | { 49 | MSG_SIGN_IN = 1, 50 | MSG_SILENT_SIGN_IN = 2, 51 | MSG_SHOW_SNAPSHOTS = 4, 52 | MSG_LOAD_SNAPSHOT = 5, 53 | MSG_SAVE_SNAPSHOT = 6, 54 | MSG_GET_ACHIEVEMENTS = 7, 55 | MSG_GET_TOP_SCORES = 8, 56 | MSG_GET_PLAYER_CENTERED_SCORES = 9, 57 | MSG_GET_PLAYER_SCORE = 10, 58 | MSG_GET_EVENTS = 11, 59 | MSG_GET_SERVER_TOKEN = 12 60 | }; 61 | 62 | // Internal to the extension 63 | enum STATUS 64 | { 65 | STATUS_SUCCESS = 1, 66 | STATUS_FAILED = 2, 67 | STATUS_CREATE_NEW_SAVE = 3, 68 | STATUS_CONFLICT = 4, 69 | }; 70 | -------------------------------------------------------------------------------- /main/authentication.gui: -------------------------------------------------------------------------------- 1 | script: "/main/authentication.gui_script" 2 | fonts { 3 | name: "larryfont" 4 | font: "/dirtylarry/larryfont.font" 5 | } 6 | textures { 7 | name: "dirtylarry" 8 | texture: "/dirtylarry/dirtylarry.atlas" 9 | } 10 | nodes { 11 | position { 12 | x: 170.0 13 | y: 650.0 14 | } 15 | type: TYPE_TEMPLATE 16 | id: "login" 17 | inherit_alpha: true 18 | template: "/dirtylarry/button.gui" 19 | } 20 | nodes { 21 | type: TYPE_BOX 22 | id: "login/larrybutton" 23 | parent: "login" 24 | template_node_child: true 25 | } 26 | nodes { 27 | type: TYPE_TEXT 28 | text: "Login" 29 | id: "login/larrylabel" 30 | parent: "login/larrybutton" 31 | overridden_fields: 8 32 | template_node_child: true 33 | } 34 | nodes { 35 | position { 36 | x: 829.0 37 | y: 679.168 38 | } 39 | size { 40 | x: 440.0 41 | y: 40.0 42 | } 43 | type: TYPE_TEXT 44 | font: "larryfont" 45 | id: "authorized" 46 | pivot: PIVOT_W 47 | outline { 48 | x: 1.0 49 | y: 1.0 50 | z: 1.0 51 | } 52 | shadow { 53 | x: 1.0 54 | y: 1.0 55 | z: 1.0 56 | } 57 | line_break: true 58 | inherit_alpha: true 59 | } 60 | nodes { 61 | position { 62 | x: 170.0 63 | y: 74.0 64 | } 65 | type: TYPE_TEMPLATE 66 | id: "back" 67 | inherit_alpha: true 68 | template: "/dirtylarry/button.gui" 69 | } 70 | nodes { 71 | type: TYPE_BOX 72 | id: "back/larrybutton" 73 | parent: "back" 74 | template_node_child: true 75 | } 76 | nodes { 77 | type: TYPE_TEXT 78 | text: "BACK" 79 | id: "back/larrylabel" 80 | parent: "back/larrybutton" 81 | overridden_fields: 8 82 | template_node_child: true 83 | } 84 | nodes { 85 | position { 86 | x: 829.0 87 | y: 629.0 88 | } 89 | size { 90 | x: 440.0 91 | y: 40.0 92 | } 93 | type: TYPE_TEXT 94 | font: "larryfont" 95 | id: "id" 96 | pivot: PIVOT_W 97 | outline { 98 | x: 1.0 99 | y: 1.0 100 | z: 1.0 101 | } 102 | shadow { 103 | x: 1.0 104 | y: 1.0 105 | z: 1.0 106 | } 107 | inherit_alpha: true 108 | } 109 | nodes { 110 | position { 111 | x: 829.0 112 | y: 577.0 113 | } 114 | size { 115 | x: 440.0 116 | y: 40.0 117 | } 118 | type: TYPE_TEXT 119 | font: "larryfont" 120 | id: "name" 121 | pivot: PIVOT_W 122 | outline { 123 | x: 1.0 124 | y: 1.0 125 | z: 1.0 126 | } 127 | shadow { 128 | x: 1.0 129 | y: 1.0 130 | z: 1.0 131 | } 132 | inherit_alpha: true 133 | } 134 | material: "/builtins/materials/gui.material" 135 | adjust_reference: ADJUST_REFERENCE_PARENT 136 | -------------------------------------------------------------------------------- /generated.appmanifest: -------------------------------------------------------------------------------- 1 | # App manifest generated Fri Nov 20 2020 09:28:33 GMT+0100 (Central European Standard Time) 2 | # Settings: OpenGL 3 | platforms: 4 | x86_64-osx: 5 | context: 6 | excludeLibs: [] 7 | excludeSymbols: [] 8 | symbols: [] 9 | libs: [] 10 | frameworks: [] 11 | linkFlags: [] 12 | 13 | x86_64-linux: 14 | context: 15 | excludeLibs: [] 16 | excludeSymbols: [] 17 | symbols: [] 18 | libs: [] 19 | linkFlags: [] 20 | 21 | js-web: 22 | context: 23 | excludeLibs: [] 24 | excludeJsLibs: [] 25 | excludeSymbols: [] 26 | symbols: [] 27 | libs: [] 28 | linkFlags: [] 29 | 30 | wasm-web: 31 | context: 32 | excludeLibs: [] 33 | excludeJsLibs: [] 34 | excludeSymbols: [] 35 | symbols: [] 36 | libs: [] 37 | linkFlags: [] 38 | 39 | x86-win32: 40 | context: 41 | excludeLibs: [] 42 | excludeSymbols: [] 43 | symbols: [] 44 | libs: [] 45 | linkFlags: [] 46 | 47 | x86_64-win32: 48 | context: 49 | excludeLibs: [] 50 | excludeSymbols: [] 51 | symbols: [] 52 | libs: [] 53 | linkFlags: [] 54 | 55 | armv7-android: 56 | context: 57 | excludeLibs: [] 58 | excludeJars: [] 59 | excludeSymbols: [] 60 | symbols: [] 61 | libs: [] 62 | linkFlags: [] 63 | jetifier: true 64 | 65 | arm64-android: 66 | context: 67 | excludeLibs: [] 68 | excludeJars: [] 69 | excludeSymbols: [] 70 | symbols: [] 71 | libs: [] 72 | linkFlags: [] 73 | jetifier: true 74 | 75 | armv7-ios: 76 | context: 77 | excludeLibs: [] 78 | excludeSymbols: [] 79 | symbols: [] 80 | libs: [] 81 | frameworks: [] 82 | linkFlags: [] 83 | 84 | arm64-ios: 85 | context: 86 | excludeLibs: [] 87 | excludeSymbols: [] 88 | symbols: [] 89 | libs: [] 90 | frameworks: [] 91 | linkFlags: [] 92 | 93 | x86_64-ios: 94 | context: 95 | excludeLibs: [] 96 | excludeSymbols: [] 97 | symbols: [] 98 | libs: [] 99 | frameworks: [] 100 | linkFlags: [] 101 | -------------------------------------------------------------------------------- /gpgs/src/gpgs_callback.cpp: -------------------------------------------------------------------------------- 1 | #if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_ANDROID) 2 | #include "private_gpgs_callback.h" 3 | #include 4 | 5 | static GPGS_callback m_callback; 6 | static dmArray m_callbacksQueue; 7 | static dmMutex::HMutex m_mutex; 8 | 9 | static void RegisterCallback(lua_State* L, int index) 10 | { 11 | GPGS_callback *cbk = &m_callback; 12 | if(cbk->m_Callback != LUA_NOREF) 13 | { 14 | dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Callback); 15 | dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Self); 16 | } 17 | 18 | cbk->m_L = dmScript::GetMainThread(L); 19 | 20 | luaL_checktype(L, index, LUA_TFUNCTION); 21 | lua_pushvalue(L, index); 22 | cbk->m_Callback = dmScript::Ref(L, LUA_REGISTRYINDEX); 23 | 24 | dmScript::GetInstance(L); 25 | cbk->m_Self = dmScript::Ref(L, LUA_REGISTRYINDEX); 26 | } 27 | 28 | static void UnregisterCallback() 29 | { 30 | GPGS_callback *cbk = &m_callback; 31 | if(cbk->m_Callback != LUA_NOREF) 32 | { 33 | dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Callback); 34 | dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Self); 35 | cbk->m_Callback = LUA_NOREF; 36 | } 37 | } 38 | 39 | static void gpgs_invoke_callback(MESSAGE_ID type, const char* json) 40 | { 41 | GPGS_callback *cbk = &m_callback; 42 | if(cbk->m_Callback == LUA_NOREF) 43 | { 44 | dmLogInfo("GPGS callback do not exist."); 45 | return; 46 | } 47 | 48 | lua_State* L = cbk->m_L; 49 | int top = lua_gettop(L); 50 | lua_rawgeti(L, LUA_REGISTRYINDEX, cbk->m_Callback); 51 | lua_rawgeti(L, LUA_REGISTRYINDEX, cbk->m_Self); 52 | lua_pushvalue(L, -1); 53 | dmScript::SetInstance(L); 54 | 55 | if (!dmScript::IsInstanceValid(L)) 56 | { 57 | UnregisterCallback(); 58 | dmLogError("Could not run GPGS callback because the instance has been deleted."); 59 | lua_pop(L, 2); 60 | } 61 | else { 62 | lua_pushnumber(L, type); 63 | dmScript::JsonToLua(L, json, strlen(json)); // throws lua error if it fails 64 | 65 | int number_of_arguments = 3; 66 | int ret = lua_pcall(L, number_of_arguments, 0, 0); 67 | if(ret != 0) 68 | { 69 | dmLogError("Error running callback: %s", lua_tostring(L, -1)); 70 | lua_pop(L, 1); 71 | } 72 | } 73 | assert(top == lua_gettop(L)); 74 | } 75 | 76 | void gpgs_callback_initialize() 77 | { 78 | m_mutex = dmMutex::New(); 79 | } 80 | 81 | void gpgs_callback_finalize() 82 | { 83 | dmMutex::Delete(m_mutex); 84 | UnregisterCallback(); 85 | } 86 | 87 | void gpgs_set_callback(lua_State* L, int pos) 88 | { 89 | int type = lua_type(L, pos); 90 | if (type == LUA_TNONE || type == LUA_TNIL) 91 | { 92 | UnregisterCallback(); 93 | } 94 | else 95 | { 96 | RegisterCallback(L, pos); 97 | } 98 | } 99 | 100 | void gpgs_add_to_queue(MESSAGE_ID msg, const char*json) 101 | { 102 | CallbackData data; 103 | data.msg = msg; 104 | data.json = json ? strdup(json) : NULL; 105 | 106 | DM_MUTEX_SCOPED_LOCK(m_mutex); 107 | if(m_callbacksQueue.Full()) 108 | { 109 | m_callbacksQueue.OffsetCapacity(1); 110 | } 111 | m_callbacksQueue.Push(data); 112 | } 113 | 114 | void gpgs_callback_update() 115 | { 116 | if (m_callbacksQueue.Empty()) 117 | { 118 | return; 119 | } 120 | 121 | dmArray tmp; 122 | { 123 | DM_MUTEX_SCOPED_LOCK(m_mutex); 124 | tmp.Swap(m_callbacksQueue); 125 | } 126 | 127 | for(uint32_t i = 0; i != tmp.Size(); ++i) 128 | { 129 | CallbackData* data = &tmp[i]; 130 | gpgs_invoke_callback(data->msg, data->json); 131 | if(data->json) 132 | { 133 | free(data->json); 134 | data->json = 0; 135 | } 136 | } 137 | } 138 | #endif 139 | -------------------------------------------------------------------------------- /main/menu.gui: -------------------------------------------------------------------------------- 1 | script: "/main/menu.gui_script" 2 | fonts { 3 | name: "larryfont" 4 | font: "/dirtylarry/larryfont.font" 5 | } 6 | textures { 7 | name: "logo" 8 | texture: "/main/logo.atlas" 9 | } 10 | nodes { 11 | position { 12 | x: 977.0 13 | y: 646.094 14 | } 15 | size { 16 | x: 300.0 17 | y: 100.0 18 | } 19 | type: TYPE_TEXT 20 | text: "Google Play Games Services" 21 | font: "larryfont" 22 | id: "title" 23 | outline { 24 | x: 1.0 25 | y: 1.0 26 | z: 1.0 27 | } 28 | shadow { 29 | x: 1.0 30 | y: 1.0 31 | z: 1.0 32 | } 33 | line_break: true 34 | inherit_alpha: true 35 | } 36 | nodes { 37 | position { 38 | x: 1206.857 39 | y: 645.837 40 | } 41 | type: TYPE_BOX 42 | texture: "logo/logo" 43 | id: "logo" 44 | inherit_alpha: true 45 | size_mode: SIZE_MODE_AUTO 46 | } 47 | nodes { 48 | position { 49 | x: 170.0 50 | y: 650.0 51 | } 52 | type: TYPE_TEMPLATE 53 | id: "authentication" 54 | inherit_alpha: true 55 | template: "/dirtylarry/button.gui" 56 | } 57 | nodes { 58 | type: TYPE_BOX 59 | id: "authentication/larrybutton" 60 | parent: "authentication" 61 | template_node_child: true 62 | } 63 | nodes { 64 | type: TYPE_TEXT 65 | text: "Authentication" 66 | id: "authentication/larrylabel" 67 | parent: "authentication/larrybutton" 68 | overridden_fields: 8 69 | template_node_child: true 70 | } 71 | nodes { 72 | position { 73 | x: 170.0 74 | y: 530.0 75 | } 76 | type: TYPE_TEMPLATE 77 | id: "snapshot" 78 | inherit_alpha: true 79 | template: "/dirtylarry/button.gui" 80 | } 81 | nodes { 82 | type: TYPE_BOX 83 | id: "snapshot/larrybutton" 84 | parent: "snapshot" 85 | template_node_child: true 86 | } 87 | nodes { 88 | type: TYPE_TEXT 89 | text: "Snapshot" 90 | id: "snapshot/larrylabel" 91 | parent: "snapshot/larrybutton" 92 | overridden_fields: 8 93 | template_node_child: true 94 | } 95 | nodes { 96 | position { 97 | x: 170.0 98 | y: 408.0 99 | } 100 | type: TYPE_TEMPLATE 101 | id: "achievements" 102 | inherit_alpha: true 103 | template: "/dirtylarry/button.gui" 104 | } 105 | nodes { 106 | type: TYPE_BOX 107 | id: "achievements/larrybutton" 108 | parent: "achievements" 109 | template_node_child: true 110 | } 111 | nodes { 112 | type: TYPE_TEXT 113 | text: "Achievements" 114 | id: "achievements/larrylabel" 115 | parent: "achievements/larrybutton" 116 | overridden_fields: 8 117 | template_node_child: true 118 | } 119 | nodes { 120 | position { 121 | x: 170.0 122 | y: 289.0 123 | } 124 | type: TYPE_TEMPLATE 125 | id: "leaderboards" 126 | inherit_alpha: true 127 | template: "/dirtylarry/button.gui" 128 | } 129 | nodes { 130 | type: TYPE_BOX 131 | id: "leaderboards/larrybutton" 132 | parent: "leaderboards" 133 | template_node_child: true 134 | } 135 | nodes { 136 | type: TYPE_TEXT 137 | text: "Leaderboards\t" 138 | id: "leaderboards/larrylabel" 139 | parent: "leaderboards/larrybutton" 140 | overridden_fields: 8 141 | template_node_child: true 142 | } 143 | nodes { 144 | position { 145 | x: 170.0 146 | y: 169.0 147 | } 148 | type: TYPE_TEMPLATE 149 | id: "events" 150 | inherit_alpha: true 151 | template: "/dirtylarry/button.gui" 152 | } 153 | nodes { 154 | type: TYPE_BOX 155 | id: "events/larrybutton" 156 | parent: "events" 157 | template_node_child: true 158 | } 159 | nodes { 160 | type: TYPE_TEXT 161 | text: "Events\t" 162 | id: "events/larrylabel" 163 | parent: "events/larrybutton" 164 | overridden_fields: 8 165 | template_node_child: true 166 | } 167 | nodes { 168 | position { 169 | x: 977.0 170 | y: 543.094 171 | } 172 | size { 173 | x: 300.0 174 | y: 100.0 175 | } 176 | type: TYPE_TEXT 177 | text: "Support Status" 178 | font: "larryfont" 179 | id: "support_status" 180 | outline { 181 | x: 1.0 182 | y: 1.0 183 | z: 1.0 184 | } 185 | shadow { 186 | x: 1.0 187 | y: 1.0 188 | z: 1.0 189 | } 190 | line_break: true 191 | inherit_alpha: true 192 | } 193 | material: "/builtins/materials/gui.material" 194 | adjust_reference: ADJUST_REFERENCE_PARENT 195 | -------------------------------------------------------------------------------- /main/snapshot.gui_script: -------------------------------------------------------------------------------- 1 | local dirtylarry = require "dirtylarry.dirtylarry" 2 | local monarch = require "monarch.monarch" 3 | 4 | 5 | local use_saved_games = sys.get_config_int("gpgs.use_saved_games") == 1 6 | 7 | local function gpgs_callback(self, message_id, message) 8 | if message_id == gpgs.MSG_LOAD_SNAPSHOT then 9 | if message.status == gpgs.STATUS_CONFLICT then 10 | self.conflictId = message.conflictId 11 | end 12 | end 13 | end 14 | 15 | function init(self) 16 | msg.post(".", "acquire_input_focus") 17 | if gpgs then 18 | gpgs.set_callback(gpgs_callback) 19 | end 20 | end 21 | 22 | function update(self, dt) 23 | if gpgs and use_saved_games then 24 | if self.snapshot_is_opened ~= gpgs.snapshot_is_opened() then 25 | self.snapshot_is_opened = gpgs.snapshot_is_opened() 26 | gui.set_text(gui.get_node("snapshotOpened"), "snapshot_is_opened: "..tostring(gpgs.snapshot_is_opened())) 27 | end 28 | if self.conflictId then 29 | gui.set_text(gui.get_node("snapshotConflict"), "conflict: "..tostring(self.conflictId)) 30 | else 31 | gui.set_text(gui.get_node("snapshotConflict"), "no conflict") 32 | end 33 | end 34 | end 35 | 36 | function on_input(self, action_id, action) 37 | dirtylarry:button("show_snapshots", action_id, action, function () 38 | if gpgs then 39 | gpgs.snapshot_display_saves("My cool saves", true, true, 3) 40 | end 41 | end) 42 | 43 | dirtylarry:button("snapshot_open", action_id, action, function () 44 | if gpgs then 45 | gpgs.snapshot_open("my_save", true, gpgs.RESOLUTION_POLICY_MANUAL) 46 | end 47 | end) 48 | 49 | dirtylarry:button("snapshot_get_data", action_id, action, function () 50 | if gpgs then 51 | local bytes, error_message = gpgs.snapshot_get_data() 52 | if not bytes then 53 | print("snapshot_get_data ERROR:", error_message) 54 | else 55 | print("snapshot_get_data",bytes) 56 | end 57 | end 58 | end) 59 | 60 | dirtylarry:button("save_snapshot", action_id, action, function () 61 | if gpgs then 62 | local png, w, h = screenshot.png() 63 | gpgs.snapshot_commit_and_close({ 64 | coverImage = png, 65 | description = "LEVEL 31, CAVE", 66 | playedTime = math.random(1000, 2000), 67 | progressValue = math.random(1000, 2000) 68 | }) 69 | end 70 | end) 71 | 72 | dirtylarry:button("snapshot_get_conflicting_data", action_id, action, function () 73 | if gpgs then 74 | local bytes, error_message = gpgs.snapshot_get_conflicting_data() 75 | if not bytes then 76 | print("snapshot_get_conflicting_data ERROR: ", error_message) 77 | else 78 | print("snapshot_get_conflicting_data: ",bytes) 79 | end 80 | end 81 | end) 82 | 83 | dirtylarry:button("snapshot_set_data", action_id, action, function () 84 | if gpgs then 85 | local success, error_message = gpgs.snapshot_set_data("MyCustomBytesForSnapshot") 86 | if not success then 87 | print("snapshot_set_data ERROR:", error_message) 88 | end 89 | end 90 | end) 91 | 92 | dirtylarry:button("snapshot_resolve_conflict", action_id, action, function () 93 | if gpgs then 94 | local success, error_message = gpgs.snapshot_resolve_conflict(self.conflictId, gpgs.SNAPSHOT_CURRENT) 95 | if not success then 96 | print("snapshot_resolve_conflict ERROR:", error_message) 97 | end 98 | end 99 | end) 100 | 101 | dirtylarry:button("snapshot_resolve_conflict_conflicting", action_id, action, function () 102 | if gpgs then 103 | gpgs.snapshot_resolve_conflict(self.conflictId, gpgs.SNAPSHOT_CONFLICTING) 104 | end 105 | end) 106 | 107 | dirtylarry:button("back", action_id, action, function () 108 | monarch.back() 109 | end) 110 | 111 | end -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Defold Google Play Game Services documentation 3 | brief: This manual covers how to setup and use Google Play Game Services in Defold. 4 | --- 5 | 6 | # Defold Google Play Game Services documentation 7 | 8 | This extension provides functions for interacting with Google Play Game Services. Supported on Android. The extension supports the following services: 9 | 10 | * Achievements 11 | * Authentication 12 | * Cloud save 13 | * Events 14 | * Leaderboards 15 | 16 | 17 | ## Installation 18 | To use this library in your Defold project, add the following URL to your `game.project` dependencies: 19 | 20 | https://github.com/defold/extension-gpgs/archive/master.zip 21 | 22 | We recommend using a link to a zip file of a [specific release](https://github.com/defold/extension-gpgs/releases). 23 | 24 | 25 | ## Google App Setup 26 | 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](https://support.google.com/googleplay/android-developer/answer/6112435). 27 | 28 | 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](https://developers.google.com/games/services/console/enabling). 29 | 30 | 31 | ## Defold Setup 32 | 33 | Add the following section into your `game.project` file (open and edit as a text file): 34 | 35 | ``` 36 | [gpgs] 37 | app_id = 1234567890 38 | use_saved_games = 1 39 | request_server_auth_code = 0 40 | ``` 41 | 42 | Where `app_id` is the 12 or 13 digit Project ID from the Google Play Console. The Project ID can be found under "Grow users" > "Play Games Services" > "Setup and management" > "Configuration". 43 | 44 | Where `use_saved_games` indicates if the [Game Saves service](https://developers.google.com/games/services/common/concepts/savedgames) should be used (0 is disabled, 1 is enabled). 45 | 46 | If you want to retrieve server auth code set `gpgs.request_server_auth_code` to 1 and provide `gpgs.client_token`. Client token should be configured to Web application. 47 | 48 | ## Usage 49 | 50 | The API uses a callback based system where events and data coming from Google Play Game Services are passed to the game client through a callback function. The kind of event coming from Google Play Game Services is identified by a pre-defined event id. Example: 51 | 52 | ```Lua 53 | local function gpgs_callback(self, message_id, message) 54 | if message_id == gpgs.MSG_SIGN_IN then 55 | print("Signed in") 56 | end 57 | end 58 | 59 | gpgs.set_callback(gpgs_callback) 60 | ``` 61 | 62 | ### Authentication: 63 | 64 | ```Lua 65 | 66 | local function gpgs_callback(self, message_id, message) 67 | if message_id == gpgs.MSG_SIGN_IN or message_id == gpgs.MSG_SILENT_SIGN_IN then 68 | if message.status == gpgs.STATUS_SUCCESS then 69 | print("Signed in") 70 | print(gpgs.get_id()) 71 | print(gpgs.get_display_name()) 72 | else 73 | print("Sign in error!") 74 | end 75 | end 76 | end 77 | 78 | gpgs.set_callback(gpgs_callback) 79 | gpgs.silent_login() 80 | 81 | ``` 82 | 83 | 84 | ### Achievements 85 | 86 | ```Lua 87 | gpgs.achievement_reveal("CgkIq5-gxcsVEAIQAQ") 88 | gpgs.achievement_unlock("CgkIq5-gxcsVEAIQAQ") 89 | gpgs.achievement_increment("CgkIq5-gxcsVEAIQAQ", 1) 90 | gpgs.achievement_set("CgkIq5-gxcsVEAIQAQ", 10) 91 | gpgs.achievement_show() 92 | gpgs.achievement_get() 93 | ``` 94 | 95 | 96 | ### Cloud save 97 | 98 | ```Lua 99 | local function gpgs_callback(self, message_id, message) 100 | if message_id == gpgs.MSG_LOAD_SNAPSHOT then 101 | if message.status == gpgs.STATUS_CONFLICT then 102 | print(message.conflictId) 103 | end 104 | end 105 | end 106 | 107 | 108 | gpgs.set_callback(gpgs_callback) 109 | 110 | gpgs.snapshot_display_saves("My saves", true, true, 3) 111 | gpgs.snapshot_open("my_save", true, gpgs.RESOLUTION_POLICY_MANUAL) 112 | 113 | local success, error_message = gpgs.snapshot_set_data("MyCustomBytesForSnapshot") 114 | 115 | local bytes, error_message = gpgs.snapshot_get_data() 116 | local bytes, error_message = gpgs.snapshot_get_conflicting_data() 117 | 118 | gpgs.snapshot_resolve_conflict(self.conflictId, gpgs.SNAPSHOT_CURRENT) 119 | gpgs.snapshot_resolve_conflict(self.conflictId, gpgs.SNAPSHOT_CONFLICTING) 120 | 121 | gpgs.snapshot_commit_and_close({ 122 | coverImage = screenshot.png(), 123 | description = "LEVEL 31, CAVE", 124 | playedTime = 1000, 125 | progressValue = 1234 126 | }) 127 | 128 | gpgs.snapshot_is_opened() 129 | 130 | ``` 131 | 132 | 133 | ### Events 134 | 135 | ```lua 136 | local function gpgs_callback(self, message_id, message) 137 | if message_id == gpgs.MSG_GET_EVENTS then 138 | for _,event in ipairs(message) do 139 | event = json.decode(event) 140 | print(event.name, event.id, event.value) 141 | end 142 | end 143 | end 144 | 145 | gpgs.set_callback(gpgs_callback) 146 | gpgs.event_increment("CgkIq5-gxcsVEAIQAw", 1) 147 | gpgs.event_get() 148 | ``` 149 | 150 | 151 | ### Leaderboards 152 | 153 | ```Lua 154 | 155 | local function gpgs_callback(self, message_id, message) 156 | if message_id == gpgs.MSG_GET_PLAYER_SCORE then 157 | print(message.display_score, message.display_rank) 158 | elseif message_id == gpgs.MSG_GET_PLAYER_CENTERED_SCORES or message_id == gpgs.MSG_GET_TOP_SCORES then 159 | for _,score in ipairs(message) do 160 | score = json.decode(score) 161 | print(score.score_holder_name, score.display_score, score.display_rank) 162 | end 163 | end 164 | end 165 | 166 | gpgs.set_callback(gpgs_callback) 167 | 168 | gpgs.leaderboard_submit_score("CgkIq5-gxcsVEAIQAg", 1337) 169 | gpgs.leaderboard_get_top_scores("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC, 10) 170 | gpgs.leaderboard_get_player_centered_scores("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC, 10) 171 | gpgs.leaderboard_get_player_score("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC) 172 | gpgs.leaderboard_show("CgkIq5-gxcsVEAIQAg", gpgs.TIME_SPAN_ALL_TIME, gpgs.COLLECTION_PUBLIC) 173 | ``` 174 | 175 | 176 | 177 | ## Source code 178 | 179 | The source code is available on [GitHub](https://github.com/defold/extension-gpgs) 180 | -------------------------------------------------------------------------------- /main/main.collection: -------------------------------------------------------------------------------- 1 | name: "main" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "main" 5 | data: "components {\n" 6 | " id: \"main\"\n" 7 | " component: \"/main/main.script\"\n" 8 | " position {\n" 9 | " x: 0.0\n" 10 | " y: 0.0\n" 11 | " z: 0.0\n" 12 | " }\n" 13 | " rotation {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " w: 1.0\n" 18 | " }\n" 19 | "}\n" 20 | "" 21 | position { 22 | x: 0.0 23 | y: 0.0 24 | z: 0.0 25 | } 26 | rotation { 27 | x: 0.0 28 | y: 0.0 29 | z: 0.0 30 | w: 1.0 31 | } 32 | scale3 { 33 | x: 1.0 34 | y: 1.0 35 | z: 1.0 36 | } 37 | } 38 | embedded_instances { 39 | id: "authentication" 40 | data: "components {\n" 41 | " id: \"screen_proxy\"\n" 42 | " component: \"/monarch/screen_proxy.script\"\n" 43 | " position {\n" 44 | " x: 0.0\n" 45 | " y: 0.0\n" 46 | " z: 0.0\n" 47 | " }\n" 48 | " rotation {\n" 49 | " x: 0.0\n" 50 | " y: 0.0\n" 51 | " z: 0.0\n" 52 | " w: 1.0\n" 53 | " }\n" 54 | " properties {\n" 55 | " id: \"screen_id\"\n" 56 | " value: \"authentication\"\n" 57 | " type: PROPERTY_TYPE_HASH\n" 58 | " }\n" 59 | "}\n" 60 | "embedded_components {\n" 61 | " id: \"collectionproxy\"\n" 62 | " type: \"collectionproxy\"\n" 63 | " data: \"collection: \\\"/main/authentication.collection\\\"\\n" 64 | "exclude: false\\n" 65 | "\"\n" 66 | " position {\n" 67 | " x: 0.0\n" 68 | " y: 0.0\n" 69 | " z: 0.0\n" 70 | " }\n" 71 | " rotation {\n" 72 | " x: 0.0\n" 73 | " y: 0.0\n" 74 | " z: 0.0\n" 75 | " w: 1.0\n" 76 | " }\n" 77 | "}\n" 78 | "" 79 | position { 80 | x: 0.0 81 | y: 0.0 82 | z: 0.0 83 | } 84 | rotation { 85 | x: 0.0 86 | y: 0.0 87 | z: 0.0 88 | w: 1.0 89 | } 90 | scale3 { 91 | x: 1.0 92 | y: 1.0 93 | z: 1.0 94 | } 95 | } 96 | embedded_instances { 97 | id: "menu" 98 | data: "components {\n" 99 | " id: \"screen_proxy\"\n" 100 | " component: \"/monarch/screen_proxy.script\"\n" 101 | " position {\n" 102 | " x: 0.0\n" 103 | " y: 0.0\n" 104 | " z: 0.0\n" 105 | " }\n" 106 | " rotation {\n" 107 | " x: 0.0\n" 108 | " y: 0.0\n" 109 | " z: 0.0\n" 110 | " w: 1.0\n" 111 | " }\n" 112 | " properties {\n" 113 | " id: \"screen_id\"\n" 114 | " value: \"menu\"\n" 115 | " type: PROPERTY_TYPE_HASH\n" 116 | " }\n" 117 | "}\n" 118 | "embedded_components {\n" 119 | " id: \"collectionproxy\"\n" 120 | " type: \"collectionproxy\"\n" 121 | " data: \"collection: \\\"/main/menu.collection\\\"\\n" 122 | "exclude: false\\n" 123 | "\"\n" 124 | " position {\n" 125 | " x: 0.0\n" 126 | " y: 0.0\n" 127 | " z: 0.0\n" 128 | " }\n" 129 | " rotation {\n" 130 | " x: 0.0\n" 131 | " y: 0.0\n" 132 | " z: 0.0\n" 133 | " w: 1.0\n" 134 | " }\n" 135 | "}\n" 136 | "" 137 | position { 138 | x: 0.0 139 | y: 0.0 140 | z: 0.0 141 | } 142 | rotation { 143 | x: 0.0 144 | y: 0.0 145 | z: 0.0 146 | w: 1.0 147 | } 148 | scale3 { 149 | x: 1.0 150 | y: 1.0 151 | z: 1.0 152 | } 153 | } 154 | embedded_instances { 155 | id: "snapshot" 156 | data: "components {\n" 157 | " id: \"screen_proxy\"\n" 158 | " component: \"/monarch/screen_proxy.script\"\n" 159 | " position {\n" 160 | " x: 0.0\n" 161 | " y: 0.0\n" 162 | " z: 0.0\n" 163 | " }\n" 164 | " rotation {\n" 165 | " x: 0.0\n" 166 | " y: 0.0\n" 167 | " z: 0.0\n" 168 | " w: 1.0\n" 169 | " }\n" 170 | " properties {\n" 171 | " id: \"screen_id\"\n" 172 | " value: \"snapshot\"\n" 173 | " type: PROPERTY_TYPE_HASH\n" 174 | " }\n" 175 | "}\n" 176 | "embedded_components {\n" 177 | " id: \"collectionproxy\"\n" 178 | " type: \"collectionproxy\"\n" 179 | " data: \"collection: \\\"/main/snapshot.collection\\\"\\n" 180 | "exclude: false\\n" 181 | "\"\n" 182 | " position {\n" 183 | " x: 0.0\n" 184 | " y: 0.0\n" 185 | " z: 0.0\n" 186 | " }\n" 187 | " rotation {\n" 188 | " x: 0.0\n" 189 | " y: 0.0\n" 190 | " z: 0.0\n" 191 | " w: 1.0\n" 192 | " }\n" 193 | "}\n" 194 | "" 195 | position { 196 | x: 0.0 197 | y: 0.0 198 | z: 0.0 199 | } 200 | rotation { 201 | x: 0.0 202 | y: 0.0 203 | z: 0.0 204 | w: 1.0 205 | } 206 | scale3 { 207 | x: 1.0 208 | y: 1.0 209 | z: 1.0 210 | } 211 | } 212 | embedded_instances { 213 | id: "achievements" 214 | data: "components {\n" 215 | " id: \"screen_proxy\"\n" 216 | " component: \"/monarch/screen_proxy.script\"\n" 217 | " position {\n" 218 | " x: 0.0\n" 219 | " y: 0.0\n" 220 | " z: 0.0\n" 221 | " }\n" 222 | " rotation {\n" 223 | " x: 0.0\n" 224 | " y: 0.0\n" 225 | " z: 0.0\n" 226 | " w: 1.0\n" 227 | " }\n" 228 | " properties {\n" 229 | " id: \"screen_id\"\n" 230 | " value: \"achievements\"\n" 231 | " type: PROPERTY_TYPE_HASH\n" 232 | " }\n" 233 | "}\n" 234 | "embedded_components {\n" 235 | " id: \"collectionproxy\"\n" 236 | " type: \"collectionproxy\"\n" 237 | " data: \"collection: \\\"/main/achievements.collection\\\"\\n" 238 | "exclude: false\\n" 239 | "\"\n" 240 | " position {\n" 241 | " x: 0.0\n" 242 | " y: 0.0\n" 243 | " z: 0.0\n" 244 | " }\n" 245 | " rotation {\n" 246 | " x: 0.0\n" 247 | " y: 0.0\n" 248 | " z: 0.0\n" 249 | " w: 1.0\n" 250 | " }\n" 251 | "}\n" 252 | "" 253 | position { 254 | x: 0.0 255 | y: 0.0 256 | z: 0.0 257 | } 258 | rotation { 259 | x: 0.0 260 | y: 0.0 261 | z: 0.0 262 | w: 1.0 263 | } 264 | scale3 { 265 | x: 1.0 266 | y: 1.0 267 | z: 1.0 268 | } 269 | } 270 | embedded_instances { 271 | id: "leaderboards" 272 | data: "components {\n" 273 | " id: \"screen_proxy\"\n" 274 | " component: \"/monarch/screen_proxy.script\"\n" 275 | " position {\n" 276 | " x: 0.0\n" 277 | " y: 0.0\n" 278 | " z: 0.0\n" 279 | " }\n" 280 | " rotation {\n" 281 | " x: 0.0\n" 282 | " y: 0.0\n" 283 | " z: 0.0\n" 284 | " w: 1.0\n" 285 | " }\n" 286 | " properties {\n" 287 | " id: \"screen_id\"\n" 288 | " value: \"leaderboards\"\n" 289 | " type: PROPERTY_TYPE_HASH\n" 290 | " }\n" 291 | "}\n" 292 | "embedded_components {\n" 293 | " id: \"collectionproxy\"\n" 294 | " type: \"collectionproxy\"\n" 295 | " data: \"collection: \\\"/main/leaderboards.collection\\\"\\n" 296 | "exclude: false\\n" 297 | "\"\n" 298 | " position {\n" 299 | " x: 0.0\n" 300 | " y: 0.0\n" 301 | " z: 0.0\n" 302 | " }\n" 303 | " rotation {\n" 304 | " x: 0.0\n" 305 | " y: 0.0\n" 306 | " z: 0.0\n" 307 | " w: 1.0\n" 308 | " }\n" 309 | "}\n" 310 | "" 311 | position { 312 | x: 0.0 313 | y: 0.0 314 | z: 0.0 315 | } 316 | rotation { 317 | x: 0.0 318 | y: 0.0 319 | z: 0.0 320 | w: 1.0 321 | } 322 | scale3 { 323 | x: 1.0 324 | y: 1.0 325 | z: 1.0 326 | } 327 | } 328 | embedded_instances { 329 | id: "events" 330 | data: "components {\n" 331 | " id: \"screen_proxy\"\n" 332 | " component: \"/monarch/screen_proxy.script\"\n" 333 | " position {\n" 334 | " x: 0.0\n" 335 | " y: 0.0\n" 336 | " z: 0.0\n" 337 | " }\n" 338 | " rotation {\n" 339 | " x: 0.0\n" 340 | " y: 0.0\n" 341 | " z: 0.0\n" 342 | " w: 1.0\n" 343 | " }\n" 344 | " properties {\n" 345 | " id: \"screen_id\"\n" 346 | " value: \"events\"\n" 347 | " type: PROPERTY_TYPE_HASH\n" 348 | " }\n" 349 | "}\n" 350 | "embedded_components {\n" 351 | " id: \"collectionproxy\"\n" 352 | " type: \"collectionproxy\"\n" 353 | " data: \"collection: \\\"/main/events.collection\\\"\\n" 354 | "exclude: false\\n" 355 | "\"\n" 356 | " position {\n" 357 | " x: 0.0\n" 358 | " y: 0.0\n" 359 | " z: 0.0\n" 360 | " }\n" 361 | " rotation {\n" 362 | " x: 0.0\n" 363 | " y: 0.0\n" 364 | " z: 0.0\n" 365 | " w: 1.0\n" 366 | " }\n" 367 | "}\n" 368 | "" 369 | position { 370 | x: 0.0 371 | y: 0.0 372 | z: 0.0 373 | } 374 | rotation { 375 | x: 0.0 376 | y: 0.0 377 | z: 0.0 378 | w: 1.0 379 | } 380 | scale3 { 381 | x: 1.0 382 | y: 1.0 383 | z: 1.0 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /main/events.gui: -------------------------------------------------------------------------------- 1 | script: "/main/events.gui_script" 2 | fonts { 3 | name: "larryfont" 4 | font: "/dirtylarry/larryfont.font" 5 | } 6 | textures { 7 | name: "dirtylarry" 8 | texture: "/dirtylarry/dirtylarry.atlas" 9 | } 10 | background_color { 11 | x: 0.0 12 | y: 0.0 13 | z: 0.0 14 | w: 0.0 15 | } 16 | nodes { 17 | position { 18 | x: 170.0 19 | y: 60.0 20 | z: 0.0 21 | w: 1.0 22 | } 23 | rotation { 24 | x: 0.0 25 | y: 0.0 26 | z: 0.0 27 | w: 1.0 28 | } 29 | scale { 30 | x: 1.0 31 | y: 1.0 32 | z: 1.0 33 | w: 1.0 34 | } 35 | size { 36 | x: 200.0 37 | y: 100.0 38 | z: 0.0 39 | w: 1.0 40 | } 41 | color { 42 | x: 1.0 43 | y: 1.0 44 | z: 1.0 45 | w: 1.0 46 | } 47 | type: TYPE_TEMPLATE 48 | id: "back" 49 | layer: "" 50 | inherit_alpha: true 51 | alpha: 1.0 52 | template: "/dirtylarry/button.gui" 53 | template_node_child: false 54 | } 55 | nodes { 56 | position { 57 | x: 0.0 58 | y: 0.0 59 | z: 0.0 60 | w: 1.0 61 | } 62 | rotation { 63 | x: 0.0 64 | y: 0.0 65 | z: 0.0 66 | w: 1.0 67 | } 68 | scale { 69 | x: 1.0 70 | y: 1.0 71 | z: 1.0 72 | w: 1.0 73 | } 74 | size { 75 | x: 300.0 76 | y: 88.0 77 | z: 0.0 78 | w: 1.0 79 | } 80 | color { 81 | x: 1.0 82 | y: 1.0 83 | z: 1.0 84 | w: 1.0 85 | } 86 | type: TYPE_BOX 87 | blend_mode: BLEND_MODE_ALPHA 88 | texture: "button/button_normal" 89 | id: "back/larrybutton" 90 | xanchor: XANCHOR_NONE 91 | yanchor: YANCHOR_NONE 92 | pivot: PIVOT_CENTER 93 | adjust_mode: ADJUST_MODE_FIT 94 | parent: "back" 95 | layer: "" 96 | inherit_alpha: true 97 | slice9 { 98 | x: 32.0 99 | y: 32.0 100 | z: 32.0 101 | w: 32.0 102 | } 103 | clipping_mode: CLIPPING_MODE_NONE 104 | clipping_visible: true 105 | clipping_inverted: false 106 | alpha: 1.0 107 | overridden_fields: 38 108 | template_node_child: true 109 | size_mode: SIZE_MODE_MANUAL 110 | } 111 | nodes { 112 | position { 113 | x: 0.0 114 | y: 0.0 115 | z: 0.0 116 | w: 1.0 117 | } 118 | rotation { 119 | x: 0.0 120 | y: 0.0 121 | z: 0.0 122 | w: 1.0 123 | } 124 | scale { 125 | x: 1.0 126 | y: 1.0 127 | z: 1.0 128 | w: 1.0 129 | } 130 | size { 131 | x: 200.0 132 | y: 100.0 133 | z: 0.0 134 | w: 1.0 135 | } 136 | color { 137 | x: 1.0 138 | y: 1.0 139 | z: 1.0 140 | w: 1.0 141 | } 142 | type: TYPE_TEXT 143 | blend_mode: BLEND_MODE_ALPHA 144 | text: "BACK" 145 | font: "larryfont" 146 | id: "back/larrylabel" 147 | xanchor: XANCHOR_NONE 148 | yanchor: YANCHOR_NONE 149 | pivot: PIVOT_CENTER 150 | outline { 151 | x: 0.0 152 | y: 0.0 153 | z: 0.0 154 | w: 1.0 155 | } 156 | shadow { 157 | x: 1.0 158 | y: 1.0 159 | z: 1.0 160 | w: 1.0 161 | } 162 | adjust_mode: ADJUST_MODE_FIT 163 | line_break: false 164 | parent: "back/larrybutton" 165 | layer: "" 166 | inherit_alpha: true 167 | alpha: 1.0 168 | outline_alpha: 1.0 169 | shadow_alpha: 1.0 170 | overridden_fields: 8 171 | template_node_child: true 172 | text_leading: 1.0 173 | text_tracking: 0.0 174 | } 175 | nodes { 176 | position { 177 | x: 170.0 178 | y: 653.0 179 | z: 0.0 180 | w: 1.0 181 | } 182 | rotation { 183 | x: 0.0 184 | y: 0.0 185 | z: 0.0 186 | w: 1.0 187 | } 188 | scale { 189 | x: 1.0 190 | y: 1.0 191 | z: 1.0 192 | w: 1.0 193 | } 194 | size { 195 | x: 200.0 196 | y: 100.0 197 | z: 0.0 198 | w: 1.0 199 | } 200 | color { 201 | x: 1.0 202 | y: 1.0 203 | z: 1.0 204 | w: 1.0 205 | } 206 | type: TYPE_TEMPLATE 207 | id: "kill_zombie" 208 | layer: "" 209 | inherit_alpha: true 210 | alpha: 1.0 211 | template: "/dirtylarry/button.gui" 212 | template_node_child: false 213 | } 214 | nodes { 215 | position { 216 | x: 0.0 217 | y: 0.0 218 | z: 0.0 219 | w: 1.0 220 | } 221 | rotation { 222 | x: 0.0 223 | y: 0.0 224 | z: 0.0 225 | w: 1.0 226 | } 227 | scale { 228 | x: 1.0 229 | y: 1.0 230 | z: 1.0 231 | w: 1.0 232 | } 233 | size { 234 | x: 300.0 235 | y: 88.0 236 | z: 0.0 237 | w: 1.0 238 | } 239 | color { 240 | x: 1.0 241 | y: 1.0 242 | z: 1.0 243 | w: 1.0 244 | } 245 | type: TYPE_BOX 246 | blend_mode: BLEND_MODE_ALPHA 247 | texture: "button/button_normal" 248 | id: "kill_zombie/larrybutton" 249 | xanchor: XANCHOR_NONE 250 | yanchor: YANCHOR_NONE 251 | pivot: PIVOT_CENTER 252 | adjust_mode: ADJUST_MODE_FIT 253 | parent: "kill_zombie" 254 | layer: "" 255 | inherit_alpha: true 256 | slice9 { 257 | x: 32.0 258 | y: 32.0 259 | z: 32.0 260 | w: 32.0 261 | } 262 | clipping_mode: CLIPPING_MODE_NONE 263 | clipping_visible: true 264 | clipping_inverted: false 265 | alpha: 1.0 266 | overridden_fields: 38 267 | template_node_child: true 268 | size_mode: SIZE_MODE_MANUAL 269 | } 270 | nodes { 271 | position { 272 | x: 0.0 273 | y: 0.0 274 | z: 0.0 275 | w: 1.0 276 | } 277 | rotation { 278 | x: 0.0 279 | y: 0.0 280 | z: 0.0 281 | w: 1.0 282 | } 283 | scale { 284 | x: 1.0 285 | y: 1.0 286 | z: 1.0 287 | w: 1.0 288 | } 289 | size { 290 | x: 200.0 291 | y: 100.0 292 | z: 0.0 293 | w: 1.0 294 | } 295 | color { 296 | x: 1.0 297 | y: 1.0 298 | z: 1.0 299 | w: 1.0 300 | } 301 | type: TYPE_TEXT 302 | blend_mode: BLEND_MODE_ALPHA 303 | text: "Kill Zombie" 304 | font: "larryfont" 305 | id: "kill_zombie/larrylabel" 306 | xanchor: XANCHOR_NONE 307 | yanchor: YANCHOR_NONE 308 | pivot: PIVOT_CENTER 309 | outline { 310 | x: 0.0 311 | y: 0.0 312 | z: 0.0 313 | w: 1.0 314 | } 315 | shadow { 316 | x: 1.0 317 | y: 1.0 318 | z: 1.0 319 | w: 1.0 320 | } 321 | adjust_mode: ADJUST_MODE_FIT 322 | line_break: false 323 | parent: "kill_zombie/larrybutton" 324 | layer: "" 325 | inherit_alpha: true 326 | alpha: 1.0 327 | outline_alpha: 1.0 328 | shadow_alpha: 1.0 329 | overridden_fields: 8 330 | template_node_child: true 331 | text_leading: 1.0 332 | text_tracking: 0.0 333 | } 334 | nodes { 335 | position { 336 | x: 170.0 337 | y: 532.0 338 | z: 0.0 339 | w: 1.0 340 | } 341 | rotation { 342 | x: 0.0 343 | y: 0.0 344 | z: 0.0 345 | w: 1.0 346 | } 347 | scale { 348 | x: 1.0 349 | y: 1.0 350 | z: 1.0 351 | w: 1.0 352 | } 353 | size { 354 | x: 200.0 355 | y: 100.0 356 | z: 0.0 357 | w: 1.0 358 | } 359 | color { 360 | x: 1.0 361 | y: 1.0 362 | z: 1.0 363 | w: 1.0 364 | } 365 | type: TYPE_TEMPLATE 366 | id: "earn_gold" 367 | layer: "" 368 | inherit_alpha: true 369 | alpha: 1.0 370 | template: "/dirtylarry/button.gui" 371 | template_node_child: false 372 | } 373 | nodes { 374 | position { 375 | x: 0.0 376 | y: 0.0 377 | z: 0.0 378 | w: 1.0 379 | } 380 | rotation { 381 | x: 0.0 382 | y: 0.0 383 | z: 0.0 384 | w: 1.0 385 | } 386 | scale { 387 | x: 1.0 388 | y: 1.0 389 | z: 1.0 390 | w: 1.0 391 | } 392 | size { 393 | x: 300.0 394 | y: 88.0 395 | z: 0.0 396 | w: 1.0 397 | } 398 | color { 399 | x: 1.0 400 | y: 1.0 401 | z: 1.0 402 | w: 1.0 403 | } 404 | type: TYPE_BOX 405 | blend_mode: BLEND_MODE_ALPHA 406 | texture: "button/button_normal" 407 | id: "earn_gold/larrybutton" 408 | xanchor: XANCHOR_NONE 409 | yanchor: YANCHOR_NONE 410 | pivot: PIVOT_CENTER 411 | adjust_mode: ADJUST_MODE_FIT 412 | parent: "earn_gold" 413 | layer: "" 414 | inherit_alpha: true 415 | slice9 { 416 | x: 32.0 417 | y: 32.0 418 | z: 32.0 419 | w: 32.0 420 | } 421 | clipping_mode: CLIPPING_MODE_NONE 422 | clipping_visible: true 423 | clipping_inverted: false 424 | alpha: 1.0 425 | overridden_fields: 38 426 | template_node_child: true 427 | size_mode: SIZE_MODE_MANUAL 428 | } 429 | nodes { 430 | position { 431 | x: 0.0 432 | y: 0.0 433 | z: 0.0 434 | w: 1.0 435 | } 436 | rotation { 437 | x: 0.0 438 | y: 0.0 439 | z: 0.0 440 | w: 1.0 441 | } 442 | scale { 443 | x: 1.0 444 | y: 1.0 445 | z: 1.0 446 | w: 1.0 447 | } 448 | size { 449 | x: 200.0 450 | y: 100.0 451 | z: 0.0 452 | w: 1.0 453 | } 454 | color { 455 | x: 1.0 456 | y: 1.0 457 | z: 1.0 458 | w: 1.0 459 | } 460 | type: TYPE_TEXT 461 | blend_mode: BLEND_MODE_ALPHA 462 | text: "Earn Gold" 463 | font: "larryfont" 464 | id: "earn_gold/larrylabel" 465 | xanchor: XANCHOR_NONE 466 | yanchor: YANCHOR_NONE 467 | pivot: PIVOT_CENTER 468 | outline { 469 | x: 0.0 470 | y: 0.0 471 | z: 0.0 472 | w: 1.0 473 | } 474 | shadow { 475 | x: 1.0 476 | y: 1.0 477 | z: 1.0 478 | w: 1.0 479 | } 480 | adjust_mode: ADJUST_MODE_FIT 481 | line_break: false 482 | parent: "earn_gold/larrybutton" 483 | layer: "" 484 | inherit_alpha: true 485 | alpha: 1.0 486 | outline_alpha: 1.0 487 | shadow_alpha: 1.0 488 | overridden_fields: 8 489 | template_node_child: true 490 | text_leading: 1.0 491 | text_tracking: 0.0 492 | } 493 | nodes { 494 | position { 495 | x: 170.0 496 | y: 411.0 497 | z: 0.0 498 | w: 1.0 499 | } 500 | rotation { 501 | x: 0.0 502 | y: 0.0 503 | z: 0.0 504 | w: 1.0 505 | } 506 | scale { 507 | x: 1.0 508 | y: 1.0 509 | z: 1.0 510 | w: 1.0 511 | } 512 | size { 513 | x: 200.0 514 | y: 100.0 515 | z: 0.0 516 | w: 1.0 517 | } 518 | color { 519 | x: 1.0 520 | y: 1.0 521 | z: 1.0 522 | w: 1.0 523 | } 524 | type: TYPE_TEMPLATE 525 | id: "spend_gold" 526 | layer: "" 527 | inherit_alpha: true 528 | alpha: 1.0 529 | template: "/dirtylarry/button.gui" 530 | template_node_child: false 531 | } 532 | nodes { 533 | position { 534 | x: 0.0 535 | y: 0.0 536 | z: 0.0 537 | w: 1.0 538 | } 539 | rotation { 540 | x: 0.0 541 | y: 0.0 542 | z: 0.0 543 | w: 1.0 544 | } 545 | scale { 546 | x: 1.0 547 | y: 1.0 548 | z: 1.0 549 | w: 1.0 550 | } 551 | size { 552 | x: 300.0 553 | y: 88.0 554 | z: 0.0 555 | w: 1.0 556 | } 557 | color { 558 | x: 1.0 559 | y: 1.0 560 | z: 1.0 561 | w: 1.0 562 | } 563 | type: TYPE_BOX 564 | blend_mode: BLEND_MODE_ALPHA 565 | texture: "button/button_normal" 566 | id: "spend_gold/larrybutton" 567 | xanchor: XANCHOR_NONE 568 | yanchor: YANCHOR_NONE 569 | pivot: PIVOT_CENTER 570 | adjust_mode: ADJUST_MODE_FIT 571 | parent: "spend_gold" 572 | layer: "" 573 | inherit_alpha: true 574 | slice9 { 575 | x: 32.0 576 | y: 32.0 577 | z: 32.0 578 | w: 32.0 579 | } 580 | clipping_mode: CLIPPING_MODE_NONE 581 | clipping_visible: true 582 | clipping_inverted: false 583 | alpha: 1.0 584 | overridden_fields: 38 585 | template_node_child: true 586 | size_mode: SIZE_MODE_MANUAL 587 | } 588 | nodes { 589 | position { 590 | x: 0.0 591 | y: 0.0 592 | z: 0.0 593 | w: 1.0 594 | } 595 | rotation { 596 | x: 0.0 597 | y: 0.0 598 | z: 0.0 599 | w: 1.0 600 | } 601 | scale { 602 | x: 1.0 603 | y: 1.0 604 | z: 1.0 605 | w: 1.0 606 | } 607 | size { 608 | x: 200.0 609 | y: 100.0 610 | z: 0.0 611 | w: 1.0 612 | } 613 | color { 614 | x: 1.0 615 | y: 1.0 616 | z: 1.0 617 | w: 1.0 618 | } 619 | type: TYPE_TEXT 620 | blend_mode: BLEND_MODE_ALPHA 621 | text: "Spend Gold" 622 | font: "larryfont" 623 | id: "spend_gold/larrylabel" 624 | xanchor: XANCHOR_NONE 625 | yanchor: YANCHOR_NONE 626 | pivot: PIVOT_CENTER 627 | outline { 628 | x: 0.0 629 | y: 0.0 630 | z: 0.0 631 | w: 1.0 632 | } 633 | shadow { 634 | x: 1.0 635 | y: 1.0 636 | z: 1.0 637 | w: 1.0 638 | } 639 | adjust_mode: ADJUST_MODE_FIT 640 | line_break: false 641 | parent: "spend_gold/larrybutton" 642 | layer: "" 643 | inherit_alpha: true 644 | alpha: 1.0 645 | outline_alpha: 1.0 646 | shadow_alpha: 1.0 647 | overridden_fields: 8 648 | template_node_child: true 649 | text_leading: 1.0 650 | text_tracking: 0.0 651 | } 652 | nodes { 653 | position { 654 | x: 656.0 655 | y: 653.0 656 | z: 0.0 657 | w: 1.0 658 | } 659 | rotation { 660 | x: 0.0 661 | y: 0.0 662 | z: 0.0 663 | w: 1.0 664 | } 665 | scale { 666 | x: 1.0 667 | y: 1.0 668 | z: 1.0 669 | w: 1.0 670 | } 671 | size { 672 | x: 200.0 673 | y: 100.0 674 | z: 0.0 675 | w: 1.0 676 | } 677 | color { 678 | x: 1.0 679 | y: 1.0 680 | z: 1.0 681 | w: 1.0 682 | } 683 | type: TYPE_TEMPLATE 684 | id: "get" 685 | layer: "" 686 | inherit_alpha: true 687 | alpha: 1.0 688 | template: "/dirtylarry/button.gui" 689 | template_node_child: false 690 | } 691 | nodes { 692 | position { 693 | x: 0.0 694 | y: 0.0 695 | z: 0.0 696 | w: 1.0 697 | } 698 | rotation { 699 | x: 0.0 700 | y: 0.0 701 | z: 0.0 702 | w: 1.0 703 | } 704 | scale { 705 | x: 1.0 706 | y: 1.0 707 | z: 1.0 708 | w: 1.0 709 | } 710 | size { 711 | x: 300.0 712 | y: 88.0 713 | z: 0.0 714 | w: 1.0 715 | } 716 | color { 717 | x: 1.0 718 | y: 1.0 719 | z: 1.0 720 | w: 1.0 721 | } 722 | type: TYPE_BOX 723 | blend_mode: BLEND_MODE_ALPHA 724 | texture: "button/button_normal" 725 | id: "get/larrybutton" 726 | xanchor: XANCHOR_NONE 727 | yanchor: YANCHOR_NONE 728 | pivot: PIVOT_CENTER 729 | adjust_mode: ADJUST_MODE_FIT 730 | parent: "get" 731 | layer: "" 732 | inherit_alpha: true 733 | slice9 { 734 | x: 32.0 735 | y: 32.0 736 | z: 32.0 737 | w: 32.0 738 | } 739 | clipping_mode: CLIPPING_MODE_NONE 740 | clipping_visible: true 741 | clipping_inverted: false 742 | alpha: 1.0 743 | overridden_fields: 38 744 | template_node_child: true 745 | size_mode: SIZE_MODE_MANUAL 746 | } 747 | nodes { 748 | position { 749 | x: 0.0 750 | y: 0.0 751 | z: 0.0 752 | w: 1.0 753 | } 754 | rotation { 755 | x: 0.0 756 | y: 0.0 757 | z: 0.0 758 | w: 1.0 759 | } 760 | scale { 761 | x: 1.0 762 | y: 1.0 763 | z: 1.0 764 | w: 1.0 765 | } 766 | size { 767 | x: 200.0 768 | y: 100.0 769 | z: 0.0 770 | w: 1.0 771 | } 772 | color { 773 | x: 1.0 774 | y: 1.0 775 | z: 1.0 776 | w: 1.0 777 | } 778 | type: TYPE_TEXT 779 | blend_mode: BLEND_MODE_ALPHA 780 | text: "Get" 781 | font: "larryfont" 782 | id: "get/larrylabel" 783 | xanchor: XANCHOR_NONE 784 | yanchor: YANCHOR_NONE 785 | pivot: PIVOT_CENTER 786 | outline { 787 | x: 0.0 788 | y: 0.0 789 | z: 0.0 790 | w: 1.0 791 | } 792 | shadow { 793 | x: 1.0 794 | y: 1.0 795 | z: 1.0 796 | w: 1.0 797 | } 798 | adjust_mode: ADJUST_MODE_FIT 799 | line_break: false 800 | parent: "get/larrybutton" 801 | layer: "" 802 | inherit_alpha: true 803 | alpha: 1.0 804 | outline_alpha: 1.0 805 | shadow_alpha: 1.0 806 | overridden_fields: 8 807 | template_node_child: true 808 | text_leading: 1.0 809 | text_tracking: 0.0 810 | } 811 | nodes { 812 | position { 813 | x: 505.0 814 | y: 569.0 815 | z: 0.0 816 | w: 1.0 817 | } 818 | rotation { 819 | x: 0.0 820 | y: 0.0 821 | z: 0.0 822 | w: 1.0 823 | } 824 | scale { 825 | x: 1.0 826 | y: 1.0 827 | z: 1.0 828 | w: 1.0 829 | } 830 | size { 831 | x: 600.0 832 | y: 100.0 833 | z: 0.0 834 | w: 1.0 835 | } 836 | color { 837 | x: 1.0 838 | y: 1.0 839 | z: 1.0 840 | w: 1.0 841 | } 842 | type: TYPE_TEXT 843 | blend_mode: BLEND_MODE_ALPHA 844 | text: "" 845 | font: "larryfont" 846 | id: "events" 847 | xanchor: XANCHOR_NONE 848 | yanchor: YANCHOR_NONE 849 | pivot: PIVOT_NW 850 | outline { 851 | x: 1.0 852 | y: 1.0 853 | z: 1.0 854 | w: 1.0 855 | } 856 | shadow { 857 | x: 1.0 858 | y: 1.0 859 | z: 1.0 860 | w: 1.0 861 | } 862 | adjust_mode: ADJUST_MODE_FIT 863 | line_break: true 864 | layer: "" 865 | inherit_alpha: true 866 | alpha: 1.0 867 | outline_alpha: 1.0 868 | shadow_alpha: 1.0 869 | template_node_child: false 870 | text_leading: 1.0 871 | text_tracking: 0.0 872 | } 873 | material: "/builtins/materials/gui.material" 874 | adjust_reference: ADJUST_REFERENCE_PARENT 875 | max_nodes: 512 876 | -------------------------------------------------------------------------------- /main/achievements.gui: -------------------------------------------------------------------------------- 1 | script: "/main/achievements.gui_script" 2 | fonts { 3 | name: "larryfont" 4 | font: "/dirtylarry/larryfont.font" 5 | } 6 | textures { 7 | name: "dirtylarry" 8 | texture: "/dirtylarry/dirtylarry.atlas" 9 | } 10 | background_color { 11 | x: 0.0 12 | y: 0.0 13 | z: 0.0 14 | w: 0.0 15 | } 16 | nodes { 17 | position { 18 | x: 170.0 19 | y: 650.0 20 | z: 0.0 21 | w: 1.0 22 | } 23 | rotation { 24 | x: 0.0 25 | y: 0.0 26 | z: 0.0 27 | w: 1.0 28 | } 29 | scale { 30 | x: 1.0 31 | y: 1.0 32 | z: 1.0 33 | w: 1.0 34 | } 35 | size { 36 | x: 200.0 37 | y: 100.0 38 | z: 0.0 39 | w: 1.0 40 | } 41 | color { 42 | x: 1.0 43 | y: 1.0 44 | z: 1.0 45 | w: 1.0 46 | } 47 | type: TYPE_TEMPLATE 48 | id: "reveal" 49 | layer: "" 50 | inherit_alpha: true 51 | alpha: 1.0 52 | template: "/dirtylarry/button.gui" 53 | template_node_child: false 54 | } 55 | nodes { 56 | position { 57 | x: 0.0 58 | y: 0.0 59 | z: 0.0 60 | w: 1.0 61 | } 62 | rotation { 63 | x: 0.0 64 | y: 0.0 65 | z: 0.0 66 | w: 1.0 67 | } 68 | scale { 69 | x: 1.0 70 | y: 1.0 71 | z: 1.0 72 | w: 1.0 73 | } 74 | size { 75 | x: 300.0 76 | y: 88.0 77 | z: 0.0 78 | w: 1.0 79 | } 80 | color { 81 | x: 1.0 82 | y: 1.0 83 | z: 1.0 84 | w: 1.0 85 | } 86 | type: TYPE_BOX 87 | blend_mode: BLEND_MODE_ALPHA 88 | texture: "button/button_normal" 89 | id: "reveal/larrybutton" 90 | xanchor: XANCHOR_NONE 91 | yanchor: YANCHOR_NONE 92 | pivot: PIVOT_CENTER 93 | adjust_mode: ADJUST_MODE_FIT 94 | parent: "reveal" 95 | layer: "" 96 | inherit_alpha: true 97 | slice9 { 98 | x: 32.0 99 | y: 32.0 100 | z: 32.0 101 | w: 32.0 102 | } 103 | clipping_mode: CLIPPING_MODE_NONE 104 | clipping_visible: true 105 | clipping_inverted: false 106 | alpha: 1.0 107 | template_node_child: true 108 | size_mode: SIZE_MODE_MANUAL 109 | } 110 | nodes { 111 | position { 112 | x: 0.0 113 | y: 0.0 114 | z: 0.0 115 | w: 1.0 116 | } 117 | rotation { 118 | x: 0.0 119 | y: 0.0 120 | z: 0.0 121 | w: 1.0 122 | } 123 | scale { 124 | x: 1.0 125 | y: 1.0 126 | z: 1.0 127 | w: 1.0 128 | } 129 | size { 130 | x: 200.0 131 | y: 100.0 132 | z: 0.0 133 | w: 1.0 134 | } 135 | color { 136 | x: 1.0 137 | y: 1.0 138 | z: 1.0 139 | w: 1.0 140 | } 141 | type: TYPE_TEXT 142 | blend_mode: BLEND_MODE_ALPHA 143 | text: "Reveal" 144 | font: "larryfont" 145 | id: "reveal/larrylabel" 146 | xanchor: XANCHOR_NONE 147 | yanchor: YANCHOR_NONE 148 | pivot: PIVOT_CENTER 149 | outline { 150 | x: 0.0 151 | y: 0.0 152 | z: 0.0 153 | w: 1.0 154 | } 155 | shadow { 156 | x: 1.0 157 | y: 1.0 158 | z: 1.0 159 | w: 1.0 160 | } 161 | adjust_mode: ADJUST_MODE_FIT 162 | line_break: false 163 | parent: "reveal/larrybutton" 164 | layer: "" 165 | inherit_alpha: true 166 | alpha: 1.0 167 | outline_alpha: 1.0 168 | shadow_alpha: 1.0 169 | overridden_fields: 8 170 | template_node_child: true 171 | text_leading: 1.0 172 | text_tracking: 0.0 173 | } 174 | nodes { 175 | position { 176 | x: 170.0 177 | y: 530.0 178 | z: 0.0 179 | w: 1.0 180 | } 181 | rotation { 182 | x: 0.0 183 | y: 0.0 184 | z: 0.0 185 | w: 1.0 186 | } 187 | scale { 188 | x: 1.0 189 | y: 1.0 190 | z: 1.0 191 | w: 1.0 192 | } 193 | size { 194 | x: 200.0 195 | y: 100.0 196 | z: 0.0 197 | w: 1.0 198 | } 199 | color { 200 | x: 1.0 201 | y: 1.0 202 | z: 1.0 203 | w: 1.0 204 | } 205 | type: TYPE_TEMPLATE 206 | id: "unlock" 207 | layer: "" 208 | inherit_alpha: true 209 | alpha: 1.0 210 | template: "/dirtylarry/button.gui" 211 | template_node_child: false 212 | } 213 | nodes { 214 | position { 215 | x: 0.0 216 | y: 0.0 217 | z: 0.0 218 | w: 1.0 219 | } 220 | rotation { 221 | x: 0.0 222 | y: 0.0 223 | z: 0.0 224 | w: 1.0 225 | } 226 | scale { 227 | x: 1.0 228 | y: 1.0 229 | z: 1.0 230 | w: 1.0 231 | } 232 | size { 233 | x: 300.0 234 | y: 88.0 235 | z: 0.0 236 | w: 1.0 237 | } 238 | color { 239 | x: 1.0 240 | y: 1.0 241 | z: 1.0 242 | w: 1.0 243 | } 244 | type: TYPE_BOX 245 | blend_mode: BLEND_MODE_ALPHA 246 | texture: "button/button_normal" 247 | id: "unlock/larrybutton" 248 | xanchor: XANCHOR_NONE 249 | yanchor: YANCHOR_NONE 250 | pivot: PIVOT_CENTER 251 | adjust_mode: ADJUST_MODE_FIT 252 | parent: "unlock" 253 | layer: "" 254 | inherit_alpha: true 255 | slice9 { 256 | x: 32.0 257 | y: 32.0 258 | z: 32.0 259 | w: 32.0 260 | } 261 | clipping_mode: CLIPPING_MODE_NONE 262 | clipping_visible: true 263 | clipping_inverted: false 264 | alpha: 1.0 265 | template_node_child: true 266 | size_mode: SIZE_MODE_MANUAL 267 | } 268 | nodes { 269 | position { 270 | x: 0.0 271 | y: 0.0 272 | z: 0.0 273 | w: 1.0 274 | } 275 | rotation { 276 | x: 0.0 277 | y: 0.0 278 | z: 0.0 279 | w: 1.0 280 | } 281 | scale { 282 | x: 1.0 283 | y: 1.0 284 | z: 1.0 285 | w: 1.0 286 | } 287 | size { 288 | x: 200.0 289 | y: 100.0 290 | z: 0.0 291 | w: 1.0 292 | } 293 | color { 294 | x: 1.0 295 | y: 1.0 296 | z: 1.0 297 | w: 1.0 298 | } 299 | type: TYPE_TEXT 300 | blend_mode: BLEND_MODE_ALPHA 301 | text: "Unlock" 302 | font: "larryfont" 303 | id: "unlock/larrylabel" 304 | xanchor: XANCHOR_NONE 305 | yanchor: YANCHOR_NONE 306 | pivot: PIVOT_CENTER 307 | outline { 308 | x: 0.0 309 | y: 0.0 310 | z: 0.0 311 | w: 1.0 312 | } 313 | shadow { 314 | x: 1.0 315 | y: 1.0 316 | z: 1.0 317 | w: 1.0 318 | } 319 | adjust_mode: ADJUST_MODE_FIT 320 | line_break: false 321 | parent: "unlock/larrybutton" 322 | layer: "" 323 | inherit_alpha: true 324 | alpha: 1.0 325 | outline_alpha: 1.0 326 | shadow_alpha: 1.0 327 | overridden_fields: 8 328 | template_node_child: true 329 | text_leading: 1.0 330 | text_tracking: 0.0 331 | } 332 | nodes { 333 | position { 334 | x: 170.0 335 | y: 74.0 336 | z: 0.0 337 | w: 1.0 338 | } 339 | rotation { 340 | x: 0.0 341 | y: 0.0 342 | z: 0.0 343 | w: 1.0 344 | } 345 | scale { 346 | x: 1.0 347 | y: 1.0 348 | z: 1.0 349 | w: 1.0 350 | } 351 | size { 352 | x: 200.0 353 | y: 100.0 354 | z: 0.0 355 | w: 1.0 356 | } 357 | color { 358 | x: 1.0 359 | y: 1.0 360 | z: 1.0 361 | w: 1.0 362 | } 363 | type: TYPE_TEMPLATE 364 | id: "back" 365 | layer: "" 366 | inherit_alpha: true 367 | alpha: 1.0 368 | template: "/dirtylarry/button.gui" 369 | template_node_child: false 370 | } 371 | nodes { 372 | position { 373 | x: 0.0 374 | y: 0.0 375 | z: 0.0 376 | w: 1.0 377 | } 378 | rotation { 379 | x: 0.0 380 | y: 0.0 381 | z: 0.0 382 | w: 1.0 383 | } 384 | scale { 385 | x: 1.0 386 | y: 1.0 387 | z: 1.0 388 | w: 1.0 389 | } 390 | size { 391 | x: 300.0 392 | y: 88.0 393 | z: 0.0 394 | w: 1.0 395 | } 396 | color { 397 | x: 1.0 398 | y: 1.0 399 | z: 1.0 400 | w: 1.0 401 | } 402 | type: TYPE_BOX 403 | blend_mode: BLEND_MODE_ALPHA 404 | texture: "button/button_normal" 405 | id: "back/larrybutton" 406 | xanchor: XANCHOR_NONE 407 | yanchor: YANCHOR_NONE 408 | pivot: PIVOT_CENTER 409 | adjust_mode: ADJUST_MODE_FIT 410 | parent: "back" 411 | layer: "" 412 | inherit_alpha: true 413 | slice9 { 414 | x: 32.0 415 | y: 32.0 416 | z: 32.0 417 | w: 32.0 418 | } 419 | clipping_mode: CLIPPING_MODE_NONE 420 | clipping_visible: true 421 | clipping_inverted: false 422 | alpha: 1.0 423 | template_node_child: true 424 | size_mode: SIZE_MODE_MANUAL 425 | } 426 | nodes { 427 | position { 428 | x: 0.0 429 | y: 0.0 430 | z: 0.0 431 | w: 1.0 432 | } 433 | rotation { 434 | x: 0.0 435 | y: 0.0 436 | z: 0.0 437 | w: 1.0 438 | } 439 | scale { 440 | x: 1.0 441 | y: 1.0 442 | z: 1.0 443 | w: 1.0 444 | } 445 | size { 446 | x: 200.0 447 | y: 100.0 448 | z: 0.0 449 | w: 1.0 450 | } 451 | color { 452 | x: 1.0 453 | y: 1.0 454 | z: 1.0 455 | w: 1.0 456 | } 457 | type: TYPE_TEXT 458 | blend_mode: BLEND_MODE_ALPHA 459 | text: "BACK" 460 | font: "larryfont" 461 | id: "back/larrylabel" 462 | xanchor: XANCHOR_NONE 463 | yanchor: YANCHOR_NONE 464 | pivot: PIVOT_CENTER 465 | outline { 466 | x: 0.0 467 | y: 0.0 468 | z: 0.0 469 | w: 1.0 470 | } 471 | shadow { 472 | x: 1.0 473 | y: 1.0 474 | z: 1.0 475 | w: 1.0 476 | } 477 | adjust_mode: ADJUST_MODE_FIT 478 | line_break: false 479 | parent: "back/larrybutton" 480 | layer: "" 481 | inherit_alpha: true 482 | alpha: 1.0 483 | outline_alpha: 1.0 484 | shadow_alpha: 1.0 485 | overridden_fields: 8 486 | template_node_child: true 487 | text_leading: 1.0 488 | text_tracking: 0.0 489 | } 490 | nodes { 491 | position { 492 | x: 170.0 493 | y: 410.0 494 | z: 0.0 495 | w: 1.0 496 | } 497 | rotation { 498 | x: 0.0 499 | y: 0.0 500 | z: 0.0 501 | w: 1.0 502 | } 503 | scale { 504 | x: 1.0 505 | y: 1.0 506 | z: 1.0 507 | w: 1.0 508 | } 509 | size { 510 | x: 200.0 511 | y: 100.0 512 | z: 0.0 513 | w: 1.0 514 | } 515 | color { 516 | x: 1.0 517 | y: 1.0 518 | z: 1.0 519 | w: 1.0 520 | } 521 | type: TYPE_TEMPLATE 522 | id: "increment" 523 | layer: "" 524 | inherit_alpha: true 525 | alpha: 1.0 526 | template: "/dirtylarry/button.gui" 527 | template_node_child: false 528 | } 529 | nodes { 530 | position { 531 | x: 0.0 532 | y: 0.0 533 | z: 0.0 534 | w: 1.0 535 | } 536 | rotation { 537 | x: 0.0 538 | y: 0.0 539 | z: 0.0 540 | w: 1.0 541 | } 542 | scale { 543 | x: 1.0 544 | y: 1.0 545 | z: 1.0 546 | w: 1.0 547 | } 548 | size { 549 | x: 300.0 550 | y: 88.0 551 | z: 0.0 552 | w: 1.0 553 | } 554 | color { 555 | x: 1.0 556 | y: 1.0 557 | z: 1.0 558 | w: 1.0 559 | } 560 | type: TYPE_BOX 561 | blend_mode: BLEND_MODE_ALPHA 562 | texture: "button/button_normal" 563 | id: "increment/larrybutton" 564 | xanchor: XANCHOR_NONE 565 | yanchor: YANCHOR_NONE 566 | pivot: PIVOT_CENTER 567 | adjust_mode: ADJUST_MODE_FIT 568 | parent: "increment" 569 | layer: "" 570 | inherit_alpha: true 571 | slice9 { 572 | x: 32.0 573 | y: 32.0 574 | z: 32.0 575 | w: 32.0 576 | } 577 | clipping_mode: CLIPPING_MODE_NONE 578 | clipping_visible: true 579 | clipping_inverted: false 580 | alpha: 1.0 581 | template_node_child: true 582 | size_mode: SIZE_MODE_MANUAL 583 | } 584 | nodes { 585 | position { 586 | x: 0.0 587 | y: 0.0 588 | z: 0.0 589 | w: 1.0 590 | } 591 | rotation { 592 | x: 0.0 593 | y: 0.0 594 | z: 0.0 595 | w: 1.0 596 | } 597 | scale { 598 | x: 1.0 599 | y: 1.0 600 | z: 1.0 601 | w: 1.0 602 | } 603 | size { 604 | x: 200.0 605 | y: 100.0 606 | z: 0.0 607 | w: 1.0 608 | } 609 | color { 610 | x: 1.0 611 | y: 1.0 612 | z: 1.0 613 | w: 1.0 614 | } 615 | type: TYPE_TEXT 616 | blend_mode: BLEND_MODE_ALPHA 617 | text: "Increment" 618 | font: "larryfont" 619 | id: "increment/larrylabel" 620 | xanchor: XANCHOR_NONE 621 | yanchor: YANCHOR_NONE 622 | pivot: PIVOT_CENTER 623 | outline { 624 | x: 0.0 625 | y: 0.0 626 | z: 0.0 627 | w: 1.0 628 | } 629 | shadow { 630 | x: 1.0 631 | y: 1.0 632 | z: 1.0 633 | w: 1.0 634 | } 635 | adjust_mode: ADJUST_MODE_FIT 636 | line_break: false 637 | parent: "increment/larrybutton" 638 | layer: "" 639 | inherit_alpha: true 640 | alpha: 1.0 641 | outline_alpha: 1.0 642 | shadow_alpha: 1.0 643 | overridden_fields: 8 644 | template_node_child: true 645 | text_leading: 1.0 646 | text_tracking: 0.0 647 | } 648 | nodes { 649 | position { 650 | x: 170.0 651 | y: 290.0 652 | z: 0.0 653 | w: 1.0 654 | } 655 | rotation { 656 | x: 0.0 657 | y: 0.0 658 | z: 0.0 659 | w: 1.0 660 | } 661 | scale { 662 | x: 1.0 663 | y: 1.0 664 | z: 1.0 665 | w: 1.0 666 | } 667 | size { 668 | x: 200.0 669 | y: 100.0 670 | z: 0.0 671 | w: 1.0 672 | } 673 | color { 674 | x: 1.0 675 | y: 1.0 676 | z: 1.0 677 | w: 1.0 678 | } 679 | type: TYPE_TEMPLATE 680 | id: "set" 681 | layer: "" 682 | inherit_alpha: true 683 | alpha: 1.0 684 | template: "/dirtylarry/button.gui" 685 | template_node_child: false 686 | } 687 | nodes { 688 | position { 689 | x: 0.0 690 | y: 0.0 691 | z: 0.0 692 | w: 1.0 693 | } 694 | rotation { 695 | x: 0.0 696 | y: 0.0 697 | z: 0.0 698 | w: 1.0 699 | } 700 | scale { 701 | x: 1.0 702 | y: 1.0 703 | z: 1.0 704 | w: 1.0 705 | } 706 | size { 707 | x: 300.0 708 | y: 88.0 709 | z: 0.0 710 | w: 1.0 711 | } 712 | color { 713 | x: 1.0 714 | y: 1.0 715 | z: 1.0 716 | w: 1.0 717 | } 718 | type: TYPE_BOX 719 | blend_mode: BLEND_MODE_ALPHA 720 | texture: "button/button_normal" 721 | id: "set/larrybutton" 722 | xanchor: XANCHOR_NONE 723 | yanchor: YANCHOR_NONE 724 | pivot: PIVOT_CENTER 725 | adjust_mode: ADJUST_MODE_FIT 726 | parent: "set" 727 | layer: "" 728 | inherit_alpha: true 729 | slice9 { 730 | x: 32.0 731 | y: 32.0 732 | z: 32.0 733 | w: 32.0 734 | } 735 | clipping_mode: CLIPPING_MODE_NONE 736 | clipping_visible: true 737 | clipping_inverted: false 738 | alpha: 1.0 739 | template_node_child: true 740 | size_mode: SIZE_MODE_MANUAL 741 | } 742 | nodes { 743 | position { 744 | x: 0.0 745 | y: 0.0 746 | z: 0.0 747 | w: 1.0 748 | } 749 | rotation { 750 | x: 0.0 751 | y: 0.0 752 | z: 0.0 753 | w: 1.0 754 | } 755 | scale { 756 | x: 1.0 757 | y: 1.0 758 | z: 1.0 759 | w: 1.0 760 | } 761 | size { 762 | x: 200.0 763 | y: 100.0 764 | z: 0.0 765 | w: 1.0 766 | } 767 | color { 768 | x: 1.0 769 | y: 1.0 770 | z: 1.0 771 | w: 1.0 772 | } 773 | type: TYPE_TEXT 774 | blend_mode: BLEND_MODE_ALPHA 775 | text: "Set" 776 | font: "larryfont" 777 | id: "set/larrylabel" 778 | xanchor: XANCHOR_NONE 779 | yanchor: YANCHOR_NONE 780 | pivot: PIVOT_CENTER 781 | outline { 782 | x: 0.0 783 | y: 0.0 784 | z: 0.0 785 | w: 1.0 786 | } 787 | shadow { 788 | x: 1.0 789 | y: 1.0 790 | z: 1.0 791 | w: 1.0 792 | } 793 | adjust_mode: ADJUST_MODE_FIT 794 | line_break: false 795 | parent: "set/larrybutton" 796 | layer: "" 797 | inherit_alpha: true 798 | alpha: 1.0 799 | outline_alpha: 1.0 800 | shadow_alpha: 1.0 801 | overridden_fields: 8 802 | template_node_child: true 803 | text_leading: 1.0 804 | text_tracking: 0.0 805 | } 806 | nodes { 807 | position { 808 | x: 499.0 809 | y: 650.0 810 | z: 0.0 811 | w: 1.0 812 | } 813 | rotation { 814 | x: 0.0 815 | y: 0.0 816 | z: 0.0 817 | w: 1.0 818 | } 819 | scale { 820 | x: 1.0 821 | y: 1.0 822 | z: 1.0 823 | w: 1.0 824 | } 825 | size { 826 | x: 200.0 827 | y: 100.0 828 | z: 0.0 829 | w: 1.0 830 | } 831 | color { 832 | x: 1.0 833 | y: 1.0 834 | z: 1.0 835 | w: 1.0 836 | } 837 | type: TYPE_TEMPLATE 838 | id: "show" 839 | layer: "" 840 | inherit_alpha: true 841 | alpha: 1.0 842 | template: "/dirtylarry/button.gui" 843 | template_node_child: false 844 | } 845 | nodes { 846 | position { 847 | x: 0.0 848 | y: 0.0 849 | z: 0.0 850 | w: 1.0 851 | } 852 | rotation { 853 | x: 0.0 854 | y: 0.0 855 | z: 0.0 856 | w: 1.0 857 | } 858 | scale { 859 | x: 1.0 860 | y: 1.0 861 | z: 1.0 862 | w: 1.0 863 | } 864 | size { 865 | x: 300.0 866 | y: 88.0 867 | z: 0.0 868 | w: 1.0 869 | } 870 | color { 871 | x: 1.0 872 | y: 1.0 873 | z: 1.0 874 | w: 1.0 875 | } 876 | type: TYPE_BOX 877 | blend_mode: BLEND_MODE_ALPHA 878 | texture: "button/button_normal" 879 | id: "show/larrybutton" 880 | xanchor: XANCHOR_NONE 881 | yanchor: YANCHOR_NONE 882 | pivot: PIVOT_CENTER 883 | adjust_mode: ADJUST_MODE_FIT 884 | parent: "show" 885 | layer: "" 886 | inherit_alpha: true 887 | slice9 { 888 | x: 32.0 889 | y: 32.0 890 | z: 32.0 891 | w: 32.0 892 | } 893 | clipping_mode: CLIPPING_MODE_NONE 894 | clipping_visible: true 895 | clipping_inverted: false 896 | alpha: 1.0 897 | template_node_child: true 898 | size_mode: SIZE_MODE_MANUAL 899 | } 900 | nodes { 901 | position { 902 | x: 0.0 903 | y: 0.0 904 | z: 0.0 905 | w: 1.0 906 | } 907 | rotation { 908 | x: 0.0 909 | y: 0.0 910 | z: 0.0 911 | w: 1.0 912 | } 913 | scale { 914 | x: 1.0 915 | y: 1.0 916 | z: 1.0 917 | w: 1.0 918 | } 919 | size { 920 | x: 200.0 921 | y: 100.0 922 | z: 0.0 923 | w: 1.0 924 | } 925 | color { 926 | x: 1.0 927 | y: 1.0 928 | z: 1.0 929 | w: 1.0 930 | } 931 | type: TYPE_TEXT 932 | blend_mode: BLEND_MODE_ALPHA 933 | text: "Show" 934 | font: "larryfont" 935 | id: "show/larrylabel" 936 | xanchor: XANCHOR_NONE 937 | yanchor: YANCHOR_NONE 938 | pivot: PIVOT_CENTER 939 | outline { 940 | x: 0.0 941 | y: 0.0 942 | z: 0.0 943 | w: 1.0 944 | } 945 | shadow { 946 | x: 1.0 947 | y: 1.0 948 | z: 1.0 949 | w: 1.0 950 | } 951 | adjust_mode: ADJUST_MODE_FIT 952 | line_break: false 953 | parent: "show/larrybutton" 954 | layer: "" 955 | inherit_alpha: true 956 | alpha: 1.0 957 | outline_alpha: 1.0 958 | shadow_alpha: 1.0 959 | overridden_fields: 8 960 | template_node_child: true 961 | text_leading: 1.0 962 | text_tracking: 0.0 963 | } 964 | nodes { 965 | position { 966 | x: 499.0 967 | y: 530.0 968 | z: 0.0 969 | w: 1.0 970 | } 971 | rotation { 972 | x: 0.0 973 | y: 0.0 974 | z: 0.0 975 | w: 1.0 976 | } 977 | scale { 978 | x: 1.0 979 | y: 1.0 980 | z: 1.0 981 | w: 1.0 982 | } 983 | size { 984 | x: 200.0 985 | y: 100.0 986 | z: 0.0 987 | w: 1.0 988 | } 989 | color { 990 | x: 1.0 991 | y: 1.0 992 | z: 1.0 993 | w: 1.0 994 | } 995 | type: TYPE_TEMPLATE 996 | id: "get" 997 | layer: "" 998 | inherit_alpha: true 999 | alpha: 1.0 1000 | template: "/dirtylarry/button.gui" 1001 | template_node_child: false 1002 | } 1003 | nodes { 1004 | position { 1005 | x: 0.0 1006 | y: 0.0 1007 | z: 0.0 1008 | w: 1.0 1009 | } 1010 | rotation { 1011 | x: 0.0 1012 | y: 0.0 1013 | z: 0.0 1014 | w: 1.0 1015 | } 1016 | scale { 1017 | x: 1.0 1018 | y: 1.0 1019 | z: 1.0 1020 | w: 1.0 1021 | } 1022 | size { 1023 | x: 300.0 1024 | y: 88.0 1025 | z: 0.0 1026 | w: 1.0 1027 | } 1028 | color { 1029 | x: 1.0 1030 | y: 1.0 1031 | z: 1.0 1032 | w: 1.0 1033 | } 1034 | type: TYPE_BOX 1035 | blend_mode: BLEND_MODE_ALPHA 1036 | texture: "button/button_normal" 1037 | id: "get/larrybutton" 1038 | xanchor: XANCHOR_NONE 1039 | yanchor: YANCHOR_NONE 1040 | pivot: PIVOT_CENTER 1041 | adjust_mode: ADJUST_MODE_FIT 1042 | parent: "get" 1043 | layer: "" 1044 | inherit_alpha: true 1045 | slice9 { 1046 | x: 32.0 1047 | y: 32.0 1048 | z: 32.0 1049 | w: 32.0 1050 | } 1051 | clipping_mode: CLIPPING_MODE_NONE 1052 | clipping_visible: true 1053 | clipping_inverted: false 1054 | alpha: 1.0 1055 | template_node_child: true 1056 | size_mode: SIZE_MODE_MANUAL 1057 | } 1058 | nodes { 1059 | position { 1060 | x: 0.0 1061 | y: 0.0 1062 | z: 0.0 1063 | w: 1.0 1064 | } 1065 | rotation { 1066 | x: 0.0 1067 | y: 0.0 1068 | z: 0.0 1069 | w: 1.0 1070 | } 1071 | scale { 1072 | x: 1.0 1073 | y: 1.0 1074 | z: 1.0 1075 | w: 1.0 1076 | } 1077 | size { 1078 | x: 200.0 1079 | y: 100.0 1080 | z: 0.0 1081 | w: 1.0 1082 | } 1083 | color { 1084 | x: 1.0 1085 | y: 1.0 1086 | z: 1.0 1087 | w: 1.0 1088 | } 1089 | type: TYPE_TEXT 1090 | blend_mode: BLEND_MODE_ALPHA 1091 | text: "Get" 1092 | font: "larryfont" 1093 | id: "get/larrylabel" 1094 | xanchor: XANCHOR_NONE 1095 | yanchor: YANCHOR_NONE 1096 | pivot: PIVOT_CENTER 1097 | outline { 1098 | x: 0.0 1099 | y: 0.0 1100 | z: 0.0 1101 | w: 1.0 1102 | } 1103 | shadow { 1104 | x: 1.0 1105 | y: 1.0 1106 | z: 1.0 1107 | w: 1.0 1108 | } 1109 | adjust_mode: ADJUST_MODE_FIT 1110 | line_break: false 1111 | parent: "get/larrybutton" 1112 | layer: "" 1113 | inherit_alpha: true 1114 | alpha: 1.0 1115 | outline_alpha: 1.0 1116 | shadow_alpha: 1.0 1117 | overridden_fields: 8 1118 | template_node_child: true 1119 | text_leading: 1.0 1120 | text_tracking: 0.0 1121 | } 1122 | material: "/builtins/materials/gui.material" 1123 | adjust_reference: ADJUST_REFERENCE_PARENT 1124 | max_nodes: 512 1125 | -------------------------------------------------------------------------------- /main/leaderboards.gui: -------------------------------------------------------------------------------- 1 | script: "/main/leaderboards.gui_script" 2 | fonts { 3 | name: "larryfont" 4 | font: "/dirtylarry/larryfont.font" 5 | } 6 | textures { 7 | name: "dirtylarry" 8 | texture: "/dirtylarry/dirtylarry.atlas" 9 | } 10 | background_color { 11 | x: 0.0 12 | y: 0.0 13 | z: 0.0 14 | w: 0.0 15 | } 16 | nodes { 17 | position { 18 | x: 170.0 19 | y: 74.0 20 | z: 0.0 21 | w: 1.0 22 | } 23 | rotation { 24 | x: 0.0 25 | y: 0.0 26 | z: 0.0 27 | w: 1.0 28 | } 29 | scale { 30 | x: 1.0 31 | y: 1.0 32 | z: 1.0 33 | w: 1.0 34 | } 35 | size { 36 | x: 200.0 37 | y: 100.0 38 | z: 0.0 39 | w: 1.0 40 | } 41 | color { 42 | x: 1.0 43 | y: 1.0 44 | z: 1.0 45 | w: 1.0 46 | } 47 | type: TYPE_TEMPLATE 48 | id: "back" 49 | layer: "" 50 | inherit_alpha: true 51 | alpha: 1.0 52 | template: "/dirtylarry/button.gui" 53 | template_node_child: false 54 | } 55 | nodes { 56 | position { 57 | x: 0.0 58 | y: 0.0 59 | z: 0.0 60 | w: 1.0 61 | } 62 | rotation { 63 | x: 0.0 64 | y: 0.0 65 | z: 0.0 66 | w: 1.0 67 | } 68 | scale { 69 | x: 1.0 70 | y: 1.0 71 | z: 1.0 72 | w: 1.0 73 | } 74 | size { 75 | x: 300.0 76 | y: 88.0 77 | z: 0.0 78 | w: 1.0 79 | } 80 | color { 81 | x: 1.0 82 | y: 1.0 83 | z: 1.0 84 | w: 1.0 85 | } 86 | type: TYPE_BOX 87 | blend_mode: BLEND_MODE_ALPHA 88 | texture: "button/button_normal" 89 | id: "back/larrybutton" 90 | xanchor: XANCHOR_NONE 91 | yanchor: YANCHOR_NONE 92 | pivot: PIVOT_CENTER 93 | adjust_mode: ADJUST_MODE_FIT 94 | parent: "back" 95 | layer: "" 96 | inherit_alpha: true 97 | slice9 { 98 | x: 32.0 99 | y: 32.0 100 | z: 32.0 101 | w: 32.0 102 | } 103 | clipping_mode: CLIPPING_MODE_NONE 104 | clipping_visible: true 105 | clipping_inverted: false 106 | alpha: 1.0 107 | template_node_child: true 108 | size_mode: SIZE_MODE_MANUAL 109 | } 110 | nodes { 111 | position { 112 | x: 0.0 113 | y: 0.0 114 | z: 0.0 115 | w: 1.0 116 | } 117 | rotation { 118 | x: 0.0 119 | y: 0.0 120 | z: 0.0 121 | w: 1.0 122 | } 123 | scale { 124 | x: 1.0 125 | y: 1.0 126 | z: 1.0 127 | w: 1.0 128 | } 129 | size { 130 | x: 200.0 131 | y: 100.0 132 | z: 0.0 133 | w: 1.0 134 | } 135 | color { 136 | x: 1.0 137 | y: 1.0 138 | z: 1.0 139 | w: 1.0 140 | } 141 | type: TYPE_TEXT 142 | blend_mode: BLEND_MODE_ALPHA 143 | text: "BACK" 144 | font: "larryfont" 145 | id: "back/larrylabel" 146 | xanchor: XANCHOR_NONE 147 | yanchor: YANCHOR_NONE 148 | pivot: PIVOT_CENTER 149 | outline { 150 | x: 0.0 151 | y: 0.0 152 | z: 0.0 153 | w: 1.0 154 | } 155 | shadow { 156 | x: 1.0 157 | y: 1.0 158 | z: 1.0 159 | w: 1.0 160 | } 161 | adjust_mode: ADJUST_MODE_FIT 162 | line_break: false 163 | parent: "back/larrybutton" 164 | layer: "" 165 | inherit_alpha: true 166 | alpha: 1.0 167 | outline_alpha: 1.0 168 | shadow_alpha: 1.0 169 | overridden_fields: 8 170 | template_node_child: true 171 | text_leading: 1.0 172 | text_tracking: 0.0 173 | } 174 | nodes { 175 | position { 176 | x: 170.0 177 | y: 656.0 178 | z: 0.0 179 | w: 1.0 180 | } 181 | rotation { 182 | x: 0.0 183 | y: 0.0 184 | z: 0.0 185 | w: 1.0 186 | } 187 | scale { 188 | x: 1.0 189 | y: 1.0 190 | z: 1.0 191 | w: 1.0 192 | } 193 | size { 194 | x: 200.0 195 | y: 100.0 196 | z: 0.0 197 | w: 1.0 198 | } 199 | color { 200 | x: 1.0 201 | y: 1.0 202 | z: 1.0 203 | w: 1.0 204 | } 205 | type: TYPE_TEMPLATE 206 | id: "submit_score" 207 | layer: "" 208 | inherit_alpha: true 209 | alpha: 1.0 210 | template: "/dirtylarry/button.gui" 211 | template_node_child: false 212 | } 213 | nodes { 214 | position { 215 | x: 0.0 216 | y: 0.0 217 | z: 0.0 218 | w: 1.0 219 | } 220 | rotation { 221 | x: 0.0 222 | y: 0.0 223 | z: 0.0 224 | w: 1.0 225 | } 226 | scale { 227 | x: 1.0 228 | y: 1.0 229 | z: 1.0 230 | w: 1.0 231 | } 232 | size { 233 | x: 300.0 234 | y: 88.0 235 | z: 0.0 236 | w: 1.0 237 | } 238 | color { 239 | x: 1.0 240 | y: 1.0 241 | z: 1.0 242 | w: 1.0 243 | } 244 | type: TYPE_BOX 245 | blend_mode: BLEND_MODE_ALPHA 246 | texture: "button/button_normal" 247 | id: "submit_score/larrybutton" 248 | xanchor: XANCHOR_NONE 249 | yanchor: YANCHOR_NONE 250 | pivot: PIVOT_CENTER 251 | adjust_mode: ADJUST_MODE_FIT 252 | parent: "submit_score" 253 | layer: "" 254 | inherit_alpha: true 255 | slice9 { 256 | x: 32.0 257 | y: 32.0 258 | z: 32.0 259 | w: 32.0 260 | } 261 | clipping_mode: CLIPPING_MODE_NONE 262 | clipping_visible: true 263 | clipping_inverted: false 264 | alpha: 1.0 265 | template_node_child: true 266 | size_mode: SIZE_MODE_MANUAL 267 | } 268 | nodes { 269 | position { 270 | x: 0.0 271 | y: 0.0 272 | z: 0.0 273 | w: 1.0 274 | } 275 | rotation { 276 | x: 0.0 277 | y: 0.0 278 | z: 0.0 279 | w: 1.0 280 | } 281 | scale { 282 | x: 1.0 283 | y: 1.0 284 | z: 1.0 285 | w: 1.0 286 | } 287 | size { 288 | x: 200.0 289 | y: 100.0 290 | z: 0.0 291 | w: 1.0 292 | } 293 | color { 294 | x: 1.0 295 | y: 1.0 296 | z: 1.0 297 | w: 1.0 298 | } 299 | type: TYPE_TEXT 300 | blend_mode: BLEND_MODE_ALPHA 301 | text: "Submit Score" 302 | font: "larryfont" 303 | id: "submit_score/larrylabel" 304 | xanchor: XANCHOR_NONE 305 | yanchor: YANCHOR_NONE 306 | pivot: PIVOT_CENTER 307 | outline { 308 | x: 0.0 309 | y: 0.0 310 | z: 0.0 311 | w: 1.0 312 | } 313 | shadow { 314 | x: 1.0 315 | y: 1.0 316 | z: 1.0 317 | w: 1.0 318 | } 319 | adjust_mode: ADJUST_MODE_FIT 320 | line_break: false 321 | parent: "submit_score/larrybutton" 322 | layer: "" 323 | inherit_alpha: true 324 | alpha: 1.0 325 | outline_alpha: 1.0 326 | shadow_alpha: 1.0 327 | overridden_fields: 8 328 | template_node_child: true 329 | text_leading: 1.0 330 | text_tracking: 0.0 331 | } 332 | nodes { 333 | position { 334 | x: 716.0 335 | y: 656.0 336 | z: 0.0 337 | w: 1.0 338 | } 339 | rotation { 340 | x: 0.0 341 | y: 0.0 342 | z: 0.0 343 | w: 1.0 344 | } 345 | scale { 346 | x: 1.0 347 | y: 1.0 348 | z: 1.0 349 | w: 1.0 350 | } 351 | size { 352 | x: 200.0 353 | y: 100.0 354 | z: 0.0 355 | w: 1.0 356 | } 357 | color { 358 | x: 1.0 359 | y: 1.0 360 | z: 1.0 361 | w: 1.0 362 | } 363 | type: TYPE_TEMPLATE 364 | id: "top_scores" 365 | layer: "" 366 | inherit_alpha: true 367 | alpha: 1.0 368 | template: "/dirtylarry/button.gui" 369 | template_node_child: false 370 | } 371 | nodes { 372 | position { 373 | x: 0.0 374 | y: 0.0 375 | z: 0.0 376 | w: 1.0 377 | } 378 | rotation { 379 | x: 0.0 380 | y: 0.0 381 | z: 0.0 382 | w: 1.0 383 | } 384 | scale { 385 | x: 1.0 386 | y: 1.0 387 | z: 1.0 388 | w: 1.0 389 | } 390 | size { 391 | x: 300.0 392 | y: 88.0 393 | z: 0.0 394 | w: 1.0 395 | } 396 | color { 397 | x: 1.0 398 | y: 1.0 399 | z: 1.0 400 | w: 1.0 401 | } 402 | type: TYPE_BOX 403 | blend_mode: BLEND_MODE_ALPHA 404 | texture: "button/button_normal" 405 | id: "top_scores/larrybutton" 406 | xanchor: XANCHOR_NONE 407 | yanchor: YANCHOR_NONE 408 | pivot: PIVOT_CENTER 409 | adjust_mode: ADJUST_MODE_FIT 410 | parent: "top_scores" 411 | layer: "" 412 | inherit_alpha: true 413 | slice9 { 414 | x: 32.0 415 | y: 32.0 416 | z: 32.0 417 | w: 32.0 418 | } 419 | clipping_mode: CLIPPING_MODE_NONE 420 | clipping_visible: true 421 | clipping_inverted: false 422 | alpha: 1.0 423 | template_node_child: true 424 | size_mode: SIZE_MODE_MANUAL 425 | } 426 | nodes { 427 | position { 428 | x: 0.0 429 | y: 0.0 430 | z: 0.0 431 | w: 1.0 432 | } 433 | rotation { 434 | x: 0.0 435 | y: 0.0 436 | z: 0.0 437 | w: 1.0 438 | } 439 | scale { 440 | x: 1.0 441 | y: 1.0 442 | z: 1.0 443 | w: 1.0 444 | } 445 | size { 446 | x: 200.0 447 | y: 100.0 448 | z: 0.0 449 | w: 1.0 450 | } 451 | color { 452 | x: 1.0 453 | y: 1.0 454 | z: 1.0 455 | w: 1.0 456 | } 457 | type: TYPE_TEXT 458 | blend_mode: BLEND_MODE_ALPHA 459 | text: "Top Scores" 460 | font: "larryfont" 461 | id: "top_scores/larrylabel" 462 | xanchor: XANCHOR_NONE 463 | yanchor: YANCHOR_NONE 464 | pivot: PIVOT_CENTER 465 | outline { 466 | x: 0.0 467 | y: 0.0 468 | z: 0.0 469 | w: 1.0 470 | } 471 | shadow { 472 | x: 1.0 473 | y: 1.0 474 | z: 1.0 475 | w: 1.0 476 | } 477 | adjust_mode: ADJUST_MODE_FIT 478 | line_break: false 479 | parent: "top_scores/larrybutton" 480 | layer: "" 481 | inherit_alpha: true 482 | alpha: 1.0 483 | outline_alpha: 1.0 484 | shadow_alpha: 1.0 485 | overridden_fields: 8 486 | template_node_child: true 487 | text_leading: 1.0 488 | text_tracking: 0.0 489 | } 490 | nodes { 491 | position { 492 | x: 1064.0 493 | y: 656.0 494 | z: 0.0 495 | w: 1.0 496 | } 497 | rotation { 498 | x: 0.0 499 | y: 0.0 500 | z: 0.0 501 | w: 1.0 502 | } 503 | scale { 504 | x: 1.0 505 | y: 1.0 506 | z: 1.0 507 | w: 1.0 508 | } 509 | size { 510 | x: 200.0 511 | y: 100.0 512 | z: 0.0 513 | w: 1.0 514 | } 515 | color { 516 | x: 1.0 517 | y: 1.0 518 | z: 1.0 519 | w: 1.0 520 | } 521 | type: TYPE_TEMPLATE 522 | id: "player_centered_scores" 523 | layer: "" 524 | inherit_alpha: true 525 | alpha: 1.0 526 | template: "/dirtylarry/button.gui" 527 | template_node_child: false 528 | } 529 | nodes { 530 | position { 531 | x: 0.0 532 | y: 0.0 533 | z: 0.0 534 | w: 1.0 535 | } 536 | rotation { 537 | x: 0.0 538 | y: 0.0 539 | z: 0.0 540 | w: 1.0 541 | } 542 | scale { 543 | x: 1.0 544 | y: 1.0 545 | z: 1.0 546 | w: 1.0 547 | } 548 | size { 549 | x: 300.0 550 | y: 88.0 551 | z: 0.0 552 | w: 1.0 553 | } 554 | color { 555 | x: 1.0 556 | y: 1.0 557 | z: 1.0 558 | w: 1.0 559 | } 560 | type: TYPE_BOX 561 | blend_mode: BLEND_MODE_ALPHA 562 | texture: "button/button_normal" 563 | id: "player_centered_scores/larrybutton" 564 | xanchor: XANCHOR_NONE 565 | yanchor: YANCHOR_NONE 566 | pivot: PIVOT_CENTER 567 | adjust_mode: ADJUST_MODE_FIT 568 | parent: "player_centered_scores" 569 | layer: "" 570 | inherit_alpha: true 571 | slice9 { 572 | x: 32.0 573 | y: 32.0 574 | z: 32.0 575 | w: 32.0 576 | } 577 | clipping_mode: CLIPPING_MODE_NONE 578 | clipping_visible: true 579 | clipping_inverted: false 580 | alpha: 1.0 581 | template_node_child: true 582 | size_mode: SIZE_MODE_MANUAL 583 | } 584 | nodes { 585 | position { 586 | x: 0.0 587 | y: 0.0 588 | z: 0.0 589 | w: 1.0 590 | } 591 | rotation { 592 | x: 0.0 593 | y: 0.0 594 | z: 0.0 595 | w: 1.0 596 | } 597 | scale { 598 | x: 1.0 599 | y: 1.0 600 | z: 1.0 601 | w: 1.0 602 | } 603 | size { 604 | x: 200.0 605 | y: 100.0 606 | z: 0.0 607 | w: 1.0 608 | } 609 | color { 610 | x: 1.0 611 | y: 1.0 612 | z: 1.0 613 | w: 1.0 614 | } 615 | type: TYPE_TEXT 616 | blend_mode: BLEND_MODE_ALPHA 617 | text: "Player Centered Scores" 618 | font: "larryfont" 619 | id: "player_centered_scores/larrylabel" 620 | xanchor: XANCHOR_NONE 621 | yanchor: YANCHOR_NONE 622 | pivot: PIVOT_CENTER 623 | outline { 624 | x: 0.0 625 | y: 0.0 626 | z: 0.0 627 | w: 1.0 628 | } 629 | shadow { 630 | x: 1.0 631 | y: 1.0 632 | z: 1.0 633 | w: 1.0 634 | } 635 | adjust_mode: ADJUST_MODE_FIT 636 | line_break: true 637 | parent: "player_centered_scores/larrybutton" 638 | layer: "" 639 | inherit_alpha: true 640 | alpha: 1.0 641 | outline_alpha: 1.0 642 | shadow_alpha: 1.0 643 | overridden_fields: 4 644 | overridden_fields: 8 645 | overridden_fields: 18 646 | template_node_child: true 647 | text_leading: 1.0 648 | text_tracking: 0.0 649 | } 650 | nodes { 651 | position { 652 | x: 170.0 653 | y: 531.0 654 | z: 0.0 655 | w: 1.0 656 | } 657 | rotation { 658 | x: 0.0 659 | y: 0.0 660 | z: 0.0 661 | w: 1.0 662 | } 663 | scale { 664 | x: 1.0 665 | y: 1.0 666 | z: 1.0 667 | w: 1.0 668 | } 669 | size { 670 | x: 200.0 671 | y: 100.0 672 | z: 0.0 673 | w: 1.0 674 | } 675 | color { 676 | x: 1.0 677 | y: 1.0 678 | z: 1.0 679 | w: 1.0 680 | } 681 | type: TYPE_TEMPLATE 682 | id: "player_score" 683 | layer: "" 684 | inherit_alpha: true 685 | alpha: 1.0 686 | template: "/dirtylarry/button.gui" 687 | template_node_child: false 688 | } 689 | nodes { 690 | position { 691 | x: 0.0 692 | y: 0.0 693 | z: 0.0 694 | w: 1.0 695 | } 696 | rotation { 697 | x: 0.0 698 | y: 0.0 699 | z: 0.0 700 | w: 1.0 701 | } 702 | scale { 703 | x: 1.0 704 | y: 1.0 705 | z: 1.0 706 | w: 1.0 707 | } 708 | size { 709 | x: 300.0 710 | y: 88.0 711 | z: 0.0 712 | w: 1.0 713 | } 714 | color { 715 | x: 1.0 716 | y: 1.0 717 | z: 1.0 718 | w: 1.0 719 | } 720 | type: TYPE_BOX 721 | blend_mode: BLEND_MODE_ALPHA 722 | texture: "button/button_normal" 723 | id: "player_score/larrybutton" 724 | xanchor: XANCHOR_NONE 725 | yanchor: YANCHOR_NONE 726 | pivot: PIVOT_CENTER 727 | adjust_mode: ADJUST_MODE_FIT 728 | parent: "player_score" 729 | layer: "" 730 | inherit_alpha: true 731 | slice9 { 732 | x: 32.0 733 | y: 32.0 734 | z: 32.0 735 | w: 32.0 736 | } 737 | clipping_mode: CLIPPING_MODE_NONE 738 | clipping_visible: true 739 | clipping_inverted: false 740 | alpha: 1.0 741 | template_node_child: true 742 | size_mode: SIZE_MODE_MANUAL 743 | } 744 | nodes { 745 | position { 746 | x: 0.0 747 | y: 0.0 748 | z: 0.0 749 | w: 1.0 750 | } 751 | rotation { 752 | x: 0.0 753 | y: 0.0 754 | z: 0.0 755 | w: 1.0 756 | } 757 | scale { 758 | x: 1.0 759 | y: 1.0 760 | z: 1.0 761 | w: 1.0 762 | } 763 | size { 764 | x: 240.0 765 | y: 100.0 766 | z: 0.0 767 | w: 1.0 768 | } 769 | color { 770 | x: 1.0 771 | y: 1.0 772 | z: 1.0 773 | w: 1.0 774 | } 775 | type: TYPE_TEXT 776 | blend_mode: BLEND_MODE_ALPHA 777 | text: "Player Score" 778 | font: "larryfont" 779 | id: "player_score/larrylabel" 780 | xanchor: XANCHOR_NONE 781 | yanchor: YANCHOR_NONE 782 | pivot: PIVOT_CENTER 783 | outline { 784 | x: 0.0 785 | y: 0.0 786 | z: 0.0 787 | w: 1.0 788 | } 789 | shadow { 790 | x: 1.0 791 | y: 1.0 792 | z: 1.0 793 | w: 1.0 794 | } 795 | adjust_mode: ADJUST_MODE_FIT 796 | line_break: true 797 | parent: "player_score/larrybutton" 798 | layer: "" 799 | inherit_alpha: true 800 | alpha: 1.0 801 | outline_alpha: 1.0 802 | shadow_alpha: 1.0 803 | overridden_fields: 4 804 | overridden_fields: 8 805 | overridden_fields: 18 806 | template_node_child: true 807 | text_leading: 1.0 808 | text_tracking: 0.0 809 | } 810 | nodes { 811 | position { 812 | x: 331.0 813 | y: 537.0 814 | z: 0.0 815 | w: 1.0 816 | } 817 | rotation { 818 | x: 0.0 819 | y: 0.0 820 | z: 0.0 821 | w: 1.0 822 | } 823 | scale { 824 | x: 1.0 825 | y: 1.0 826 | z: 1.0 827 | w: 1.0 828 | } 829 | size { 830 | x: 200.0 831 | y: 100.0 832 | z: 0.0 833 | w: 1.0 834 | } 835 | color { 836 | x: 1.0 837 | y: 1.0 838 | z: 1.0 839 | w: 1.0 840 | } 841 | type: TYPE_TEXT 842 | blend_mode: BLEND_MODE_ALPHA 843 | text: "" 844 | font: "larryfont" 845 | id: "score" 846 | xanchor: XANCHOR_NONE 847 | yanchor: YANCHOR_NONE 848 | pivot: PIVOT_W 849 | outline { 850 | x: 1.0 851 | y: 1.0 852 | z: 1.0 853 | w: 1.0 854 | } 855 | shadow { 856 | x: 1.0 857 | y: 1.0 858 | z: 1.0 859 | w: 1.0 860 | } 861 | adjust_mode: ADJUST_MODE_FIT 862 | line_break: false 863 | layer: "" 864 | inherit_alpha: true 865 | alpha: 1.0 866 | outline_alpha: 1.0 867 | shadow_alpha: 1.0 868 | template_node_child: false 869 | text_leading: 1.0 870 | text_tracking: 0.0 871 | } 872 | nodes { 873 | position { 874 | x: 331.0 875 | y: 656.0 876 | z: 0.0 877 | w: 1.0 878 | } 879 | rotation { 880 | x: 0.0 881 | y: 0.0 882 | z: 0.0 883 | w: 1.0 884 | } 885 | scale { 886 | x: 1.0 887 | y: 1.0 888 | z: 1.0 889 | w: 1.0 890 | } 891 | size { 892 | x: 200.0 893 | y: 100.0 894 | z: 0.0 895 | w: 1.0 896 | } 897 | color { 898 | x: 1.0 899 | y: 1.0 900 | z: 1.0 901 | w: 1.0 902 | } 903 | type: TYPE_TEXT 904 | blend_mode: BLEND_MODE_ALPHA 905 | text: "" 906 | font: "larryfont" 907 | id: "clicks" 908 | xanchor: XANCHOR_NONE 909 | yanchor: YANCHOR_NONE 910 | pivot: PIVOT_W 911 | outline { 912 | x: 1.0 913 | y: 1.0 914 | z: 1.0 915 | w: 1.0 916 | } 917 | shadow { 918 | x: 1.0 919 | y: 1.0 920 | z: 1.0 921 | w: 1.0 922 | } 923 | adjust_mode: ADJUST_MODE_FIT 924 | line_break: false 925 | layer: "" 926 | inherit_alpha: true 927 | alpha: 1.0 928 | outline_alpha: 1.0 929 | shadow_alpha: 1.0 930 | template_node_child: false 931 | text_leading: 1.0 932 | text_tracking: 0.0 933 | } 934 | nodes { 935 | position { 936 | x: 565.0 937 | y: 537.0 938 | z: 0.0 939 | w: 1.0 940 | } 941 | rotation { 942 | x: 0.0 943 | y: 0.0 944 | z: 0.0 945 | w: 1.0 946 | } 947 | scale { 948 | x: 1.0 949 | y: 1.0 950 | z: 1.0 951 | w: 1.0 952 | } 953 | size { 954 | x: 650.0 955 | y: 100.0 956 | z: 0.0 957 | w: 1.0 958 | } 959 | color { 960 | x: 1.0 961 | y: 1.0 962 | z: 1.0 963 | w: 1.0 964 | } 965 | type: TYPE_TEXT 966 | blend_mode: BLEND_MODE_ALPHA 967 | text: "" 968 | font: "larryfont" 969 | id: "scores" 970 | xanchor: XANCHOR_NONE 971 | yanchor: YANCHOR_NONE 972 | pivot: PIVOT_W 973 | outline { 974 | x: 1.0 975 | y: 1.0 976 | z: 1.0 977 | w: 1.0 978 | } 979 | shadow { 980 | x: 1.0 981 | y: 1.0 982 | z: 1.0 983 | w: 1.0 984 | } 985 | adjust_mode: ADJUST_MODE_FIT 986 | line_break: true 987 | layer: "" 988 | inherit_alpha: true 989 | alpha: 1.0 990 | outline_alpha: 1.0 991 | shadow_alpha: 1.0 992 | template_node_child: false 993 | text_leading: 1.0 994 | text_tracking: 0.0 995 | } 996 | nodes { 997 | position { 998 | x: 170.0 999 | y: 412.0 1000 | z: 0.0 1001 | w: 1.0 1002 | } 1003 | rotation { 1004 | x: 0.0 1005 | y: 0.0 1006 | z: 0.0 1007 | w: 1.0 1008 | } 1009 | scale { 1010 | x: 1.0 1011 | y: 1.0 1012 | z: 1.0 1013 | w: 1.0 1014 | } 1015 | size { 1016 | x: 200.0 1017 | y: 100.0 1018 | z: 0.0 1019 | w: 1.0 1020 | } 1021 | color { 1022 | x: 1.0 1023 | y: 1.0 1024 | z: 1.0 1025 | w: 1.0 1026 | } 1027 | type: TYPE_TEMPLATE 1028 | id: "show_leaderboard" 1029 | layer: "" 1030 | inherit_alpha: true 1031 | alpha: 1.0 1032 | template: "/dirtylarry/button.gui" 1033 | template_node_child: false 1034 | } 1035 | nodes { 1036 | position { 1037 | x: 0.0 1038 | y: 0.0 1039 | z: 0.0 1040 | w: 1.0 1041 | } 1042 | rotation { 1043 | x: 0.0 1044 | y: 0.0 1045 | z: 0.0 1046 | w: 1.0 1047 | } 1048 | scale { 1049 | x: 1.0 1050 | y: 1.0 1051 | z: 1.0 1052 | w: 1.0 1053 | } 1054 | size { 1055 | x: 300.0 1056 | y: 88.0 1057 | z: 0.0 1058 | w: 1.0 1059 | } 1060 | color { 1061 | x: 1.0 1062 | y: 1.0 1063 | z: 1.0 1064 | w: 1.0 1065 | } 1066 | type: TYPE_BOX 1067 | blend_mode: BLEND_MODE_ALPHA 1068 | texture: "button/button_normal" 1069 | id: "show_leaderboard/larrybutton" 1070 | xanchor: XANCHOR_NONE 1071 | yanchor: YANCHOR_NONE 1072 | pivot: PIVOT_CENTER 1073 | adjust_mode: ADJUST_MODE_FIT 1074 | parent: "show_leaderboard" 1075 | layer: "" 1076 | inherit_alpha: true 1077 | slice9 { 1078 | x: 32.0 1079 | y: 32.0 1080 | z: 32.0 1081 | w: 32.0 1082 | } 1083 | clipping_mode: CLIPPING_MODE_NONE 1084 | clipping_visible: true 1085 | clipping_inverted: false 1086 | alpha: 1.0 1087 | template_node_child: true 1088 | size_mode: SIZE_MODE_MANUAL 1089 | } 1090 | nodes { 1091 | position { 1092 | x: 0.0 1093 | y: 0.0 1094 | z: 0.0 1095 | w: 1.0 1096 | } 1097 | rotation { 1098 | x: 0.0 1099 | y: 0.0 1100 | z: 0.0 1101 | w: 1.0 1102 | } 1103 | scale { 1104 | x: 1.0 1105 | y: 1.0 1106 | z: 1.0 1107 | w: 1.0 1108 | } 1109 | size { 1110 | x: 200.0 1111 | y: 100.0 1112 | z: 0.0 1113 | w: 1.0 1114 | } 1115 | color { 1116 | x: 1.0 1117 | y: 1.0 1118 | z: 1.0 1119 | w: 1.0 1120 | } 1121 | type: TYPE_TEXT 1122 | blend_mode: BLEND_MODE_ALPHA 1123 | text: "Show Leaderboard" 1124 | font: "larryfont" 1125 | id: "show_leaderboard/larrylabel" 1126 | xanchor: XANCHOR_NONE 1127 | yanchor: YANCHOR_NONE 1128 | pivot: PIVOT_CENTER 1129 | outline { 1130 | x: 0.0 1131 | y: 0.0 1132 | z: 0.0 1133 | w: 1.0 1134 | } 1135 | shadow { 1136 | x: 1.0 1137 | y: 1.0 1138 | z: 1.0 1139 | w: 1.0 1140 | } 1141 | adjust_mode: ADJUST_MODE_FIT 1142 | line_break: false 1143 | parent: "show_leaderboard/larrybutton" 1144 | layer: "" 1145 | inherit_alpha: true 1146 | alpha: 1.0 1147 | outline_alpha: 1.0 1148 | shadow_alpha: 1.0 1149 | overridden_fields: 8 1150 | template_node_child: true 1151 | text_leading: 1.0 1152 | text_tracking: 0.0 1153 | } 1154 | material: "/builtins/materials/gui.material" 1155 | adjust_reference: ADJUST_REFERENCE_PARENT 1156 | max_nodes: 512 1157 | -------------------------------------------------------------------------------- /main/snapshot.gui: -------------------------------------------------------------------------------- 1 | script: "/main/snapshot.gui_script" 2 | fonts { 3 | name: "larryfont" 4 | font: "/dirtylarry/larryfont.font" 5 | } 6 | textures { 7 | name: "logo" 8 | texture: "/main/logo.atlas" 9 | } 10 | background_color { 11 | x: 0.0 12 | y: 0.0 13 | z: 0.0 14 | w: 1.0 15 | } 16 | nodes { 17 | position { 18 | x: 170.0 19 | y: 650.0 20 | z: 0.0 21 | w: 1.0 22 | } 23 | rotation { 24 | x: 0.0 25 | y: 0.0 26 | z: 0.0 27 | w: 1.0 28 | } 29 | scale { 30 | x: 1.0 31 | y: 1.0 32 | z: 1.0 33 | w: 1.0 34 | } 35 | size { 36 | x: 200.0 37 | y: 100.0 38 | z: 0.0 39 | w: 1.0 40 | } 41 | color { 42 | x: 1.0 43 | y: 1.0 44 | z: 1.0 45 | w: 1.0 46 | } 47 | type: TYPE_TEMPLATE 48 | id: "snapshot_open" 49 | layer: "" 50 | inherit_alpha: true 51 | alpha: 1.0 52 | template: "/dirtylarry/button.gui" 53 | template_node_child: false 54 | } 55 | nodes { 56 | position { 57 | x: 0.0 58 | y: 0.0 59 | z: 0.0 60 | w: 1.0 61 | } 62 | rotation { 63 | x: 0.0 64 | y: 0.0 65 | z: 0.0 66 | w: 1.0 67 | } 68 | scale { 69 | x: 1.0 70 | y: 1.0 71 | z: 1.0 72 | w: 1.0 73 | } 74 | size { 75 | x: 300.0 76 | y: 88.0 77 | z: 0.0 78 | w: 1.0 79 | } 80 | color { 81 | x: 1.0 82 | y: 1.0 83 | z: 1.0 84 | w: 1.0 85 | } 86 | type: TYPE_BOX 87 | blend_mode: BLEND_MODE_ALPHA 88 | texture: "button/button_normal" 89 | id: "snapshot_open/larrybutton" 90 | xanchor: XANCHOR_NONE 91 | yanchor: YANCHOR_NONE 92 | pivot: PIVOT_CENTER 93 | adjust_mode: ADJUST_MODE_FIT 94 | parent: "snapshot_open" 95 | layer: "" 96 | inherit_alpha: true 97 | slice9 { 98 | x: 32.0 99 | y: 32.0 100 | z: 32.0 101 | w: 32.0 102 | } 103 | clipping_mode: CLIPPING_MODE_NONE 104 | clipping_visible: true 105 | clipping_inverted: false 106 | alpha: 1.0 107 | overridden_fields: 38 108 | template_node_child: true 109 | size_mode: SIZE_MODE_MANUAL 110 | } 111 | nodes { 112 | position { 113 | x: 0.0 114 | y: 0.0 115 | z: 0.0 116 | w: 1.0 117 | } 118 | rotation { 119 | x: 0.0 120 | y: 0.0 121 | z: 0.0 122 | w: 1.0 123 | } 124 | scale { 125 | x: 1.0 126 | y: 1.0 127 | z: 1.0 128 | w: 1.0 129 | } 130 | size { 131 | x: 200.0 132 | y: 100.0 133 | z: 0.0 134 | w: 1.0 135 | } 136 | color { 137 | x: 1.0 138 | y: 1.0 139 | z: 1.0 140 | w: 1.0 141 | } 142 | type: TYPE_TEXT 143 | blend_mode: BLEND_MODE_ALPHA 144 | text: "Open Snapshot" 145 | font: "larryfont" 146 | id: "snapshot_open/larrylabel" 147 | xanchor: XANCHOR_NONE 148 | yanchor: YANCHOR_NONE 149 | pivot: PIVOT_CENTER 150 | outline { 151 | x: 0.0 152 | y: 0.0 153 | z: 0.0 154 | w: 1.0 155 | } 156 | shadow { 157 | x: 1.0 158 | y: 1.0 159 | z: 1.0 160 | w: 1.0 161 | } 162 | adjust_mode: ADJUST_MODE_FIT 163 | line_break: false 164 | parent: "snapshot_open/larrybutton" 165 | layer: "" 166 | inherit_alpha: true 167 | alpha: 1.0 168 | outline_alpha: 1.0 169 | shadow_alpha: 1.0 170 | overridden_fields: 8 171 | template_node_child: true 172 | text_leading: 1.0 173 | text_tracking: 0.0 174 | } 175 | nodes { 176 | position { 177 | x: 170.0 178 | y: 530.0 179 | z: 0.0 180 | w: 1.0 181 | } 182 | rotation { 183 | x: 0.0 184 | y: 0.0 185 | z: 0.0 186 | w: 1.0 187 | } 188 | scale { 189 | x: 1.0 190 | y: 1.0 191 | z: 1.0 192 | w: 1.0 193 | } 194 | size { 195 | x: 200.0 196 | y: 100.0 197 | z: 0.0 198 | w: 1.0 199 | } 200 | color { 201 | x: 1.0 202 | y: 1.0 203 | z: 1.0 204 | w: 1.0 205 | } 206 | type: TYPE_TEMPLATE 207 | id: "snapshot_get_data" 208 | layer: "" 209 | inherit_alpha: true 210 | alpha: 1.0 211 | template: "/dirtylarry/button.gui" 212 | template_node_child: false 213 | } 214 | nodes { 215 | position { 216 | x: 0.0 217 | y: 0.0 218 | z: 0.0 219 | w: 1.0 220 | } 221 | rotation { 222 | x: 0.0 223 | y: 0.0 224 | z: 0.0 225 | w: 1.0 226 | } 227 | scale { 228 | x: 1.0 229 | y: 1.0 230 | z: 1.0 231 | w: 1.0 232 | } 233 | size { 234 | x: 300.0 235 | y: 88.0 236 | z: 0.0 237 | w: 1.0 238 | } 239 | color { 240 | x: 1.0 241 | y: 1.0 242 | z: 1.0 243 | w: 1.0 244 | } 245 | type: TYPE_BOX 246 | blend_mode: BLEND_MODE_ALPHA 247 | texture: "button/button_normal" 248 | id: "snapshot_get_data/larrybutton" 249 | xanchor: XANCHOR_NONE 250 | yanchor: YANCHOR_NONE 251 | pivot: PIVOT_CENTER 252 | adjust_mode: ADJUST_MODE_FIT 253 | parent: "snapshot_get_data" 254 | layer: "" 255 | inherit_alpha: true 256 | slice9 { 257 | x: 32.0 258 | y: 32.0 259 | z: 32.0 260 | w: 32.0 261 | } 262 | clipping_mode: CLIPPING_MODE_NONE 263 | clipping_visible: true 264 | clipping_inverted: false 265 | alpha: 1.0 266 | overridden_fields: 38 267 | template_node_child: true 268 | size_mode: SIZE_MODE_MANUAL 269 | } 270 | nodes { 271 | position { 272 | x: 0.0 273 | y: 0.0 274 | z: 0.0 275 | w: 1.0 276 | } 277 | rotation { 278 | x: 0.0 279 | y: 0.0 280 | z: 0.0 281 | w: 1.0 282 | } 283 | scale { 284 | x: 1.0 285 | y: 1.0 286 | z: 1.0 287 | w: 1.0 288 | } 289 | size { 290 | x: 200.0 291 | y: 100.0 292 | z: 0.0 293 | w: 1.0 294 | } 295 | color { 296 | x: 1.0 297 | y: 1.0 298 | z: 1.0 299 | w: 1.0 300 | } 301 | type: TYPE_TEXT 302 | blend_mode: BLEND_MODE_ALPHA 303 | text: "Get Save Data" 304 | font: "larryfont" 305 | id: "snapshot_get_data/larrylabel" 306 | xanchor: XANCHOR_NONE 307 | yanchor: YANCHOR_NONE 308 | pivot: PIVOT_CENTER 309 | outline { 310 | x: 0.0 311 | y: 0.0 312 | z: 0.0 313 | w: 1.0 314 | } 315 | shadow { 316 | x: 1.0 317 | y: 1.0 318 | z: 1.0 319 | w: 1.0 320 | } 321 | adjust_mode: ADJUST_MODE_FIT 322 | line_break: false 323 | parent: "snapshot_get_data/larrybutton" 324 | layer: "" 325 | inherit_alpha: true 326 | alpha: 1.0 327 | outline_alpha: 1.0 328 | shadow_alpha: 1.0 329 | overridden_fields: 8 330 | template_node_child: true 331 | text_leading: 1.0 332 | text_tracking: 0.0 333 | } 334 | nodes { 335 | position { 336 | x: 170.0 337 | y: 410.0 338 | z: 0.0 339 | w: 1.0 340 | } 341 | rotation { 342 | x: 0.0 343 | y: 0.0 344 | z: 0.0 345 | w: 1.0 346 | } 347 | scale { 348 | x: 1.0 349 | y: 1.0 350 | z: 1.0 351 | w: 1.0 352 | } 353 | size { 354 | x: 200.0 355 | y: 100.0 356 | z: 0.0 357 | w: 1.0 358 | } 359 | color { 360 | x: 1.0 361 | y: 1.0 362 | z: 1.0 363 | w: 1.0 364 | } 365 | type: TYPE_TEMPLATE 366 | id: "snapshot_set_data" 367 | layer: "" 368 | inherit_alpha: true 369 | alpha: 1.0 370 | template: "/dirtylarry/button.gui" 371 | template_node_child: false 372 | } 373 | nodes { 374 | position { 375 | x: 0.0 376 | y: 0.0 377 | z: 0.0 378 | w: 1.0 379 | } 380 | rotation { 381 | x: 0.0 382 | y: 0.0 383 | z: 0.0 384 | w: 1.0 385 | } 386 | scale { 387 | x: 1.0 388 | y: 1.0 389 | z: 1.0 390 | w: 1.0 391 | } 392 | size { 393 | x: 300.0 394 | y: 88.0 395 | z: 0.0 396 | w: 1.0 397 | } 398 | color { 399 | x: 1.0 400 | y: 1.0 401 | z: 1.0 402 | w: 1.0 403 | } 404 | type: TYPE_BOX 405 | blend_mode: BLEND_MODE_ALPHA 406 | texture: "button/button_normal" 407 | id: "snapshot_set_data/larrybutton" 408 | xanchor: XANCHOR_NONE 409 | yanchor: YANCHOR_NONE 410 | pivot: PIVOT_CENTER 411 | adjust_mode: ADJUST_MODE_FIT 412 | parent: "snapshot_set_data" 413 | layer: "" 414 | inherit_alpha: true 415 | slice9 { 416 | x: 32.0 417 | y: 32.0 418 | z: 32.0 419 | w: 32.0 420 | } 421 | clipping_mode: CLIPPING_MODE_NONE 422 | clipping_visible: true 423 | clipping_inverted: false 424 | alpha: 1.0 425 | overridden_fields: 38 426 | template_node_child: true 427 | size_mode: SIZE_MODE_MANUAL 428 | } 429 | nodes { 430 | position { 431 | x: 0.0 432 | y: 0.0 433 | z: 0.0 434 | w: 1.0 435 | } 436 | rotation { 437 | x: 0.0 438 | y: 0.0 439 | z: 0.0 440 | w: 1.0 441 | } 442 | scale { 443 | x: 1.0 444 | y: 1.0 445 | z: 1.0 446 | w: 1.0 447 | } 448 | size { 449 | x: 200.0 450 | y: 100.0 451 | z: 0.0 452 | w: 1.0 453 | } 454 | color { 455 | x: 1.0 456 | y: 1.0 457 | z: 1.0 458 | w: 1.0 459 | } 460 | type: TYPE_TEXT 461 | blend_mode: BLEND_MODE_ALPHA 462 | text: "Set Save Data" 463 | font: "larryfont" 464 | id: "snapshot_set_data/larrylabel" 465 | xanchor: XANCHOR_NONE 466 | yanchor: YANCHOR_NONE 467 | pivot: PIVOT_CENTER 468 | outline { 469 | x: 0.0 470 | y: 0.0 471 | z: 0.0 472 | w: 1.0 473 | } 474 | shadow { 475 | x: 1.0 476 | y: 1.0 477 | z: 1.0 478 | w: 1.0 479 | } 480 | adjust_mode: ADJUST_MODE_FIT 481 | line_break: false 482 | parent: "snapshot_set_data/larrybutton" 483 | layer: "" 484 | inherit_alpha: true 485 | alpha: 1.0 486 | outline_alpha: 1.0 487 | shadow_alpha: 1.0 488 | overridden_fields: 8 489 | template_node_child: true 490 | text_leading: 1.0 491 | text_tracking: 0.0 492 | } 493 | nodes { 494 | position { 495 | x: 490.0 496 | y: 410.0 497 | z: 0.0 498 | w: 1.0 499 | } 500 | rotation { 501 | x: 0.0 502 | y: 0.0 503 | z: 0.0 504 | w: 1.0 505 | } 506 | scale { 507 | x: 1.0 508 | y: 1.0 509 | z: 1.0 510 | w: 1.0 511 | } 512 | size { 513 | x: 200.0 514 | y: 100.0 515 | z: 0.0 516 | w: 1.0 517 | } 518 | color { 519 | x: 1.0 520 | y: 1.0 521 | z: 1.0 522 | w: 1.0 523 | } 524 | type: TYPE_TEMPLATE 525 | id: "save_snapshot" 526 | layer: "" 527 | inherit_alpha: true 528 | alpha: 1.0 529 | template: "/dirtylarry/button.gui" 530 | template_node_child: false 531 | } 532 | nodes { 533 | position { 534 | x: 0.0 535 | y: 0.0 536 | z: 0.0 537 | w: 1.0 538 | } 539 | rotation { 540 | x: 0.0 541 | y: 0.0 542 | z: 0.0 543 | w: 1.0 544 | } 545 | scale { 546 | x: 1.0 547 | y: 1.0 548 | z: 1.0 549 | w: 1.0 550 | } 551 | size { 552 | x: 300.0 553 | y: 88.0 554 | z: 0.0 555 | w: 1.0 556 | } 557 | color { 558 | x: 1.0 559 | y: 1.0 560 | z: 1.0 561 | w: 1.0 562 | } 563 | type: TYPE_BOX 564 | blend_mode: BLEND_MODE_ALPHA 565 | texture: "button/button_normal" 566 | id: "save_snapshot/larrybutton" 567 | xanchor: XANCHOR_NONE 568 | yanchor: YANCHOR_NONE 569 | pivot: PIVOT_CENTER 570 | adjust_mode: ADJUST_MODE_FIT 571 | parent: "save_snapshot" 572 | layer: "" 573 | inherit_alpha: true 574 | slice9 { 575 | x: 32.0 576 | y: 32.0 577 | z: 32.0 578 | w: 32.0 579 | } 580 | clipping_mode: CLIPPING_MODE_NONE 581 | clipping_visible: true 582 | clipping_inverted: false 583 | alpha: 1.0 584 | overridden_fields: 38 585 | template_node_child: true 586 | size_mode: SIZE_MODE_MANUAL 587 | } 588 | nodes { 589 | position { 590 | x: 0.0 591 | y: 0.0 592 | z: 0.0 593 | w: 1.0 594 | } 595 | rotation { 596 | x: 0.0 597 | y: 0.0 598 | z: 0.0 599 | w: 1.0 600 | } 601 | scale { 602 | x: 0.9 603 | y: 0.9 604 | z: 1.0 605 | w: 1.0 606 | } 607 | size { 608 | x: 200.0 609 | y: 100.0 610 | z: 0.0 611 | w: 1.0 612 | } 613 | color { 614 | x: 1.0 615 | y: 1.0 616 | z: 1.0 617 | w: 1.0 618 | } 619 | type: TYPE_TEXT 620 | blend_mode: BLEND_MODE_ALPHA 621 | text: "Commit and Close\n" 622 | "Snapshot" 623 | font: "larryfont" 624 | id: "save_snapshot/larrylabel" 625 | xanchor: XANCHOR_NONE 626 | yanchor: YANCHOR_NONE 627 | pivot: PIVOT_CENTER 628 | outline { 629 | x: 0.0 630 | y: 0.0 631 | z: 0.0 632 | w: 1.0 633 | } 634 | shadow { 635 | x: 1.0 636 | y: 1.0 637 | z: 1.0 638 | w: 1.0 639 | } 640 | adjust_mode: ADJUST_MODE_FIT 641 | line_break: false 642 | parent: "save_snapshot/larrybutton" 643 | layer: "" 644 | inherit_alpha: true 645 | alpha: 1.0 646 | outline_alpha: 1.0 647 | shadow_alpha: 1.0 648 | overridden_fields: 3 649 | overridden_fields: 8 650 | template_node_child: true 651 | text_leading: 1.0 652 | text_tracking: 0.0 653 | } 654 | nodes { 655 | position { 656 | x: 490.0 657 | y: 290.0 658 | z: 0.0 659 | w: 1.0 660 | } 661 | rotation { 662 | x: 0.0 663 | y: 0.0 664 | z: 0.0 665 | w: 1.0 666 | } 667 | scale { 668 | x: 1.0 669 | y: 1.0 670 | z: 1.0 671 | w: 1.0 672 | } 673 | size { 674 | x: 200.0 675 | y: 100.0 676 | z: 0.0 677 | w: 1.0 678 | } 679 | color { 680 | x: 1.0 681 | y: 1.0 682 | z: 1.0 683 | w: 1.0 684 | } 685 | type: TYPE_TEMPLATE 686 | id: "show_snapshots" 687 | layer: "" 688 | inherit_alpha: true 689 | alpha: 1.0 690 | template: "/dirtylarry/button.gui" 691 | template_node_child: false 692 | } 693 | nodes { 694 | position { 695 | x: 0.0 696 | y: 0.0 697 | z: 0.0 698 | w: 1.0 699 | } 700 | rotation { 701 | x: 0.0 702 | y: 0.0 703 | z: 0.0 704 | w: 1.0 705 | } 706 | scale { 707 | x: 1.0 708 | y: 1.0 709 | z: 1.0 710 | w: 1.0 711 | } 712 | size { 713 | x: 300.0 714 | y: 88.0 715 | z: 0.0 716 | w: 1.0 717 | } 718 | color { 719 | x: 1.0 720 | y: 1.0 721 | z: 1.0 722 | w: 1.0 723 | } 724 | type: TYPE_BOX 725 | blend_mode: BLEND_MODE_ALPHA 726 | texture: "button/button_normal" 727 | id: "show_snapshots/larrybutton" 728 | xanchor: XANCHOR_NONE 729 | yanchor: YANCHOR_NONE 730 | pivot: PIVOT_CENTER 731 | adjust_mode: ADJUST_MODE_FIT 732 | parent: "show_snapshots" 733 | layer: "" 734 | inherit_alpha: true 735 | slice9 { 736 | x: 32.0 737 | y: 32.0 738 | z: 32.0 739 | w: 32.0 740 | } 741 | clipping_mode: CLIPPING_MODE_NONE 742 | clipping_visible: true 743 | clipping_inverted: false 744 | alpha: 1.0 745 | template_node_child: true 746 | size_mode: SIZE_MODE_MANUAL 747 | } 748 | nodes { 749 | position { 750 | x: 0.0 751 | y: 0.0 752 | z: 0.0 753 | w: 1.0 754 | } 755 | rotation { 756 | x: 0.0 757 | y: 0.0 758 | z: 0.0 759 | w: 1.0 760 | } 761 | scale { 762 | x: 1.0 763 | y: 1.0 764 | z: 1.0 765 | w: 1.0 766 | } 767 | size { 768 | x: 200.0 769 | y: 100.0 770 | z: 0.0 771 | w: 1.0 772 | } 773 | color { 774 | x: 1.0 775 | y: 1.0 776 | z: 1.0 777 | w: 1.0 778 | } 779 | type: TYPE_TEXT 780 | blend_mode: BLEND_MODE_ALPHA 781 | text: "Show Saves" 782 | font: "larryfont" 783 | id: "show_snapshots/larrylabel" 784 | xanchor: XANCHOR_NONE 785 | yanchor: YANCHOR_NONE 786 | pivot: PIVOT_CENTER 787 | outline { 788 | x: 0.0 789 | y: 0.0 790 | z: 0.0 791 | w: 1.0 792 | } 793 | shadow { 794 | x: 1.0 795 | y: 1.0 796 | z: 1.0 797 | w: 1.0 798 | } 799 | adjust_mode: ADJUST_MODE_FIT 800 | line_break: false 801 | parent: "show_snapshots/larrybutton" 802 | layer: "" 803 | inherit_alpha: true 804 | alpha: 1.0 805 | outline_alpha: 1.0 806 | shadow_alpha: 1.0 807 | overridden_fields: 8 808 | template_node_child: true 809 | text_leading: 1.0 810 | text_tracking: 0.0 811 | } 812 | nodes { 813 | position { 814 | x: 829.0 815 | y: 680.168 816 | z: 0.0 817 | w: 1.0 818 | } 819 | rotation { 820 | x: 0.0 821 | y: 0.0 822 | z: 0.0 823 | w: 1.0 824 | } 825 | scale { 826 | x: 1.0 827 | y: 1.0 828 | z: 1.0 829 | w: 1.0 830 | } 831 | size { 832 | x: 440.0 833 | y: 40.0 834 | z: 0.0 835 | w: 1.0 836 | } 837 | color { 838 | x: 1.0 839 | y: 1.0 840 | z: 1.0 841 | w: 1.0 842 | } 843 | type: TYPE_TEXT 844 | blend_mode: BLEND_MODE_ALPHA 845 | text: "" 846 | font: "larryfont" 847 | id: "snapshotOpened" 848 | xanchor: XANCHOR_NONE 849 | yanchor: YANCHOR_NONE 850 | pivot: PIVOT_W 851 | outline { 852 | x: 1.0 853 | y: 1.0 854 | z: 1.0 855 | w: 1.0 856 | } 857 | shadow { 858 | x: 1.0 859 | y: 1.0 860 | z: 1.0 861 | w: 1.0 862 | } 863 | adjust_mode: ADJUST_MODE_FIT 864 | line_break: true 865 | layer: "" 866 | inherit_alpha: true 867 | alpha: 1.0 868 | outline_alpha: 1.0 869 | shadow_alpha: 1.0 870 | template_node_child: false 871 | text_leading: 1.0 872 | text_tracking: 0.0 873 | } 874 | nodes { 875 | position { 876 | x: 170.0 877 | y: 290.0 878 | z: 0.0 879 | w: 1.0 880 | } 881 | rotation { 882 | x: 0.0 883 | y: 0.0 884 | z: 0.0 885 | w: 1.0 886 | } 887 | scale { 888 | x: 1.0 889 | y: 1.0 890 | z: 1.0 891 | w: 1.0 892 | } 893 | size { 894 | x: 200.0 895 | y: 100.0 896 | z: 0.0 897 | w: 1.0 898 | } 899 | color { 900 | x: 1.0 901 | y: 1.0 902 | z: 1.0 903 | w: 1.0 904 | } 905 | type: TYPE_TEMPLATE 906 | id: "snapshot_get_conflicting_data" 907 | layer: "" 908 | inherit_alpha: true 909 | alpha: 1.0 910 | template: "/dirtylarry/button.gui" 911 | template_node_child: false 912 | } 913 | nodes { 914 | position { 915 | x: 0.0 916 | y: 0.0 917 | z: 0.0 918 | w: 1.0 919 | } 920 | rotation { 921 | x: 0.0 922 | y: 0.0 923 | z: 0.0 924 | w: 1.0 925 | } 926 | scale { 927 | x: 1.0 928 | y: 1.0 929 | z: 1.0 930 | w: 1.0 931 | } 932 | size { 933 | x: 300.0 934 | y: 88.0 935 | z: 0.0 936 | w: 1.0 937 | } 938 | color { 939 | x: 1.0 940 | y: 1.0 941 | z: 1.0 942 | w: 1.0 943 | } 944 | type: TYPE_BOX 945 | blend_mode: BLEND_MODE_ALPHA 946 | texture: "button/button_normal" 947 | id: "snapshot_get_conflicting_data/larrybutton" 948 | xanchor: XANCHOR_NONE 949 | yanchor: YANCHOR_NONE 950 | pivot: PIVOT_CENTER 951 | adjust_mode: ADJUST_MODE_FIT 952 | parent: "snapshot_get_conflicting_data" 953 | layer: "" 954 | inherit_alpha: true 955 | slice9 { 956 | x: 32.0 957 | y: 32.0 958 | z: 32.0 959 | w: 32.0 960 | } 961 | clipping_mode: CLIPPING_MODE_NONE 962 | clipping_visible: true 963 | clipping_inverted: false 964 | alpha: 1.0 965 | overridden_fields: 38 966 | template_node_child: true 967 | size_mode: SIZE_MODE_MANUAL 968 | } 969 | nodes { 970 | position { 971 | x: 0.0 972 | y: 0.0 973 | z: 0.0 974 | w: 1.0 975 | } 976 | rotation { 977 | x: 0.0 978 | y: 0.0 979 | z: 0.0 980 | w: 1.0 981 | } 982 | scale { 983 | x: 1.0 984 | y: 1.0 985 | z: 1.0 986 | w: 1.0 987 | } 988 | size { 989 | x: 200.0 990 | y: 100.0 991 | z: 0.0 992 | w: 1.0 993 | } 994 | color { 995 | x: 1.0 996 | y: 1.0 997 | z: 1.0 998 | w: 1.0 999 | } 1000 | type: TYPE_TEXT 1001 | blend_mode: BLEND_MODE_ALPHA 1002 | text: "Get Conflicting\n" 1003 | "Save Data" 1004 | font: "larryfont" 1005 | id: "snapshot_get_conflicting_data/larrylabel" 1006 | xanchor: XANCHOR_NONE 1007 | yanchor: YANCHOR_NONE 1008 | pivot: PIVOT_CENTER 1009 | outline { 1010 | x: 0.0 1011 | y: 0.0 1012 | z: 0.0 1013 | w: 1.0 1014 | } 1015 | shadow { 1016 | x: 1.0 1017 | y: 1.0 1018 | z: 1.0 1019 | w: 1.0 1020 | } 1021 | adjust_mode: ADJUST_MODE_FIT 1022 | line_break: false 1023 | parent: "snapshot_get_conflicting_data/larrybutton" 1024 | layer: "" 1025 | inherit_alpha: true 1026 | alpha: 1.0 1027 | outline_alpha: 1.0 1028 | shadow_alpha: 1.0 1029 | overridden_fields: 8 1030 | template_node_child: true 1031 | text_leading: 1.0 1032 | text_tracking: 0.0 1033 | } 1034 | nodes { 1035 | position { 1036 | x: 170.0 1037 | y: 182.0 1038 | z: 0.0 1039 | w: 1.0 1040 | } 1041 | rotation { 1042 | x: 0.0 1043 | y: 0.0 1044 | z: 0.0 1045 | w: 1.0 1046 | } 1047 | scale { 1048 | x: 1.0 1049 | y: 1.0 1050 | z: 1.0 1051 | w: 1.0 1052 | } 1053 | size { 1054 | x: 200.0 1055 | y: 100.0 1056 | z: 0.0 1057 | w: 1.0 1058 | } 1059 | color { 1060 | x: 1.0 1061 | y: 1.0 1062 | z: 1.0 1063 | w: 1.0 1064 | } 1065 | type: TYPE_TEMPLATE 1066 | id: "snapshot_resolve_conflict" 1067 | layer: "" 1068 | inherit_alpha: true 1069 | alpha: 1.0 1070 | template: "/dirtylarry/button.gui" 1071 | template_node_child: false 1072 | } 1073 | nodes { 1074 | position { 1075 | x: 0.0 1076 | y: 0.0 1077 | z: 0.0 1078 | w: 1.0 1079 | } 1080 | rotation { 1081 | x: 0.0 1082 | y: 0.0 1083 | z: 0.0 1084 | w: 1.0 1085 | } 1086 | scale { 1087 | x: 1.0 1088 | y: 1.0 1089 | z: 1.0 1090 | w: 1.0 1091 | } 1092 | size { 1093 | x: 300.0 1094 | y: 88.0 1095 | z: 0.0 1096 | w: 1.0 1097 | } 1098 | color { 1099 | x: 1.0 1100 | y: 1.0 1101 | z: 1.0 1102 | w: 1.0 1103 | } 1104 | type: TYPE_BOX 1105 | blend_mode: BLEND_MODE_ALPHA 1106 | texture: "button/button_normal" 1107 | id: "snapshot_resolve_conflict/larrybutton" 1108 | xanchor: XANCHOR_NONE 1109 | yanchor: YANCHOR_NONE 1110 | pivot: PIVOT_CENTER 1111 | adjust_mode: ADJUST_MODE_FIT 1112 | parent: "snapshot_resolve_conflict" 1113 | layer: "" 1114 | inherit_alpha: true 1115 | slice9 { 1116 | x: 32.0 1117 | y: 32.0 1118 | z: 32.0 1119 | w: 32.0 1120 | } 1121 | clipping_mode: CLIPPING_MODE_NONE 1122 | clipping_visible: true 1123 | clipping_inverted: false 1124 | alpha: 1.0 1125 | overridden_fields: 38 1126 | template_node_child: true 1127 | size_mode: SIZE_MODE_MANUAL 1128 | } 1129 | nodes { 1130 | position { 1131 | x: 0.0 1132 | y: 0.0 1133 | z: 0.0 1134 | w: 1.0 1135 | } 1136 | rotation { 1137 | x: 0.0 1138 | y: 0.0 1139 | z: 0.0 1140 | w: 1.0 1141 | } 1142 | scale { 1143 | x: 0.8 1144 | y: 0.8 1145 | z: 1.0 1146 | w: 1.0 1147 | } 1148 | size { 1149 | x: 200.0 1150 | y: 100.0 1151 | z: 0.0 1152 | w: 1.0 1153 | } 1154 | color { 1155 | x: 1.0 1156 | y: 1.0 1157 | z: 1.0 1158 | w: 1.0 1159 | } 1160 | type: TYPE_TEXT 1161 | blend_mode: BLEND_MODE_ALPHA 1162 | text: "Resolve Conflict\n" 1163 | "SNAPSHOT_CURRENT" 1164 | font: "larryfont" 1165 | id: "snapshot_resolve_conflict/larrylabel" 1166 | xanchor: XANCHOR_NONE 1167 | yanchor: YANCHOR_NONE 1168 | pivot: PIVOT_CENTER 1169 | outline { 1170 | x: 0.0 1171 | y: 0.0 1172 | z: 0.0 1173 | w: 1.0 1174 | } 1175 | shadow { 1176 | x: 1.0 1177 | y: 1.0 1178 | z: 1.0 1179 | w: 1.0 1180 | } 1181 | adjust_mode: ADJUST_MODE_FIT 1182 | line_break: false 1183 | parent: "snapshot_resolve_conflict/larrybutton" 1184 | layer: "" 1185 | inherit_alpha: true 1186 | alpha: 1.0 1187 | outline_alpha: 1.0 1188 | shadow_alpha: 1.0 1189 | overridden_fields: 3 1190 | overridden_fields: 8 1191 | template_node_child: true 1192 | text_leading: 1.0 1193 | text_tracking: 0.0 1194 | } 1195 | nodes { 1196 | position { 1197 | x: 488.0 1198 | y: 182.0 1199 | z: 0.0 1200 | w: 1.0 1201 | } 1202 | rotation { 1203 | x: 0.0 1204 | y: 0.0 1205 | z: 0.0 1206 | w: 1.0 1207 | } 1208 | scale { 1209 | x: 1.0 1210 | y: 1.0 1211 | z: 1.0 1212 | w: 1.0 1213 | } 1214 | size { 1215 | x: 200.0 1216 | y: 100.0 1217 | z: 0.0 1218 | w: 1.0 1219 | } 1220 | color { 1221 | x: 1.0 1222 | y: 1.0 1223 | z: 1.0 1224 | w: 1.0 1225 | } 1226 | type: TYPE_TEMPLATE 1227 | id: "snapshot_resolve_conflict_conflicting" 1228 | layer: "" 1229 | inherit_alpha: true 1230 | alpha: 1.0 1231 | template: "/dirtylarry/button.gui" 1232 | template_node_child: false 1233 | } 1234 | nodes { 1235 | position { 1236 | x: 0.0 1237 | y: 0.0 1238 | z: 0.0 1239 | w: 1.0 1240 | } 1241 | rotation { 1242 | x: 0.0 1243 | y: 0.0 1244 | z: 0.0 1245 | w: 1.0 1246 | } 1247 | scale { 1248 | x: 1.0 1249 | y: 1.0 1250 | z: 1.0 1251 | w: 1.0 1252 | } 1253 | size { 1254 | x: 300.0 1255 | y: 88.0 1256 | z: 0.0 1257 | w: 1.0 1258 | } 1259 | color { 1260 | x: 1.0 1261 | y: 1.0 1262 | z: 1.0 1263 | w: 1.0 1264 | } 1265 | type: TYPE_BOX 1266 | blend_mode: BLEND_MODE_ALPHA 1267 | texture: "button/button_normal" 1268 | id: "snapshot_resolve_conflict_conflicting/larrybutton" 1269 | xanchor: XANCHOR_NONE 1270 | yanchor: YANCHOR_NONE 1271 | pivot: PIVOT_CENTER 1272 | adjust_mode: ADJUST_MODE_FIT 1273 | parent: "snapshot_resolve_conflict_conflicting" 1274 | layer: "" 1275 | inherit_alpha: true 1276 | slice9 { 1277 | x: 32.0 1278 | y: 32.0 1279 | z: 32.0 1280 | w: 32.0 1281 | } 1282 | clipping_mode: CLIPPING_MODE_NONE 1283 | clipping_visible: true 1284 | clipping_inverted: false 1285 | alpha: 1.0 1286 | overridden_fields: 38 1287 | template_node_child: true 1288 | size_mode: SIZE_MODE_MANUAL 1289 | } 1290 | nodes { 1291 | position { 1292 | x: 0.0 1293 | y: 0.0 1294 | z: 0.0 1295 | w: 1.0 1296 | } 1297 | rotation { 1298 | x: 0.0 1299 | y: 0.0 1300 | z: 0.0 1301 | w: 1.0 1302 | } 1303 | scale { 1304 | x: 0.7 1305 | y: 0.7 1306 | z: 1.0 1307 | w: 1.0 1308 | } 1309 | size { 1310 | x: 200.0 1311 | y: 100.0 1312 | z: 0.0 1313 | w: 1.0 1314 | } 1315 | color { 1316 | x: 1.0 1317 | y: 1.0 1318 | z: 1.0 1319 | w: 1.0 1320 | } 1321 | type: TYPE_TEXT 1322 | blend_mode: BLEND_MODE_ALPHA 1323 | text: "Resolve conflict\n" 1324 | "SNAPSHOT_CONFLICTING" 1325 | font: "larryfont" 1326 | id: "snapshot_resolve_conflict_conflicting/larrylabel" 1327 | xanchor: XANCHOR_NONE 1328 | yanchor: YANCHOR_NONE 1329 | pivot: PIVOT_CENTER 1330 | outline { 1331 | x: 0.0 1332 | y: 0.0 1333 | z: 0.0 1334 | w: 1.0 1335 | } 1336 | shadow { 1337 | x: 1.0 1338 | y: 1.0 1339 | z: 1.0 1340 | w: 1.0 1341 | } 1342 | adjust_mode: ADJUST_MODE_FIT 1343 | line_break: false 1344 | parent: "snapshot_resolve_conflict_conflicting/larrybutton" 1345 | layer: "" 1346 | inherit_alpha: true 1347 | alpha: 1.0 1348 | outline_alpha: 1.0 1349 | shadow_alpha: 1.0 1350 | overridden_fields: 3 1351 | overridden_fields: 8 1352 | template_node_child: true 1353 | text_leading: 1.0 1354 | text_tracking: 0.0 1355 | } 1356 | nodes { 1357 | position { 1358 | x: 170.0 1359 | y: 60.0 1360 | z: 0.0 1361 | w: 1.0 1362 | } 1363 | rotation { 1364 | x: 0.0 1365 | y: 0.0 1366 | z: 0.0 1367 | w: 1.0 1368 | } 1369 | scale { 1370 | x: 1.0 1371 | y: 1.0 1372 | z: 1.0 1373 | w: 1.0 1374 | } 1375 | size { 1376 | x: 200.0 1377 | y: 100.0 1378 | z: 0.0 1379 | w: 1.0 1380 | } 1381 | color { 1382 | x: 1.0 1383 | y: 1.0 1384 | z: 1.0 1385 | w: 1.0 1386 | } 1387 | type: TYPE_TEMPLATE 1388 | id: "back" 1389 | layer: "" 1390 | inherit_alpha: true 1391 | alpha: 1.0 1392 | template: "/dirtylarry/button.gui" 1393 | template_node_child: false 1394 | } 1395 | nodes { 1396 | position { 1397 | x: 0.0 1398 | y: 0.0 1399 | z: 0.0 1400 | w: 1.0 1401 | } 1402 | rotation { 1403 | x: 0.0 1404 | y: 0.0 1405 | z: 0.0 1406 | w: 1.0 1407 | } 1408 | scale { 1409 | x: 1.0 1410 | y: 1.0 1411 | z: 1.0 1412 | w: 1.0 1413 | } 1414 | size { 1415 | x: 300.0 1416 | y: 88.0 1417 | z: 0.0 1418 | w: 1.0 1419 | } 1420 | color { 1421 | x: 1.0 1422 | y: 1.0 1423 | z: 1.0 1424 | w: 1.0 1425 | } 1426 | type: TYPE_BOX 1427 | blend_mode: BLEND_MODE_ALPHA 1428 | texture: "button/button_normal" 1429 | id: "back/larrybutton" 1430 | xanchor: XANCHOR_NONE 1431 | yanchor: YANCHOR_NONE 1432 | pivot: PIVOT_CENTER 1433 | adjust_mode: ADJUST_MODE_FIT 1434 | parent: "back" 1435 | layer: "" 1436 | inherit_alpha: true 1437 | slice9 { 1438 | x: 32.0 1439 | y: 32.0 1440 | z: 32.0 1441 | w: 32.0 1442 | } 1443 | clipping_mode: CLIPPING_MODE_NONE 1444 | clipping_visible: true 1445 | clipping_inverted: false 1446 | alpha: 1.0 1447 | overridden_fields: 38 1448 | template_node_child: true 1449 | size_mode: SIZE_MODE_MANUAL 1450 | } 1451 | nodes { 1452 | position { 1453 | x: 0.0 1454 | y: 0.0 1455 | z: 0.0 1456 | w: 1.0 1457 | } 1458 | rotation { 1459 | x: 0.0 1460 | y: 0.0 1461 | z: 0.0 1462 | w: 1.0 1463 | } 1464 | scale { 1465 | x: 1.0 1466 | y: 1.0 1467 | z: 1.0 1468 | w: 1.0 1469 | } 1470 | size { 1471 | x: 200.0 1472 | y: 100.0 1473 | z: 0.0 1474 | w: 1.0 1475 | } 1476 | color { 1477 | x: 1.0 1478 | y: 1.0 1479 | z: 1.0 1480 | w: 1.0 1481 | } 1482 | type: TYPE_TEXT 1483 | blend_mode: BLEND_MODE_ALPHA 1484 | text: "BACK" 1485 | font: "larryfont" 1486 | id: "back/larrylabel" 1487 | xanchor: XANCHOR_NONE 1488 | yanchor: YANCHOR_NONE 1489 | pivot: PIVOT_CENTER 1490 | outline { 1491 | x: 0.0 1492 | y: 0.0 1493 | z: 0.0 1494 | w: 1.0 1495 | } 1496 | shadow { 1497 | x: 1.0 1498 | y: 1.0 1499 | z: 1.0 1500 | w: 1.0 1501 | } 1502 | adjust_mode: ADJUST_MODE_FIT 1503 | line_break: false 1504 | parent: "back/larrybutton" 1505 | layer: "" 1506 | inherit_alpha: true 1507 | alpha: 1.0 1508 | outline_alpha: 1.0 1509 | shadow_alpha: 1.0 1510 | overridden_fields: 8 1511 | template_node_child: true 1512 | text_leading: 1.0 1513 | text_tracking: 0.0 1514 | } 1515 | nodes { 1516 | position { 1517 | x: 829.0 1518 | y: 627.168 1519 | z: 0.0 1520 | w: 1.0 1521 | } 1522 | rotation { 1523 | x: 0.0 1524 | y: 0.0 1525 | z: 0.0 1526 | w: 1.0 1527 | } 1528 | scale { 1529 | x: 1.0 1530 | y: 1.0 1531 | z: 1.0 1532 | w: 1.0 1533 | } 1534 | size { 1535 | x: 440.0 1536 | y: 40.0 1537 | z: 0.0 1538 | w: 1.0 1539 | } 1540 | color { 1541 | x: 1.0 1542 | y: 1.0 1543 | z: 1.0 1544 | w: 1.0 1545 | } 1546 | type: TYPE_TEXT 1547 | blend_mode: BLEND_MODE_ALPHA 1548 | text: "" 1549 | font: "larryfont" 1550 | id: "snapshotConflict" 1551 | xanchor: XANCHOR_NONE 1552 | yanchor: YANCHOR_NONE 1553 | pivot: PIVOT_W 1554 | outline { 1555 | x: 1.0 1556 | y: 1.0 1557 | z: 1.0 1558 | w: 1.0 1559 | } 1560 | shadow { 1561 | x: 1.0 1562 | y: 1.0 1563 | z: 1.0 1564 | w: 1.0 1565 | } 1566 | adjust_mode: ADJUST_MODE_FIT 1567 | line_break: true 1568 | layer: "" 1569 | inherit_alpha: true 1570 | alpha: 1.0 1571 | outline_alpha: 1.0 1572 | shadow_alpha: 1.0 1573 | template_node_child: false 1574 | text_leading: 1.0 1575 | text_tracking: 0.0 1576 | } 1577 | material: "/builtins/materials/gui.material" 1578 | adjust_reference: ADJUST_REFERENCE_PARENT 1579 | max_nodes: 512 1580 | -------------------------------------------------------------------------------- /gpgs/api/gpgs.script_api: -------------------------------------------------------------------------------- 1 | - name: gpgs 2 | type: table 3 | desc: Functions and constants for interacting with Google Play Game Services (GPGS) APIs 4 | 5 | members: 6 | 7 | #***************************************************************************************************** 8 | 9 | - name: is_supported 10 | type: function 11 | desc: Check if Google Play Services are available & ready on the device. 12 | 13 | returns: 14 | - name: is_supported 15 | type: boolean 16 | desc: Status of Google Play Services on the device. 17 | 18 | examples: 19 | - desc: |- 20 | ```lua 21 | if gpgs then 22 | local is_supported = gpgs.is_supported() 23 | end 24 | ``` 25 | 26 | #***************************************************************************************************** 27 | 28 | - name: login 29 | type: function 30 | desc: Login to GPGS using a button. 31 | 32 | examples: 33 | - desc: |- 34 | Log in to GPGS using a button: 35 | ```lua 36 | if gpgs then 37 | gpgs.login() 38 | end 39 | ``` 40 | 41 | #***************************************************************************************************** 42 | 43 | - name: silent_login 44 | type: function 45 | desc: Silent login to GPGS. 46 | 47 | This function is trying to retrieve the currently signed-in player’s account. 48 | 49 | examples: 50 | - desc: |- 51 | ```lua 52 | function init(self) 53 | if gpgs then 54 | gpgs.silent_login() 55 | end 56 | end 57 | ``` 58 | 59 | #***************************************************************************************************** 60 | 61 | - name: get_display_name 62 | type: function 63 | desc: Get the current GPGS player display name. 64 | 65 | returns: 66 | - name: name 67 | type: string 68 | desc: The player's display name. 69 | 70 | examples: 71 | - desc: |- 72 | ```lua 73 | if gpgs then 74 | local name = gpgs.get_display_name() 75 | end 76 | ``` 77 | 78 | #***************************************************************************************************** 79 | 80 | - name: get_id 81 | type: function 82 | desc: Get the current GPGS player id. 83 | 84 | returns: 85 | - name: id 86 | type: string 87 | desc: The player ID. 88 | 89 | examples: 90 | - desc: |- 91 | ```lua 92 | if gpgs then 93 | local id = gpgs.get_id() 94 | end 95 | ``` 96 | 97 | #***************************************************************************************************** 98 | 99 | - name: get_server_auth_code 100 | type: function 101 | desc: Returns a one-time server auth code to send to your web server which can be exchanged for access token 102 | 103 | Token can be retrieved only if `gpgs.request_server_auth_code` set to 1 and `gpgs.client` is set. 104 | 105 | returns: 106 | - name: server_auth_code 107 | type: string 108 | desc: The server auth code for logged in account. Can be nil if operation is not completed yet. 109 | 110 | Auth token is avaliable after receiving message with id `gpgs.MSG_GET_SERVER_TOKEN` 111 | in callback set via `gpgs.set_callback`. 112 | 113 | examples: 114 | - desc: |- 115 | ```lua 116 | if gpgs then 117 | local server_auth_code = gpgs.get_server_auth_code() 118 | end 119 | ``` 120 | 121 | #***************************************************************************************************** 122 | 123 | - name: is_logged_in 124 | type: function 125 | desc: Check if a user is logged in currently. 126 | 127 | returns: 128 | - name: is_loggedin 129 | type: boolean 130 | desc: Current login state. 131 | 132 | examples: 133 | - desc: |- 134 | ```lua 135 | if gpgs then 136 | local is_loggedin = gpgs.is_logged_in() 137 | end 138 | ``` 139 | 140 | #***************************************************************************************************** 141 | 142 | - name: set_callback 143 | type: function 144 | desc: Set callback for receiving messages from GPGS. 145 | 146 | parameters: 147 | - name: callback 148 | type: function 149 | desc: A callback taking the following parameters 150 | parameters: 151 | - name: self 152 | type: object 153 | desc: The calling script 154 | 155 | - name: message_id 156 | type: number 157 | desc: An message_id can be one of the predefined constants below 158 | 159 | - `gpgs.MSG_SIGN_IN` 160 | 161 | - `gpgs.MSG_SILENT_SIGN_IN` 162 | 163 | - `gpgs.MSG_SHOW_SNAPSHOTS` 164 | 165 | - `gpgs.MSG_LOAD_SNAPSHOT` 166 | 167 | - `gpgs.MSG_SAVE_SNAPSHOT` 168 | 169 | 170 | - name: message 171 | type: table 172 | desc: Contains information that depends on message_id. 173 | members: 174 | - name: status 175 | type: number 176 | desc: Status of the current operation. It can be one of the predefined constants below 177 | 178 | - `gpgs.STATUS_SUCCESS` 179 | 180 | - `gpgs.STATUS_FAILED` 181 | 182 | - `gpgs.STATUS_CREATE_NEW_SAVE` 183 | 184 | - `gpgs.STATUS_CONFLICT` 185 | 186 | - name: error 187 | type: string 188 | optional: true 189 | desc: The error message. Available only if `status` is `gpgs.STATUS_FAILED`. 190 | 191 | - name: error_status 192 | type: number 193 | optional: true 194 | desc: The error code. Available only if `status` is `gpgs.STATUS_FAILED` and GPGS provide this code. 195 | It can be one of the predefined constants below 196 | 197 | - `gpgs.ERROR_STATUS_SNAPSHOT_COMMIT_FAILED` 198 | 199 | - `gpgs.ERROR_STATUS_SNAPSHOT_CONFLICT_MISSING` 200 | 201 | - `gpgs.ERROR_STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE` 202 | 203 | - `gpgs.ERROR_STATUS_SNAPSHOT_CREATION_FAILED` 204 | 205 | - `gpgs.ERROR_STATUS_SNAPSHOT_FOLDER_UNAVAILABLE` 206 | 207 | - `gpgs.ERROR_STATUS_SNAPSHOT_NOT_FOUND` 208 | 209 | Or it can be ApiException.getStatusCode() (if ApiException was thrown) 210 | 211 | - name: metadata 212 | type: table 213 | optional: true 214 | desc: Metadata of the loaded save. Available only if `message_id` is `gpgs.MSG_LOAD_SNAPSHOT`. 215 | 216 | - name: conflictId 217 | type: string 218 | optional: true 219 | desc: The conflict id. Available only if `status` is `gpgs.STATUS_CONFLICT`. 220 | 221 | - name: conflictMetadata 222 | type: table 223 | optional: true 224 | desc: The conflicting metadata. Available only if `status` is `gpgs.STATUS_CONFLICT`. 225 | 226 | examples: 227 | - desc: |- 228 | ```lua 229 | function callback(self, message_id, message) 230 | if message_id == gpgs.MSG_SIGN_IN or message_id == gpgs.MSG_SILENT_SIGN_IN then 231 | if message.status == gpgs.STATUS_SUCCESS then 232 | -- do something after login 233 | end 234 | elseif message_id == gpgs.MSG_LOAD_SNAPSHOT then 235 | -- do something when a save was loaded 236 | end 237 | end 238 | 239 | function init(self) 240 | gpgs.set_callback(callback) 241 | end 242 | 243 | function init(self) 244 | gpgs.set_callback(nil) -- remove callback 245 | end 246 | ``` 247 | 248 | #***************************************************************************************************** 249 | 250 | - name: snapshot_display_saves 251 | type: function 252 | desc: Provides a default saved games selection user interface. 253 | 254 | parameters: 255 | - name: popupTitle 256 | type: string 257 | optional: true 258 | desc: The title to display in the action bar. By default "Game Saves". 259 | 260 | - name: allowAddButton 261 | type: boolean 262 | optional: true 263 | desc: Whether or not to display a "create new snapshot" option in the selection UI. By default `true`. 264 | 265 | - name: allowDelete 266 | type: boolean 267 | optional: true 268 | desc: Whether or not to provide a delete overflow menu option for each snapshot in the selection UI. By default `true`. 269 | 270 | - name: maxNumberOfSavedGamesToShow 271 | type: number 272 | optional: true 273 | desc: The maximum number of snapshots to display in the UI. By default 5. 274 | 275 | examples: 276 | - desc: |- 277 | ```lua 278 | if gpgs then 279 | gpgs.snapshot_display_saves("Choose the save of the game", false, true, 10) 280 | end 281 | ``` 282 | 283 | #***************************************************************************************************** 284 | 285 | - name: snapshot_open 286 | type: function 287 | desc: Opens a snapshot with the given `saveName`. If `createIfNotFound` is set to `true`, the specified snapshot will be created if it does not already exist. 288 | 289 | parameters: 290 | - name: saveName 291 | type: string 292 | desc: The name of the snapshot file to open. Must be between 1 and 100 non-URL-reserved characters (a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~"). 293 | 294 | - name: createIfNotFound 295 | type: boolean 296 | optional: true 297 | desc: If `true`, the snapshot will be created if one cannot be found. 298 | 299 | - name: conflictPolicy 300 | type: number 301 | optional: true 302 | desc: The conflict resolution policy to use for this snapshot that can be one of the predefined constants below 303 | 304 | - `gpgs.RESOLUTION_POLICY_MANUAL` 305 | 306 | - `gpgs.RESOLUTION_POLICY_LONGEST_PLAYTIME` 307 | 308 | - `gpgs.RESOLUTION_POLICY_LAST_KNOWN_GOOD` 309 | 310 | - `gpgs.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED` 311 | 312 | - `gpgs.RESOLUTION_POLICY_HIGHEST_PROGRESS` 313 | 314 | 315 | Default value is `gpgs.RESOLUTION_POLICY_LAST_KNOWN_GOOD` 316 | 317 | examples: 318 | - desc: |- 319 | ```lua 320 | if gpgs then 321 | gpgs.snapshot_open("my_save_1", true, gpgs.RESOLUTION_POLICY_LONGEST_PLAYTIME) 322 | end 323 | ``` 324 | 325 | #***************************************************************************************************** 326 | 327 | - name: snapshot_commit_and_close 328 | type: function 329 | desc: Save the currently opened save on the server and close it. 330 | 331 | parameters: 332 | - name: metadata 333 | type: table 334 | optional: true 335 | desc: A table with metadata for a save. It contains the fields below 336 | members: 337 | - name: playedTime 338 | type: number 339 | optional: true 340 | desc: The new played time to set for the snapshot in ms. 341 | 342 | - name: progressValue 343 | type: number 344 | optional: true 345 | desc: The new progress value to set for the snapshot. 346 | 347 | - name: description 348 | type: string 349 | optional: true 350 | desc: The new description to set for the snapshot. 351 | 352 | - name: coverImage 353 | type: object 354 | optional: true 355 | desc: The new cover image to set for the snapshot in `png`. 356 | 357 | 358 | examples: 359 | - desc: |- 360 | ```lua 361 | if gpgs then 362 | local png_img, w, h = screenshot.png() 363 | gpgs.snapshot_commit_and_close({ 364 | coverImage = png_img, 365 | description = "LEVEL 31, CAVE", 366 | playedTime = 12345667, 367 | progressValue = 657 368 | }) 369 | end 370 | ``` 371 | 372 | #***************************************************************************************************** 373 | 374 | - name: snapshot_get_data 375 | type: function 376 | desc: Returns the currently opened snapshot data. 377 | 378 | returns: 379 | - name: bytes 380 | type: string 381 | desc: The byte array data of the currently opened snapshot. `nil` if something goes wrong. 382 | 383 | - name: error_message 384 | type: string 385 | desc: An error message if something goes wrong. 386 | 387 | examples: 388 | - desc: |- 389 | ```lua 390 | if gpgs then 391 | local bytes, error_message = gpgs.snapshot_get_data() 392 | if not bytes then 393 | print("snapshot_get_data ERROR:", error_message) 394 | else 395 | print("snapshot_get_data",bytes) 396 | -- Do something with your data 397 | end 398 | end 399 | ``` 400 | 401 | #***************************************************************************************************** 402 | 403 | - name: snapshot_set_data 404 | type: function 405 | desc: Sets the data for the currently opened snapshot. 406 | 407 | parameters: 408 | - name: data 409 | type: string 410 | desc: The data to set. 411 | 412 | returns: 413 | - name: success 414 | type: boolean 415 | desc: True if data was set for the currently opened snapshot. 416 | 417 | - name: error_message 418 | type: string 419 | desc: An error message if something goes wrong. 420 | 421 | examples: 422 | - desc: |- 423 | ```lua 424 | if gpgs then 425 | local success, error_message = gpgs.snapshot_set_data(my_data) 426 | if not success then 427 | print("snapshot_set_data ERROR:", error_message) 428 | end 429 | end 430 | ``` 431 | 432 | #***************************************************************************************************** 433 | 434 | - name: snapshot_is_opened 435 | type: function 436 | desc: Check if a snapshot was opened. 437 | 438 | returns: 439 | - name: is_opened 440 | type: boolean 441 | desc: A current snapshot state. 442 | 443 | examples: 444 | - desc: |- 445 | ```lua 446 | if gpgs then 447 | local is_opened = gpgs.snapshot_is_opened() 448 | end 449 | ``` 450 | 451 | #***************************************************************************************************** 452 | 453 | - name: snapshot_get_max_image_size 454 | type: function 455 | desc: Returns the maximum data size per snapshot cover image in bytes. 456 | 457 | returns: 458 | - name: image_size 459 | type: number 460 | desc: The maximum data size per snapshot cover image in bytes. 461 | 462 | examples: 463 | - desc: |- 464 | ```lua 465 | if gpgs then 466 | local image_size = gpgs.snapshot_get_max_image_size() 467 | end 468 | ``` 469 | 470 | #***************************************************************************************************** 471 | 472 | - name: snapshot_get_max_save_size 473 | type: function 474 | desc: Returns the maximum data size per snapshot in bytes. 475 | 476 | returns: 477 | - name: data_size 478 | type: number 479 | desc: The maximum data size per snapshot in bytes. 480 | 481 | examples: 482 | - desc: |- 483 | ```lua 484 | if gpgs then 485 | local data_size = gpgs.snapshot_get_max_save_size() 486 | end 487 | ``` 488 | 489 | #***************************************************************************************************** 490 | 491 | - name: snapshot_get_conflicting_data 492 | type: function 493 | desc: Returns the conflicting snapshot data. 494 | 495 | returns: 496 | - name: bytes 497 | type: string 498 | desc: The byte array data of the conflicting snapshot. `nil` if something goes wrong. 499 | 500 | - name: error_message 501 | type: boolean 502 | desc: An error message if something goes wrong. 503 | 504 | examples: 505 | - desc: |- 506 | ```lua 507 | if gpgs then 508 | local bytes, error_message = gpgs.snapshot_get_conflicting_data() 509 | if not bytes then 510 | print("snapshot_get_conflicting_data ERROR:", error_message) 511 | else 512 | print("snapshot_get_conflicting_data:",bytes) 513 | -- Do something with conflicting data data 514 | end 515 | end 516 | ``` 517 | 518 | #***************************************************************************************************** 519 | 520 | - name: snapshot_resolve_conflict 521 | type: function 522 | desc: Resolves a conflict using the data from the provided snapshot. 523 | 524 | parameters: 525 | - name: conflictId 526 | type: string 527 | desc: The conflict id that you want to resolve. Provided in `message` table with `STATUS_CONFLICT` message type. 528 | 529 | - name: snapshotId 530 | type: number 531 | desc: Type of the snapshot you want to use for conflict solving that can be one of the predefined constants below 532 | 533 | - `gpgs.SNAPSHOT_CURRENT` 534 | 535 | - `gpgs.SNAPSHOT_CONFLICTING` 536 | 537 | examples: 538 | - desc: |- 539 | ```lua 540 | if gpgs then 541 | gpgs.snapshot_resolve_conflict(self.conflictId, gpgs.SNAPSHOT_CONFLICTING) 542 | end 543 | ``` 544 | #***************************************************************************************************** 545 | 546 | - name: leaderboard_submit_score 547 | type: function 548 | desc: Submit a score to a leaderboard for the currently signed-in player. 549 | 550 | parameters: 551 | - name: leaderboardId 552 | type: string 553 | 554 | - name: score 555 | type: number 556 | 557 | #***************************************************************************************************** 558 | 559 | - name: leaderboard_get_top_scores 560 | type: function 561 | desc: Asynchronously gets the top page of scores for a leaderboard. 562 | 563 | parameters: 564 | - name: leaderboardId 565 | type: string 566 | 567 | - name: time_span 568 | type: number 569 | desc: One of the gpgs.TIME_SPAN_ constants 570 | 571 | - name: collection 572 | type: number 573 | desc: One of the gpgs.COLLECTION_ constants 574 | 575 | - name: max_results 576 | type: number 577 | desc: Between 1-25 578 | 579 | #***************************************************************************************************** 580 | 581 | - name: leaderboard_get_player_centered_scores 582 | type: function 583 | desc: Asynchronously gets a player-centered page of scores for a leaderboard. 584 | 585 | parameters: 586 | - name: leaderboardId 587 | type: string 588 | 589 | - name: time_span 590 | type: number 591 | desc: One of the gpgs.TIME_SPAN_ constants 592 | 593 | - name: collection 594 | type: number 595 | desc: One of the gpgs.COLLECTION_ constants 596 | 597 | - name: max_results 598 | type: number 599 | desc: Between 1-25 600 | 601 | - name: force_reload 602 | type: boolean 603 | desc: If true, this call will clear any locally cached data and attempt to fetch the latest data from the server 604 | 605 | #***************************************************************************************************** 606 | 607 | - name: leaderboard_show 608 | type: function 609 | desc: Show a leaderboard for a game specified by a leaderboardId. 610 | 611 | parameters: 612 | - name: leaderboardId 613 | type: string 614 | 615 | - name: time_span 616 | type: number 617 | desc: One of the gpgs.TIME_SPAN_ constants 618 | 619 | - name: collection 620 | type: number 621 | desc: One of the gpgs.COLLECTION_ constants 622 | 623 | #***************************************************************************************************** 624 | 625 | - name: leaderboard_list 626 | type: function 627 | desc: Show the list of leaderboards. 628 | 629 | #***************************************************************************************************** 630 | - name: leaderboard_get_player_score 631 | type: function 632 | desc: Asynchronously gets a player-centered page of scores for a leaderboard. 633 | 634 | parameters: 635 | - name: leaderboardId 636 | type: string 637 | 638 | - name: time_span 639 | type: number 640 | desc: One of the gpgs.TIME_SPAN_ constants 641 | 642 | - name: collection 643 | type: number 644 | desc: One of the gpgs.COLLECTION_ constants 645 | 646 | #***************************************************************************************************** 647 | 648 | - name: achievement_reveal 649 | type: function 650 | desc: Reveals a hidden achievement to the current player. 651 | 652 | parameters: 653 | - name: achievementId 654 | type: string 655 | desc: Achievement id (from GP console) 656 | 657 | #***************************************************************************************************** 658 | - name: achievement_unlock 659 | type: function 660 | desc: Unlocks an achievement for the current player. 661 | 662 | parameters: 663 | - name: achievementId 664 | type: string 665 | desc: Achievement id (from GP console) 666 | 667 | #***************************************************************************************************** 668 | - name: achievement_set 669 | type: function 670 | desc: Sets an achievement to have at least the given number of steps completed. 671 | 672 | parameters: 673 | - name: achievementId 674 | type: string 675 | desc: Achievement id (from GP console) 676 | 677 | - name: steps 678 | type: number 679 | desc: The number of steps to set the achievement to. Must be greater than 0. 680 | 681 | #***************************************************************************************************** 682 | - name: achievement_increment 683 | type: function 684 | desc: Increments an achievement by the given number of steps. 685 | 686 | parameters: 687 | - name: achievementId 688 | type: string 689 | desc: Achievement id (from GP console) 690 | 691 | - name: steps 692 | type: number 693 | desc: The number of steps to increment by. Must be greater than 0. 694 | 695 | #***************************************************************************************************** 696 | - name: achievement_show 697 | type: function 698 | desc: Show achivements 699 | 700 | #***************************************************************************************************** 701 | - name: achievement_get 702 | type: function 703 | desc: Get information about all achievement's state asynchronously. Result return to callback previously set by 704 | `gpgs.set_callback` with `message_id == gpgs.MSG_ACHIEVEMENTS`. Result is array of tables which contain 705 | following fields 706 | 707 | - `id` - achievement id (from GP console) 708 | 709 | - `name` - achievement name 710 | 711 | - `description` - achievement description 712 | 713 | - `xp` - how much experience points will be added when achievement will be unlocked 714 | 715 | - `steps` - current step of incremental achievement 716 | 717 | - `total_steps` - total amount of steps of incremental achievement 718 | 719 | - `unlocked` - set to `true` if achievement is unlocked. Otherwise field is missed. 720 | 721 | - `hidden` - set to `true if achievement is hidden. Otherwise field is missed. 722 | 723 | - `revealed` - set to `true` if achievement is revealed. Otherwise field is missed. 724 | 725 | 726 | #***************************************************************************************************** 727 | - name: event_increment 728 | type: function 729 | desc: Increments an event specified by `eventId` by the given number of steps 730 | 731 | parameters: 732 | - name: eventId 733 | type: string 734 | desc: Event id (from GP console) 735 | 736 | - name: amount 737 | type: number 738 | desc: The amount increment by. Must be greater than or equal to 0 739 | 740 | #***************************************************************************************************** 741 | - name: event_get 742 | type: function 743 | desc: Get information about all events asynchronously. Result returns to callback previously set by 744 | `gpgs.set_callback` with `message_id == gpgs.MSG_GET_EVENTS`. Result is array of tables which contain 745 | following fields 746 | 747 | - `id` - event id 748 | 749 | - `formatted_value` - sum of all increments have been made to this event 750 | 751 | - `value` - the number of increments this user has made to this event 752 | 753 | - `description` - event's description 754 | 755 | - `image` - URI that can be used to load the event's image icon 756 | 757 | - `name` - event's name 758 | 759 | - `visible` - whether the event should be displayed to the user in any event related UIs 760 | 761 | 762 | #***************************************************************************************************** 763 | 764 | - name: RESOLUTION_POLICY_MANUAL 765 | type: number 766 | desc: Official [GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient.html#RESOLUTION_POLICY_MANUAL) for this constant 767 | 768 | - name: RESOLUTION_POLICY_LONGEST_PLAYTIME 769 | type: number 770 | desc: Official [GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient.html#RESOLUTION_POLICY_LONGEST_PLAYTIME) for this constant 771 | 772 | - name: RESOLUTION_POLICY_LAST_KNOWN_GOOD 773 | type: number 774 | desc: Official [GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient.html#RESOLUTION_POLICY_LAST_KNOWN_GOOD) for this constant 775 | 776 | - name: RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED 777 | type: number 778 | desc: Official [GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient.html#RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED) for this constant 779 | 780 | - name: RESOLUTION_POLICY_HIGHEST_PROGRESS 781 | type: number 782 | desc: Official [GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient.html#RESOLUTION_POLICY_HIGHEST_PROGRESS) for this constant 783 | 784 | - name: MSG_SIGN_IN 785 | type: number 786 | desc: The message type that GPGS sends when finishing the asynchronous operation 787 | after calling `gpgs.login()` 788 | 789 | - name: MSG_SILENT_SIGN_IN 790 | type: number 791 | desc: The message type that GPGS sends when finishing the asynchronous operation 792 | after calling `gpgs.silent_login()` 793 | 794 | - name: MSG_SHOW_SNAPSHOTS 795 | type: number 796 | desc: The message type that GPGS sends when finishing the asynchronous operation 797 | after calling `gpgs.snapshot_display_saves()` 798 | 799 | - name: MSG_LOAD_SNAPSHOT 800 | type: number 801 | desc: The message type that GPGS sends when finishing the asynchronous operation 802 | after calling `gpgs.snapshot_open()` 803 | 804 | - name: MSG_SAVE_SNAPSHOT 805 | type: number 806 | desc: The message type that GPGS sends when finishing the asynchronous operation 807 | after calling `gpgs.snapshot_commit_and_close()` 808 | 809 | - name: MSG_GET_SERVER_TOKEN 810 | type: number 811 | desc: The message type that GPGS sends when finishing the asynchronous operation 812 | of server token retrieval 813 | 814 | - name: STATUS_SUCCESS 815 | type: number 816 | desc: An operation success. 817 | 818 | - name: STATUS_FAILED 819 | type: number 820 | desc: An operation failed. Check the error field in the massage table. 821 | 822 | - name: STATUS_CREATE_NEW_SAVE 823 | type: number 824 | desc: A user wants to create new save as a result of `gpgs.snapshot_display_saves()` method. 825 | Turn off this button in `gpgs.snapshot_display_saves()` if you don't want to have this functionality. 826 | 827 | - name: STATUS_CONFLICT 828 | type: number 829 | desc: The result of the calling `gpgs.snapshot_open()` or 'gpgs.snapshot_resolve_conflict()' is a conflict. 830 | You need to make decision on how to solve this conflict using 'gpgs.snapshot_resolve_conflict()'. 831 | 832 | - name: SNAPSHOT_CURRENT 833 | type: number 834 | desc: The second parameter for 'gpgs.snapshot_resolve_conflict()' method, which means that you want to choose 835 | the current snapshot as a snapshot for conflict solving. 836 | 837 | - name: SNAPSHOT_CONFLICTING 838 | type: number 839 | desc: The second parameter for 'gpgs.snapshot_resolve_conflict()' method, which means that you want to choose 840 | the conflicting snapshot as a snapshot for conflict solving. 841 | 842 | - name: ERROR_STATUS_SNAPSHOT_NOT_FOUND 843 | type: number 844 | desc: This constant is used in `message.error_status` table when `MSG_LOAD_SNAPSHOT` is `STATUS_FAILED`. 845 | [Official GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/GamesStatusCodes.html#STATUS_SNAPSHOT_NOT_FOUND) for this constant 846 | 847 | - name: ERROR_STATUS_SNAPSHOT_CREATION_FAILED 848 | type: number 849 | desc: This constant is used in `message.error_status` table when `MSG_LOAD_SNAPSHOT` is `STATUS_FAILED`. 850 | [Official GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/GamesStatusCodes.html#STATUS_SNAPSHOT_CREATION_FAILED) for this constant 851 | 852 | - name: ERROR_STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE 853 | type: number 854 | desc: This constant is used in `message.error_status` table when `MSG_LOAD_SNAPSHOT` is `STATUS_FAILED`. 855 | [Official GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/GamesStatusCodes.html#STATUS_SNAPSHOT_CONTENTS_UNAVAILABLE) for this constant 856 | 857 | - name: ERROR_STATUS_SNAPSHOT_COMMIT_FAILED 858 | type: number 859 | desc: This constant is used in `message.error_status` table when `MSG_LOAD_SNAPSHOT` is `STATUS_FAILED`. 860 | [Official GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/GamesStatusCodes.html#STATUS_SNAPSHOT_COMMIT_FAILED) for this constant 861 | 862 | - name: ERROR_STATUS_SNAPSHOT_FOLDER_UNAVAILABLE 863 | type: number 864 | desc: This constant is used in `message.error_status` table when `MSG_LOAD_SNAPSHOT` is `STATUS_FAILED`. 865 | [Official GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/GamesStatusCodes.html#STATUS_SNAPSHOT_FOLDER_UNAVAILABLE) for this constant 866 | 867 | - name: ERROR_STATUS_SNAPSHOT_CONFLICT_MISSING 868 | type: number 869 | desc: This constant is used in `message.error_status` table when `MSG_LOAD_SNAPSHOT` is `STATUS_FAILED`. 870 | [Official GPGS documentation](https://developers.google.com/android/reference/com/google/android/gms/games/GamesStatusCodes.html#STATUS_SNAPSHOT_CONFLICT_MISSING) for this constant 871 | -------------------------------------------------------------------------------- /gpgs/src/java/com/defold/gpgs/GpgsJNI.java: -------------------------------------------------------------------------------- 1 | package com.defold.gpgs; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.util.Log; 9 | 10 | import com.google.android.gms.games.PlayGames; 11 | import com.google.android.gms.games.GamesSignInClient; 12 | import com.google.android.gms.common.api.ApiException; 13 | import com.google.android.gms.common.ConnectionResult; 14 | import com.google.android.gms.common.GoogleApiAvailability; 15 | import com.google.android.gms.games.Player; 16 | import com.google.android.gms.games.PlayersClient; 17 | 18 | import com.google.android.gms.tasks.OnCompleteListener; 19 | import com.google.android.gms.tasks.OnFailureListener; 20 | import com.google.android.gms.tasks.OnSuccessListener; 21 | import com.google.android.gms.tasks.Task; 22 | 23 | import com.google.android.gms.games.SnapshotsClient; 24 | import com.google.android.gms.games.snapshot.SnapshotMetadata; 25 | import com.google.android.gms.games.snapshot.SnapshotMetadataChange; 26 | import com.google.android.gms.games.snapshot.Snapshot; 27 | 28 | import com.google.android.gms.games.LeaderboardsClient; 29 | import com.google.android.gms.games.leaderboard.LeaderboardScore; 30 | import com.google.android.gms.games.leaderboard.LeaderboardScoreBuffer; 31 | 32 | import com.google.android.gms.games.AchievementsClient; 33 | import com.google.android.gms.games.achievement.Achievement; 34 | import com.google.android.gms.games.achievement.AchievementBuffer; 35 | import com.google.android.gms.games.GamesClientStatusCodes; 36 | 37 | import com.google.android.gms.games.EventsClient; 38 | import com.google.android.gms.games.event.Event; 39 | import com.google.android.gms.games.event.EventBuffer; 40 | 41 | import java.io.IOException; 42 | 43 | import org.json.JSONArray; 44 | import org.json.JSONObject; 45 | import org.json.JSONException; 46 | 47 | public class GpgsJNI { 48 | 49 | private static final String TAG = "GpgsJNI"; 50 | 51 | //Internal constants: 52 | 53 | private static final int RC_UNUSED = 5001; 54 | // Request code for listing saved games 55 | private static final int RC_LIST_SAVED_GAMES = 9002; 56 | // Request code for listing achievements 57 | private static final int RC_ACHIEVEMENT_UI = 9003; 58 | private static final int RC_SHOW_LEADERBOARD = 9004; 59 | private static final int RC_SHOW_ALL_LEADERBOARDS = 9005; 60 | 61 | // duplicate of enums from gpgs_extension.h: 62 | private static final int MSG_SIGN_IN = 1; 63 | private static final int MSG_SILENT_SIGN_IN = 2; 64 | private static final int MSG_SHOW_SNAPSHOTS = 4; 65 | private static final int MSG_LOAD_SNAPSHOT = 5; 66 | private static final int MSG_SAVE_SNAPSHOT = 6; 67 | private static final int MSG_ACHIEVEMENTS = 7; 68 | private static final int MSG_GET_TOP_SCORES = 8; 69 | private static final int MSG_GET_PLAYER_CENTERED_SCORES = 9; 70 | private static final int MSG_GET_PLAYER_SCORE = 10; 71 | private static final int MSG_GET_EVENTS = 11; 72 | private static final int MSG_GET_SERVER_TOKEN = 12; 73 | 74 | // duplicate of enums from gpgs_extension.h: 75 | private static final int STATUS_SUCCESS = 1; 76 | private static final int STATUS_FAILED = 2; 77 | private static final int STATUS_CREATE_NEW_SAVE = 3; 78 | private static final int STATUS_CONFLICT = 4; 79 | 80 | // duplicate of enums from gpgs_extension.h: 81 | private static final int SNAPSHOT_CURRENT = 1; 82 | private static final int SNAPSHOT_CONFLICTING = 2; 83 | 84 | //-------------------------------------------------- 85 | public static native void gpgsAddToQueue(int msg, String json); 86 | 87 | //-------------------------------------------------- 88 | private Activity activity; 89 | private boolean isDiskActive; 90 | private boolean isRequestAuthCode; 91 | private boolean isSupported; 92 | private String mWebClientToken = null; // need for server auth token request 93 | private String mServerAuthCode = null; // can be non-null if isRequestAuthCode == true 94 | 95 | //-------------------------------------------------- 96 | // Authorization 97 | 98 | private GamesSignInClient mSignInClient; 99 | private Player mPlayer; 100 | 101 | 102 | private OnFailureListener newOnFailureListener(final int messageId, final String message) { 103 | return e -> sendFailedMessage(messageId, message, e); 104 | } 105 | 106 | private OnSuccessListener newOnSuccessListenerForIntent(final int requestCode) { 107 | return intent -> activity.startActivityForResult(intent, requestCode); 108 | } 109 | 110 | private void sendSimpleMessage(int msg, String key_1, int value_1) { 111 | String message = null; 112 | try { 113 | JSONObject obj = new JSONObject(); 114 | obj.put(key_1, value_1); 115 | message = obj.toString(); 116 | } catch (JSONException e) { 117 | message = "{ \"error\": \"Error while converting simple message to JSON: " + e.getMessage() + "\" }"; 118 | } 119 | gpgsAddToQueue(msg, message); 120 | } 121 | 122 | private void sendSimpleMessage(int msg, String key_1, int value_1, String key_2, String value_2) { 123 | String message = null; 124 | try { 125 | JSONObject obj = new JSONObject(); 126 | obj.put(key_1, value_1); 127 | obj.put(key_2, value_2); 128 | message = obj.toString(); 129 | } catch (JSONException e) { 130 | message = "{ \"error\": \"Error while converting simple message to JSON: " + e.getMessage() + "\" }"; 131 | } 132 | gpgsAddToQueue(msg, message); 133 | } 134 | 135 | private void sendSimpleMessage(int msg, String key_1, int value_1, String key_2, int value_2, String key_3, String value_3) { 136 | String message = null; 137 | try { 138 | JSONObject obj = new JSONObject(); 139 | obj.put(key_1, value_1); 140 | obj.put(key_2, value_2); 141 | obj.put(key_3, value_3); 142 | message = obj.toString(); 143 | } catch (JSONException e) { 144 | message = "{ \"error\": \"Error while converting simple message to JSON: " + e.getMessage() + "\" }"; 145 | } 146 | gpgsAddToQueue(msg, message); 147 | } 148 | 149 | private void sendFailedMessage(int msg, String error_text, Exception e) { 150 | if(e != null) { 151 | if (e instanceof ApiException) { 152 | ApiException apiException = (ApiException) e; 153 | Integer errorStatusCode = apiException.getStatusCode(); 154 | error_text += ": " + GamesClientStatusCodes.getStatusCodeString(errorStatusCode) +" ("+errorStatusCode.toString()+")"; 155 | 156 | sendSimpleMessage(msg, 157 | "status", STATUS_FAILED, 158 | "error_status", errorStatusCode, 159 | "error", error_text); 160 | } else { 161 | error_text += ": " + e.toString(); 162 | 163 | sendSimpleMessage(msg, 164 | "status", STATUS_FAILED, 165 | "error", error_text); 166 | } 167 | } else { 168 | 169 | sendSimpleMessage(msg, 170 | "status", STATUS_FAILED, 171 | "error", error_text); 172 | } 173 | } 174 | 175 | public GpgsJNI(Activity activity, boolean isDiskActive, boolean isRequestAuthCode, String oauthToken) { 176 | this.activity = activity; 177 | this.isDiskActive = isDiskActive; 178 | this.isRequestAuthCode = isRequestAuthCode; 179 | if (isRequestAuthCode) { 180 | this.mWebClientToken = oauthToken; 181 | } 182 | 183 | this.isSupported = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS; 184 | 185 | mSignInClient = PlayGames.getGamesSignInClient(activity); 186 | if (isDiskActive) { 187 | mPlayerSnapshotsClient = PlayGames.getSnapshotsClient(activity); 188 | } 189 | mLeaderboardsClient = PlayGames.getLeaderboardsClient(activity); 190 | mAchievementsClient = PlayGames.getAchievementsClient(activity); 191 | mEventsClient = PlayGames.getEventsClient(activity); 192 | } 193 | 194 | private void onConnected(final int msg) { 195 | // until we get player information 196 | mPlayer = null; 197 | onAccountChangedDisk(); 198 | PlayersClient playersClient = PlayGames.getPlayersClient(activity); 199 | if (this.isRequestAuthCode) { 200 | mSignInClient.requestServerSideAccess(mWebClientToken, false) 201 | .addOnCompleteListener(task -> { 202 | if (task.isSuccessful()) { 203 | mServerAuthCode = task.getResult(); 204 | sendSimpleMessage(MSG_GET_SERVER_TOKEN, "status", STATUS_SUCCESS, "token", mServerAuthCode); 205 | } else { 206 | sendFailedMessage(MSG_GET_SERVER_TOKEN, "Can't get server auth token", task.getException()); 207 | } 208 | }); 209 | } 210 | playersClient.getCurrentPlayer() 211 | .addOnCompleteListener(task -> { 212 | if (task.isSuccessful()) { 213 | mPlayer = task.getResult(); 214 | sendSimpleMessage(msg, "status", STATUS_SUCCESS); 215 | } else { 216 | sendFailedMessage(MSG_SIGN_IN, "There was a problem getting the player id!", task.getException()); 217 | } 218 | }); 219 | } 220 | 221 | public void activityResult(int requestCode, int resultCode, Intent intent) { 222 | if (requestCode == RC_LIST_SAVED_GAMES) { 223 | if (intent != null) { 224 | if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA)) { 225 | SnapshotMetadata snapshotMetadata = 226 | intent.getParcelableExtra(SnapshotsClient.EXTRA_SNAPSHOT_METADATA); 227 | sendSnapshotMetadataMessage(MSG_SHOW_SNAPSHOTS, snapshotMetadata); 228 | } else if (intent.hasExtra(SnapshotsClient.EXTRA_SNAPSHOT_NEW)) { 229 | sendSimpleMessage(MSG_SHOW_SNAPSHOTS, "status", STATUS_CREATE_NEW_SAVE); 230 | } 231 | } else { 232 | // Error message 233 | } 234 | } 235 | } 236 | 237 | public void silentLogin() { 238 | mSignInClient.isAuthenticated().addOnCompleteListener(isAuthenticatedTask -> { 239 | boolean isAuthenticated = 240 | (isAuthenticatedTask.isSuccessful() && 241 | isAuthenticatedTask.getResult().isAuthenticated()); 242 | if (isAuthenticated) { 243 | onConnected(MSG_SILENT_SIGN_IN); 244 | } else { 245 | sendFailedMessage(MSG_SILENT_SIGN_IN, "Silent sign-in failed", isAuthenticatedTask.getException()); 246 | } 247 | }); 248 | } 249 | 250 | public void login() { 251 | mSignInClient.signIn() 252 | .addOnCompleteListener(task -> { 253 | if (task.isSuccessful() && task.getResult().isAuthenticated()) { 254 | onConnected(MSG_SIGN_IN); 255 | } else { 256 | sendFailedMessage(MSG_SIGN_IN, "Sign-in failed", task.getException()); 257 | } 258 | }); 259 | } 260 | 261 | public String getDisplayName() { 262 | return isLoggedIn() ? mPlayer.getDisplayName() : null; 263 | } 264 | 265 | public String getId() { 266 | return isLoggedIn() ? mPlayer.getPlayerId() : null; 267 | } 268 | 269 | public String getServerAuthCode() { 270 | return mServerAuthCode; 271 | } 272 | 273 | public boolean isLoggedIn() { 274 | return mPlayer != null; 275 | } 276 | 277 | public boolean isSupported() { 278 | return isSupported; 279 | } 280 | 281 | //-------------------------------------------------- 282 | // GoogleDrive (Snapshots) 283 | 284 | // Client used to interact with Google Snapshots. 285 | private SnapshotsClient mPlayerSnapshotsClient = null; 286 | private Snapshot mPlayerSnapshot = null; 287 | private byte[] currentPlayerSave = null; 288 | 289 | private Snapshot mConflictingSnapshot = null; 290 | private byte[] conflictingSave = null; 291 | 292 | // values from the official docs: https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient.html#getMaxCoverImageSize() 293 | private int maxCoverImageSize = 819200; 294 | // https://developers.google.com/android/reference/com/google/android/gms/games/SnapshotsClient.html#getMaxDataSize() 295 | private int maxDataSize = 3145728; 296 | 297 | private void onAccountChangedDisk() { 298 | if (this.isDiskActive) { 299 | mPlayerSnapshotsClient.getMaxCoverImageSize() 300 | .addOnCompleteListener(task -> { 301 | if (task.isSuccessful()) { 302 | maxCoverImageSize = task.getResult(); 303 | } 304 | }); 305 | 306 | mPlayerSnapshotsClient.getMaxDataSize() 307 | .addOnCompleteListener(task -> { 308 | if (task.isSuccessful()) { 309 | maxDataSize = task.getResult(); 310 | } 311 | }); 312 | } 313 | } 314 | 315 | private void addSnapshotMetadtaToJson(JSONObject json, String name, SnapshotMetadata metadata) throws JSONException { 316 | JSONObject obj = json; 317 | if (name != null) { 318 | obj = new JSONObject(); 319 | json.put(name, obj); 320 | } 321 | obj.put("coverImageAspectRatio", metadata.getCoverImageAspectRatio()); 322 | obj.put("coverImageUri", metadata.getCoverImageUri()); 323 | obj.put("description", metadata.getDescription()); 324 | obj.put("deviceName", metadata.getDeviceName()); 325 | obj.put("lastModifiedTimestamp", metadata.getLastModifiedTimestamp()); 326 | obj.put("playedTime", metadata.getPlayedTime()); 327 | obj.put("progressValue", metadata.getProgressValue()); 328 | obj.put("snapshotId", metadata.getSnapshotId()); 329 | obj.put("uniqueName", metadata.getUniqueName()); 330 | } 331 | 332 | private void sendSnapshotMetadataMessage(int msg, SnapshotMetadata metadata) { 333 | String message = null; 334 | try { 335 | JSONObject obj = new JSONObject(); 336 | obj.put("status", STATUS_SUCCESS); 337 | addSnapshotMetadtaToJson(obj, "metadata", metadata); 338 | message = obj.toString(); 339 | } catch (JSONException e) { 340 | message = "{ \"error\": \"Error while converting a metadata message to JSON: " + e.getMessage() + "\", \"status\": " + STATUS_FAILED + " }"; 341 | } 342 | gpgsAddToQueue(msg, message); 343 | } 344 | 345 | private void sendConflictMessage(int msg, SnapshotMetadata metadata, SnapshotMetadata conflictMetadata, String conflictId) { 346 | String message = null; 347 | try { 348 | JSONObject obj = new JSONObject(); 349 | obj.put("status", STATUS_CONFLICT); 350 | obj.put("conflictId", conflictId); 351 | addSnapshotMetadtaToJson(obj, "metadata", metadata); 352 | addSnapshotMetadtaToJson(obj, "conflictMetadata", conflictMetadata); 353 | message = obj.toString(); 354 | } catch (JSONException e) { 355 | message = "{ \"error\": \"Error while converting a metadata or a conflict metadata message to JSON: " + e.getMessage() + "\", \"status\": " + STATUS_FAILED + " }"; 356 | } 357 | gpgsAddToQueue(msg, message); 358 | } 359 | 360 | private OnCompleteListener> getOnLoadCompleteListener() { 361 | return task -> { 362 | if (!task.isSuccessful()) { 363 | sendFailedMessage(MSG_LOAD_SNAPSHOT, "Error while opening Snapshot", task.getException()); 364 | } else { 365 | SnapshotsClient.DataOrConflict result = task.getResult(); 366 | if (!result.isConflict()) { 367 | mPlayerSnapshot = result.getData(); 368 | try { 369 | currentPlayerSave = mPlayerSnapshot.getSnapshotContents().readFully(); 370 | sendSnapshotMetadataMessage(MSG_LOAD_SNAPSHOT, mPlayerSnapshot.getMetadata()); 371 | } catch (IOException e) { 372 | sendFailedMessage(MSG_LOAD_SNAPSHOT, "Error while reading Snapshot", e); 373 | } catch (NullPointerException e) { 374 | sendFailedMessage(MSG_LOAD_SNAPSHOT, "Snapshot is null", e); 375 | } 376 | } else { 377 | SnapshotsClient.SnapshotConflict conflict = result.getConflict(); 378 | mPlayerSnapshot = conflict.getSnapshot(); 379 | mConflictingSnapshot = conflict.getConflictingSnapshot(); 380 | try { 381 | currentPlayerSave = mPlayerSnapshot.getSnapshotContents().readFully(); 382 | conflictingSave = mConflictingSnapshot.getSnapshotContents().readFully(); 383 | sendConflictMessage(MSG_LOAD_SNAPSHOT, mPlayerSnapshot.getMetadata(), 384 | mConflictingSnapshot.getMetadata(), conflict.getConflictId()); 385 | } catch (IOException e) { 386 | sendFailedMessage(MSG_LOAD_SNAPSHOT, "Error while reading Snapshot or Conflict", e); 387 | } 388 | } 389 | } 390 | }; 391 | } 392 | 393 | public void showSavedGamesUI(String popupTitle, boolean allowAddButton, 394 | boolean allowDelete, int maxNumberOfSavedGamesToShow) { 395 | 396 | if (mPlayerSnapshotsClient == null) { 397 | sendSimpleMessage(MSG_SHOW_SNAPSHOTS, 398 | "status", STATUS_FAILED, 399 | "error", 400 | "Can't start activity for showing saved games. You aren't logged in."); 401 | return; 402 | } 403 | 404 | Task intentTask = mPlayerSnapshotsClient.getSelectSnapshotIntent( 405 | popupTitle, allowAddButton, allowDelete, maxNumberOfSavedGamesToShow); 406 | 407 | intentTask 408 | .addOnSuccessListener(newOnSuccessListenerForIntent(RC_LIST_SAVED_GAMES)) 409 | .addOnFailureListener(newOnFailureListener(MSG_SHOW_SNAPSHOTS, "Can't start activity for showing saved games")); 410 | } 411 | 412 | public void loadSnapshot(String saveName, boolean createIfNotFound, int conflictPolicy) { 413 | int conflictResolutionPolicy = SnapshotsClient.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED; 414 | 415 | if (mPlayerSnapshotsClient == null) { 416 | sendSimpleMessage(MSG_LOAD_SNAPSHOT, 417 | "status", STATUS_FAILED, 418 | "error", 419 | "Failed to open snapshot. You aren't logged in."); 420 | return; 421 | } 422 | 423 | mPlayerSnapshotsClient.open(saveName, createIfNotFound, conflictPolicy) 424 | .addOnCompleteListener(getOnLoadCompleteListener()); 425 | } 426 | 427 | public void commitAndCloseSnapshot(long playedTime, long progressValue, String description, byte[] coverImage) { 428 | SnapshotMetadataChange.Builder builder = new SnapshotMetadataChange.Builder(); 429 | if (playedTime != -1) { 430 | builder.setPlayedTimeMillis(playedTime); 431 | } 432 | if (progressValue != -1) { 433 | builder.setProgressValue(progressValue); 434 | } 435 | if (description != null) { 436 | builder.setDescription(description); 437 | } 438 | if (coverImage != null) { 439 | Bitmap bitmap = BitmapFactory.decodeByteArray(coverImage, 0, coverImage.length); 440 | builder.setCoverImage(bitmap); 441 | } 442 | 443 | if (mPlayerSnapshot == null) { 444 | sendSimpleMessage(MSG_SAVE_SNAPSHOT, 445 | "status", STATUS_FAILED, 446 | "error", 447 | "A snapshot wasn't opened."); 448 | return; 449 | } 450 | 451 | mPlayerSnapshotsClient.commitAndClose(mPlayerSnapshot, builder.build()) 452 | .addOnCompleteListener(task -> { 453 | if (task.isSuccessful()) { 454 | mPlayerSnapshot = null; 455 | currentPlayerSave = null; 456 | sendSimpleMessage(MSG_SAVE_SNAPSHOT, 457 | "status", STATUS_SUCCESS); 458 | } else { 459 | sendFailedMessage(MSG_SAVE_SNAPSHOT, "Failed to save a snapshot", task.getException()); 460 | } 461 | }); 462 | } 463 | 464 | public void resolveConflict(String conflictId, int metadataId) { 465 | Snapshot snapshot = mPlayerSnapshot; 466 | if (metadataId == SNAPSHOT_CONFLICTING) { 467 | snapshot = mConflictingSnapshot; 468 | } 469 | if (mPlayerSnapshot == null) { 470 | sendSimpleMessage(SNAPSHOT_CONFLICTING, 471 | "status", STATUS_FAILED, 472 | "error", 473 | "Failed to resolve conflict. You aren't logged in."); 474 | return; 475 | } 476 | mPlayerSnapshotsClient.resolveConflict(conflictId, snapshot) 477 | .addOnCompleteListener(getOnLoadCompleteListener()); 478 | } 479 | 480 | public byte[] getSave() { 481 | return currentPlayerSave; 482 | } 483 | 484 | public byte[] getConflictingSave() { 485 | return conflictingSave; 486 | } 487 | 488 | public String setSave(byte[] bytes) { 489 | if (mPlayerSnapshot != null) { 490 | mPlayerSnapshot.getSnapshotContents().writeBytes(bytes); 491 | currentPlayerSave = bytes; 492 | return null; 493 | } 494 | return "Can't write data to the snapshot. The snapshot wasn't open."; 495 | } 496 | 497 | public boolean isSnapshotOpened() { 498 | if (mPlayerSnapshot == null || mPlayerSnapshot.getSnapshotContents() == null) { 499 | return false; 500 | } 501 | return !mPlayerSnapshot.getSnapshotContents().isClosed(); 502 | } 503 | 504 | public int getMaxCoverImageSize() { 505 | return maxCoverImageSize; 506 | } 507 | 508 | public int getMaxDataSize() { 509 | return maxDataSize; 510 | } 511 | 512 | 513 | //-------------------------------------------------- 514 | // Leaderboards 515 | 516 | // Client used to interact with Leaderboards. 517 | private LeaderboardsClient mLeaderboardsClient = null; 518 | 519 | public void submitScore(String leaderboardId, double score) { 520 | mLeaderboardsClient.submitScore(leaderboardId, (long)score); 521 | } 522 | 523 | private static JSONObject scoreToJSON(LeaderboardScore score, String leaderboardId) throws JSONException { 524 | JSONObject json = new JSONObject(); 525 | json.put("leaderboard_id", leaderboardId); 526 | json.put("display_rank", score.getDisplayRank()); 527 | json.put("display_score", score.getDisplayScore()); 528 | json.put("rank", score.getRank()); 529 | json.put("score", score.getRawScore()); 530 | json.put("tag", score.getScoreTag()); 531 | json.put("timestamp", score.getTimestampMillis()); 532 | json.put("score_holder_name", score.getScoreHolderDisplayName()); 533 | json.put("score_holder_icon", score.getScoreHolderIconImageUri()); 534 | json.put("score_holder_image", score.getScoreHolderHiResImageUri()); 535 | return json; 536 | } 537 | 538 | public void loadTopScores(final String leaderboardId, int span, int collection, int maxResults) { 539 | mLeaderboardsClient.loadTopScores(leaderboardId, span, collection, maxResults) 540 | .addOnCompleteListener(task -> { 541 | if (task.isSuccessful()) { 542 | LeaderboardsClient.LeaderboardScores scores = task.getResult().get(); 543 | LeaderboardScoreBuffer buffer = scores.getScores(); 544 | String message = null; 545 | try { 546 | JSONArray result = new JSONArray(); 547 | for (LeaderboardScore score : buffer) { 548 | JSONObject json = scoreToJSON(score, leaderboardId); 549 | result.put(json.toString()); 550 | } 551 | message = result.toString(); 552 | } catch (JSONException e) { 553 | message = "{ \"error\": \"Error while converting leaderboard score to JSON: " + e.getMessage() + "\", \"status\": " + STATUS_FAILED + " }"; 554 | } 555 | buffer.release(); 556 | gpgsAddToQueue(MSG_GET_TOP_SCORES, message); 557 | } else { 558 | sendFailedMessage(MSG_GET_TOP_SCORES, "Unable to get top scores", task.getException()); 559 | } 560 | }); 561 | } 562 | 563 | public void loadPlayerCenteredScores(final String leaderboardId, int span, int collection, int maxResults, boolean forceReload) { 564 | mLeaderboardsClient.loadPlayerCenteredScores(leaderboardId, span, collection, maxResults, forceReload) 565 | .addOnCompleteListener(task -> { 566 | if (task.isSuccessful()) { 567 | LeaderboardsClient.LeaderboardScores scores = task.getResult().get(); 568 | LeaderboardScoreBuffer buffer = scores.getScores(); 569 | String message = null; 570 | try { 571 | JSONArray result = new JSONArray(); 572 | for (LeaderboardScore score : buffer) { 573 | JSONObject json = scoreToJSON(score, leaderboardId); 574 | result.put(json.toString()); 575 | } 576 | message = result.toString(); 577 | } catch (JSONException e) { 578 | message = "{ \"error\": \"Error while converting leaderboard score to JSON: " + e.getMessage() + "\", \"status\": " + STATUS_FAILED + " }"; 579 | } 580 | buffer.release(); 581 | gpgsAddToQueue(MSG_GET_PLAYER_CENTERED_SCORES, message); 582 | } else { 583 | Exception exception = task.getException(); 584 | sendFailedMessage(MSG_GET_PLAYER_CENTERED_SCORES, "Unable to get player centered scores", exception); 585 | } 586 | }); 587 | } 588 | 589 | public void loadCurrentPlayerLeaderboardScore(final String leaderboardId, int span, int collection) { 590 | mLeaderboardsClient.loadCurrentPlayerLeaderboardScore(leaderboardId, span, collection) 591 | .addOnCompleteListener(task -> { 592 | if (task.isSuccessful()) { 593 | LeaderboardScore score = task.getResult().get(); 594 | String message = null; 595 | if (score == null) { 596 | message = "{ \"error\": \"Player has no score on leaderboard\", \"status\": " + STATUS_FAILED + " }"; 597 | 598 | } 599 | else { 600 | try { 601 | JSONObject result = scoreToJSON(score, leaderboardId); 602 | message = result.toString(); 603 | } catch (JSONException e) { 604 | message = "{ \"error\": \"Error while converting leaderboard score to JSON: " + e.getMessage() + "\", \"status\": " + STATUS_FAILED + " }"; 605 | } 606 | } 607 | gpgsAddToQueue(MSG_GET_PLAYER_SCORE, message); 608 | } else { 609 | Exception exception = task.getException(); 610 | sendFailedMessage(MSG_GET_PLAYER_SCORE, "Unable to get player scores", exception); 611 | } 612 | }); 613 | } 614 | 615 | public void showLeaderboard(String leaderboardId, int span, int collection) { 616 | mLeaderboardsClient.getLeaderboardIntent(leaderboardId, span, collection) 617 | .addOnSuccessListener(newOnSuccessListenerForIntent(RC_SHOW_LEADERBOARD)); 618 | } 619 | 620 | public void showAllLeaderboards() { 621 | mLeaderboardsClient.getAllLeaderboardsIntent() 622 | .addOnSuccessListener(newOnSuccessListenerForIntent(RC_SHOW_ALL_LEADERBOARDS)); 623 | } 624 | 625 | //-------------------------------------------------- 626 | // Achievements 627 | 628 | // Client used to interact with Achievements. 629 | private AchievementsClient mAchievementsClient = null; 630 | 631 | public void revealAchievement(String achievementId) { 632 | mAchievementsClient.reveal(achievementId); 633 | } 634 | 635 | public void unlockAchievement(String achievementId) { 636 | mAchievementsClient.unlock(achievementId); 637 | } 638 | 639 | public void incrementAchievement(String achievementId, int steps) { 640 | mAchievementsClient.increment(achievementId, steps); 641 | } 642 | 643 | public void setAchievement(String achievementId, int steps) { 644 | mAchievementsClient.setSteps(achievementId, steps); 645 | } 646 | 647 | public void showAchievements() { 648 | mAchievementsClient.getAchievementsIntent() 649 | .addOnSuccessListener(newOnSuccessListenerForIntent(RC_UNUSED)); 650 | } 651 | 652 | public void getAchievements() { 653 | mAchievementsClient 654 | .load(false) 655 | .addOnCompleteListener(task -> { 656 | if (task.isSuccessful()) { 657 | AchievementBuffer buffer = task.getResult().get(); 658 | String message = null; 659 | try { 660 | JSONArray result = new JSONArray(); 661 | for (Achievement a : buffer) { 662 | JSONObject json = new JSONObject(); 663 | json.put("id", a.getAchievementId()); 664 | json.put("name", a.getName()); 665 | json.put("description", a.getDescription()); 666 | json.put("xp", a.getXpValue()); 667 | if (a.getType() == Achievement.TYPE_INCREMENTAL) { 668 | json.put("steps", a.getCurrentSteps()); 669 | json.put("total_steps", a.getTotalSteps()); 670 | } 671 | if (a.getState() == Achievement.STATE_UNLOCKED) { 672 | json.put("unlocked", true); 673 | } 674 | else if (a.getState() == Achievement.STATE_HIDDEN) { 675 | json.put("hidden", true); 676 | } 677 | else if (a.getState() == Achievement.STATE_REVEALED) { 678 | json.put("revealed", true); 679 | } 680 | result.put(json.toString()); 681 | } 682 | message = result.toString(); 683 | buffer.release(); 684 | } catch (JSONException e) { 685 | message = "{ \"error\": \"Error while converting achievements to JSON: " + e.getMessage() + "\", \"status\": " + STATUS_FAILED + " }"; 686 | } 687 | gpgsAddToQueue(MSG_ACHIEVEMENTS, message); 688 | } else { 689 | Exception exception = task.getException(); 690 | sendFailedMessage(MSG_ACHIEVEMENTS, "Unable to get achievements", exception); 691 | } 692 | }); 693 | } 694 | 695 | private EventsClient mEventsClient = null; 696 | 697 | public void incrementEvent(String eventId, int amount) { 698 | mEventsClient.increment(eventId, amount); 699 | } 700 | 701 | public void loadEvents() { 702 | mEventsClient 703 | .load(false) 704 | .addOnCompleteListener(task -> { 705 | if (task.isSuccessful()) { 706 | EventBuffer buffer = task.getResult().get(); 707 | String message = null; 708 | try { 709 | JSONArray result = new JSONArray(); 710 | for (Event e : buffer) { 711 | JSONObject json = new JSONObject(); 712 | json.put("id", e.getEventId()); 713 | json.put("formatted_value", e.getFormattedValue()); 714 | json.put("value", e.getValue()); 715 | json.put("description", e.getDescription()); 716 | json.put("image", e.getIconImageUri()); 717 | json.put("name", e.getName()); 718 | json.put("visible", e.isVisible()); 719 | result.put(json.toString()); 720 | } 721 | message = result.toString(); 722 | buffer.release(); 723 | } catch (JSONException e) { 724 | message = "{ \"error\": \"Error while converting event to JSON: " + e.getMessage() + "\", \"status\": " + STATUS_FAILED + " }"; 725 | } 726 | gpgsAddToQueue(MSG_GET_EVENTS, message); 727 | } else { 728 | Exception exception = task.getException(); 729 | sendFailedMessage(MSG_GET_EVENTS, "Unable to get events", exception); 730 | } 731 | }); 732 | } 733 | 734 | } 735 | --------------------------------------------------------------------------------