android and ios achievements.

This commit is contained in:
Bryce Covert
2018-01-04 21:54:21 -08:00
parent c4e4a14be3
commit e95d6c4be1
24 changed files with 379 additions and 24 deletions

View File

@@ -15,6 +15,8 @@
android:hardwareAccelerated="true"
android:largeHeap="true"
android:label="Tick's Tales">
<meta-data android:name="com.google.android.gms.games.APP_ID"
android:value="@string/app_id"/>
<activity android:name="advent.core.SplashActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:screenOrientation="landscape"

View File

@@ -14,34 +14,42 @@
[com.android.billingclient/billing "dp-1" :extension "aar"]
[org.clojure/tools.logging "0.3.1"]
[com.google.android.gms/play-services-games "11.6.2" :extension "aar" :exclusions [com.android.support/support-annotations]]
[com.google.android.gms/play-services-auth "11.6.2" :extension "aar" :exclusions [com.android.support/support-annotations]]
#_[com.google.android.gms/play-services "11.6.2" :extension "aar" :exclusions [com.android.support/support-annotations]]
[org.clojure/tools.logging "0.3.1" :exclusions [org.clojure/clojure]]
[org.clojure-android/clojure "1.7.0-r4"]
[org.im4java/im4java "1.4.0"]
[org.clojure/tools.nrepl "0.2.7"]
[play-clj "0.4.6-BRYCE"]
[play-clj "0.4.6-BRYCE" :exclusions [org.clojure/clojure]]
[org.clojure/data.priority-map "0.0.5"]
[org.clojure/core.async "0.2.371"]]
:plugins [[lein-droid "0.4.6"]]
:repositories [["jCenter" "https://jcenter.bintray.com/"]]
[org.clojure/core.async "0.2.371" :exclusions [org.clojure/clojure]]]
:plugins [[lein-droid "0.4.6" :exclusions [org.clojure/clojure] ]]
:repositories [["jCenter" "https://jcenter.bintray.com/"]
["google" "https://maven.google.com"]]
:profiles {:dev {:dependencies [[android/tools.nrepl "0.2.0-bigstack"]
[compliment "0.1.3"]]
[compliment "0.1.3"]
[org.clojure/tools.nrepl "0.2.7" :exclusions [org.clojure/clojure]]]
:jvm-opts ["-Dplatform=android"]
:android {:aot :all-with-unused
:rename-manifest-package "tickstales.core.debug"
:manifest-options {:app-name "ticks tales (debug)"}
:aot-exclude-ns ["clojure.core.memoize" "core.async"]}}
:release {:android
:release {
:jvm-opts ["-Dplatform=android"]
:android
{;; Specify the path to your private
;; keystore and the the alias of the
;; key you want to sign APKs with.
;; :keystore-path "ticks-talkes-release.jks"
;; :key-alias "ticks-tales-release"
:jvm-opts ["-Dplatform=android"]
:build-type :release
:aot :all-with-unused
:aot-exclude-ns [cljs.core.async.macros cljs.core.impl-ioc-macros cljs.core.impl.ioc_macros]}}}

View File

@@ -2,5 +2,6 @@
<resources>
<string name="app_name">advent</string>
<string name="app_id">891208148801</string>
</resources>

View File

@@ -0,0 +1,88 @@
package advent.core;
import clojure.lang.RT;
import clojure.lang.Symbol;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.backends.android.AndroidApplication;
import android.support.annotation.NonNull;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.assets.AssetManager;
import com.google.android.gms.games.*;
import com.google.android.gms.auth.api.signin.*;
import android.app.Activity;
import android.content.Intent;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
public class GooglePlay {
static GoogleSignInAccount mAccount;
public void signIn(Activity act) {
GoogleSignInClient signInClient = GoogleSignIn.getClient(act, GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
Intent intent = signInClient.getSignInIntent();
act.startActivityForResult(intent, 14562);
}
public void signInSilently(Activity act) {
GoogleSignInClient signInClient = GoogleSignIn.getClient(act, GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN);
System.out.println("trying silent sign in");
signInClient.silentSignIn().addOnCompleteListener(act,
new OnCompleteListener<GoogleSignInAccount>() {
@Override
public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
if (task.isSuccessful()) {
System.out.println("silent sign in succeeded.");
signedIn(task.getResult());
} else {
}
}
});
}
public static void signedIn(GoogleSignInAccount acct) {
mAccount = acct;
}
public void showAchievements(final Activity act) {
if (mAccount != null) {
com.google.android.gms.games.Games.getAchievementsClient(act, mAccount).getAchievementsIntent()
.addOnSuccessListener(new OnSuccessListener<Intent>() {
@Override
public void onSuccess(Intent intent) {
System.out.println("SUCCESS");
act.startActivityForResult(intent, 0);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
System.out.println("FAIL");
System.out.println(e.toString());
}
});
} else {
signIn(act);
}
}
public void setAchievement(Activity act, String a) {
System.out.println("TRYING TO UNLOCK");
System.out.println(a);
if (mAccount != null) {
System.out.println(mAccount.toString());
com.google.android.gms.games.Games.getAchievementsClient(act, mAccount).unlock(a);
}
}
}

View File

@@ -16,7 +16,16 @@ import com.android.billingclient.api.BillingClient.SkuType;
import com.android.billingclient.api.SkuDetails.SkuDetailsResult;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingFlowParams.Builder;
import android.content.Intent;
import com.google.android.gms.common.api.ApiException;
import android.content.pm.*;
import com.google.android.gms.games.*;
import com.google.android.gms.auth.api.signin.*;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import android.app.AlertDialog;
public class MainActivity extends AndroidApplication {
public boolean triggerPurchase() {
@@ -25,6 +34,43 @@ public class MainActivity extends AndroidApplication {
int returnValue = mBillingClient.launchBillingFlow(this, builder.build());
return returnValue == BillingClient.BillingResponse.OK || returnValue == BillingClient.BillingResponse.ITEM_ALREADY_OWNED;
}
@Override
protected void onResume() {
super.onResume();
// Since the state of the signed in user can change when the activity is not active
// it is recommended to try and sign in silently from when the app resumes.
new GooglePlay().signInSilently(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == 14562) {
System.out.println("LOGIN RESULT");
Task<GoogleSignInAccount> task =
GoogleSignIn.getSignedInAccountFromIntent(intent);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
System.out.println("GOT ACCOUNT");
System.out.println(account.toString());
GooglePlay.signedIn(account);
new GooglePlay().showAchievements(this);
} catch (ApiException apiException) {
System.out.println("NOT GOT ACCOUNT");
System.out.println(apiException.toString());
new AlertDialog.Builder(this)
.setMessage("Could not sign in to Google Play")
.setNeutralButton("Ok", null)
.show();
}
}
}
private BillingClient mBillingClient;

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -2,7 +2,7 @@
(def packs (into ["do"]
(mapcat (fn [directory]
["run" "-m" "com.badlogic.gdx.tools.texturepacker.TexturePacker" (str "asset-work/" directory) "resources/packed/" (str directory ",")])
["global" "credits"]
["title" ]
#_["behindhouse" "dream" "georgia" "inside-cafeteria" "inside-jail" "outsidehouse" "safe-song" "title"
"castle-gate" "ego" "held" "inside-castle" "inside-stash" "outside-castle" "screenshots" "wizard"
"cat-tree" "ending-castle" "inside-antique" "inside-house" "outside-jail" "space" ])))

View File

@@ -46,6 +46,13 @@ dot
orig: 1, 1
offset: 0, 0
index: -1
google-play
rotate: false
xy: 324, 324
size: 33, 39
orig: 33, 39
offset: 0, 0
index: -1
logo
rotate: false
xy: 2, 249
@@ -55,21 +62,21 @@ logo
index: -1
quill
rotate: false
xy: 324, 324
xy: 879, 978
size: 33, 39
orig: 33, 39
offset: 0, 0
index: -1
save-indicator
rotate: false
xy: 879, 1010
xy: 810, 766
size: 7, 7
orig: 7, 7
offset: 0, 0
index: -1
save-indicator-active
rotate: false
xy: 810, 766
xy: 648, 934
size: 7, 7
orig: 7, 7
offset: 0, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 858 KiB

After

Width:  |  Height:  |  Size: 858 KiB

View File

@@ -0,0 +1,12 @@
(ns advent.achievements
(:import [com.badlogic.gdx Gdx Application])
(:require [advent.steam :as steam]
[advent.utils :as utils]))
(def android-ids {"DESTINY" "CgkIwc6UgfgZEAIQAQ"})
(defn set-achievement [achievement]
(utils/platformify
(.reportAchievement (advent.core.GameCenter.) achievement)
(.setAchievement (advent.core.GooglePlay.) (Gdx/app) (android-ids achievement))
(steam/set-achievement achievement)))

View File

@@ -3,6 +3,7 @@
[advent.screens.rooms.common :as common]
[advent.screens.items :as items]
[advent.actions :as actions]
[advent.achievements :as achievements]
[advent.utils :as utils]
[advent.steam :as steam]
[clojure.zip :as zip]
@@ -105,6 +106,7 @@
:label "Crumbly wall"
:cursor :hand
:script (actions/get-script entities
(achievements/set-achievement "SAFE_AND_SOUND")
(cond (= :night (get-in @entities [:state :time]))
(actions/talk entities :ego "The house is empty right now.")
@@ -119,7 +121,7 @@
(actions/talk entities :ego "So that's the code to his safe..." :animate? false :stop? false)
(actions/play-animation entities :ego :end-squat)
(actions/talk entities :ego "A lot of good it'll do me to know his password while he's still there.")
(steam/set-achievement "SAFE_AND_SOUND")
(achievements/set-achievement "SAFE_AND_SOUND")
(increment-safe-listens entities))
(and (get-in @entities [:state :opened-crack?])

View File

@@ -6,6 +6,7 @@
[advent.utils :as utils]
[advent.screens.dialogue :as dialogue]
[advent.steam :as steam]
[advent.achievements :as achievements]
[advent.tween :as tween]
[clojure.zip :as zip]
@@ -187,7 +188,7 @@
(actions/play-animation entities :ego :reach)
(actions/do-dialogue entities :ego "There, now the vote is 35 to 34!")
(actions/update-state entities #(assoc % :has-voted? true))
(steam/set-achievement "PARDON"))))
(achievements/set-achievement "PARDON"))))
(defn make-note []
{:box [97 102 111 132]

View File

@@ -6,6 +6,7 @@
[advent.screens.rooms.common :as common]
[advent.utils :as utils]
[advent.steam :as steam]
[advent.achievements :as achievements]
[clojure.zip :as zip]
[play-clj.core :refer :all]
[play-clj.ui :refer :all]
@@ -411,7 +412,7 @@
(actions/give entities :kiss)
(actions/do-dialogue entities :ego "A kiss for an inventory item?"
:ego "Sounds like the game designer was running out of good ideas.")
(steam/set-achievement "KITTY_KISS"))
(achievements/set-achievement "KITTY_KISS"))
(actions/talk entities :ego "I can't get his attention from way down here.")))
:stick (actions/get-script entities
(if (get-in @entities [:room :entities :ladder])
@@ -507,7 +508,7 @@
(actions/play-animation entities :owl :eye)
(actions/do-dialogue entities
:owl "I don't think that helped that much.")
(steam/set-achievement "BEHOLDER")
(achievements/set-achievement "BEHOLDER")
(when (actions/has-obtained? entities :feather)
(actions/do-dialogue entities :owl "I think I'll just stick to the monocle."))
(actions/update-state entities (fn [s] (assoc s :owl-tried-strength? true))))

View File

@@ -4,6 +4,7 @@
[advent.actions :as actions]
[advent.screens.items :as items]
[advent.steam :as steam]
[advent.achievements :as achievements]
[advent.utils :as utils]
[advent.pathfind]
[advent.tween :as tween]
@@ -480,7 +481,7 @@
:ego "Hey!"
:ego "I won!")
(steam/set-achievement "BLOODCLOT")
(achievements/set-achievement "BLOODCLOT")
(actions/glad entities)
(actions/walk-straight-to entities :ego [340 55])
(actions/run-action entities

View File

@@ -8,6 +8,7 @@
[advent.tween :as tween]
[advent.utils :as utils]
[advent.saves :as saves]
[advent.achievements :as achievements]
[advent.steam :as steam]
[clojure.zip :as zip]
[clojure.set :as set]
@@ -93,6 +94,7 @@
(defn read-sword-plaque [entities]
(actions/walk-to entities :ego [168 76] :face :left)
(if-not (get-in @entities [:state :plaques-read :sword])
@@ -467,7 +469,7 @@
(actions/resume-camera entities)
(actions/walk-straight-to entities :ego [79 145] :stop? false)
(actions/walk-to entities :ego [159 74])
(steam/set-achievement "DESTINY")
(achievements/set-achievement "DESTINY")
(actions/do-dialogue entities
:ego "Man! What a dream!"
:ego "If only I could become a real knight."

View File

@@ -4,6 +4,7 @@
[advent.screens.items :as items]
[advent.actions :as actions]
[advent.steam :as steam]
[advent.achievements :as achievements]
[advent.utils :as utils]
[clojure.zip :as zip]
[play-clj.core :refer :all]
@@ -86,7 +87,7 @@
:warriors "Take thy servant's medal of strength.")
(actions/give entities :medal)
(actions/glad entities)
(steam/set-achievement "PRO_WRESTLER"))
(achievements/set-achievement "PRO_WRESTLER"))
(do
(play-battle entities :lose)
(actions/do-dialogue entities

View File

@@ -7,6 +7,7 @@
[advent.screens.items :as items]
[advent.utils :as utils]
[advent.steam :as steam]
[advent.achievements :as achievements]
[advent.tween :as tween]
[clojure.zip :as zip]
[clojure.set :as set]
@@ -631,7 +632,7 @@
(actions/remove-entity entities :trophy)
(actions/glad entities)
(actions/talk entities :ego "Thanks!")
(steam/set-achievement "WISE_UP")
(achievements/set-achievement "WISE_UP")
)
))
(brian-get-to-work entities))

View File

@@ -4,6 +4,7 @@
[advent.screens.rooms.common :as common]
[advent.saves :as saves]
[advent.steam :as steam]
[advent.achievements :as achievements]
[advent.actions :as actions]
[advent.screens.items :as items]
[advent.utils :as utils]
@@ -201,7 +202,7 @@
:ego "But what now?"
:ego "I have till sunrise before Bloodclot comes and destroys the town."
:ego "Maybe Gandarf can help me!")
(steam/set-achievement "EX_CON")
(achievements/set-achievement "EX_CON")
(utils/save-chapter @entities :chapter-4)
)
(do

View File

@@ -7,6 +7,7 @@
[advent.actions :as actions]
[advent.tween :as tween]
[advent.steam :as steam]
[advent.achievements :as achievements]
[advent.utils :as utils]
[advent.iap :as iap]
[clojure.zip :as zip]
@@ -724,7 +725,7 @@
(actions/play-animation entities :ego :reach)
(actions/update-state entities #(assoc % :wool-count (inc (or (:wool-count %) 0))))
(when (= 3 (get-in @entities [:state :wool-count]))
(steam/set-achievement "SHEEP_HORDER"))
(achievements/set-achievement "SHEEP_HORDER"))
(actions/update-entities entities #(update-in
% [:room :entities :sheep]

View File

@@ -17,6 +17,7 @@
[advent.saves :as saves]
[advent.tween :as tween]
[advent.steam :as steam]
[advent.achievements :as achievements]
[advent.screens.rooms :as rooms]
[advent.screens.shader :refer [v-shader pix-shader]]
[advent.screens.fade :refer [fade-screen]]
@@ -278,7 +279,7 @@
(Thread/sleep 500)
(actions/play-animation entities :ego :sigh)
(actions/talk entities :ego "You really are a sucker for punishment, aren't you?")
(steam/set-achievement "FOOLISH_LULLABY"))
(achievements/set-achievement "FOOLISH_LULLABY"))
:else
(do
(actions/talk entities :ego "Ugh! I have Gandarf's MagiSafe 2000 tune stuck in my head.")

View File

@@ -393,6 +393,15 @@
save-object
(#(utils/add-actor-to-stage screen %)))
:google-play (doto (assoc (image-button (BaseDrawable.)) :x 1150 :y 160 :scale-x 4 :scale-y 4 :origin-x 0 :origin-y 0 :z 10 :key :google-play)
(image-button! :add (doto (Group. )
(.addActor (:object (doto (image (utils/atlas->texture title-atlas "google-play.png"))
(image! :set-scale 4))))))
save-object
(#(utils/add-actor-to-stage screen %)))
:logo (assoc (utils/atlas->texture title-atlas "logo.png" ) :x 640 :y 960 :scale-x (/ 4 utils/ui-scale) :scale-y (/ 4 utils/ui-scale) :origin-x 160 :origin-y 240 :z 6)
:fade (assoc (utils/atlas->texture global-atlas "black.png")
:scale-x 80
@@ -537,6 +546,15 @@
(assoc :chapters-menu (->> (chapters-menu )
(utils/add-actor-to-stage screen))))
(= :google-play actor-key)
(utils/platformify
entities
(do
(.showAchievements (advent.core.GooglePlay.) (Gdx/app))
entities)
entities)
(= :settings actor-key)
(-> entities
(utils/remove-actor-from-stage :main-menu)

View File

@@ -101,5 +101,6 @@
<framework>AudioToolbox</framework>
<framework>AVFoundation</framework>
<framework>StoreKit</framework>
<framework>GameKit</framework>
</frameworks>
</config>

View File

@@ -0,0 +1,159 @@
package advent.core;
import java.util.ArrayList;
import org.robovm.apple.foundation.NSArray;
import org.robovm.apple.foundation.NSError;
import org.robovm.apple.foundation.NSErrorUserInfo;
import org.robovm.apple.foundation.NSString;
import org.robovm.apple.gamekit.GKAchievement;
import org.robovm.apple.gamekit.GKAchievementViewController;
import org.robovm.apple.gamekit.GKAchievementViewControllerDelegateAdapter;
import org.robovm.apple.gamekit.GKGameCenterControllerDelegateAdapter;
import org.robovm.apple.gamekit.GKGameCenterViewController;
import org.robovm.apple.gamekit.GKGameCenterViewControllerState;
import org.robovm.apple.gamekit.GKLeaderboard;
import org.robovm.apple.gamekit.GKLeaderboardTimeScope;
import org.robovm.apple.gamekit.GKLeaderboardViewController;
import org.robovm.apple.gamekit.GKLeaderboardViewControllerDelegateAdapter;
import org.robovm.apple.gamekit.GKLocalPlayer;
import org.robovm.apple.gamekit.GKScore;
import org.robovm.apple.uikit.UIDevice;
import org.robovm.apple.uikit.UIViewController;
import org.robovm.apple.uikit.UIWindow;
import org.robovm.objc.block.VoidBlock1;
import org.robovm.objc.block.VoidBlock2;
import org.robovm.objc.block.VoidBlock3;
@SuppressWarnings("deprecation")
public class GameCenter {
// private final UIWindow keyWindow;
//private final GameCenterListener listener;
/** Constructor.
* @param keyWindow KeyWindow can't be accessed from the Delegates sometimes, so we need to save a reference
* @param listener */
/*
public GameCenter (UIWindow keyWindow, GameCenterListener listener) {
this.keyWindow = keyWindow;
this.listener = listener;
}
*/
/** Do the login logic. If the user has never loged, a dialog will be shown. */
public void login () {
GKLocalPlayer.getLocalPlayer().setAuthenticateHandler(new VoidBlock2<UIViewController, NSError>() {
@Override
public void invoke (UIViewController viewController, NSError error) {
// If the device does not have an authenticated player, show the login dialog
if (viewController != null) {
System.out.println("Not logged in");
// keyWindow.getRootViewController().presentViewController(viewController, true, null);
}
// If the viewController is null and the player is authenticated, the login is completed
else if (GKLocalPlayer.getLocalPlayer().isAuthenticated()) {
System.out.println("Logged in");
// listener.playerLoginCompleted();
}
// If the viewController is null and the player is not authenticated the login has failed
else {
System.out.println("login error");
// listener.playerLoginFailed(error);
}
}
});
}
/** Report an achievement completed (100 as percentComplete)
*
* @param identifier */
public void reportAchievement (String identifier) {
reportAchievement(identifier, 100);
}
/** Report an achievement with a percentComplete
*
* @param identifier
* @param percentComplete */
public void reportAchievement (String identifier, double percentComplete) {
// If player is not authenticated, do nothing
if (!GKLocalPlayer.getLocalPlayer().isAuthenticated()) {
System.out.println("not authenticated");
//listener.achievementReportFailed(buildUnauthenticatedPlayerError());
return;
}
GKAchievement achievement = new GKAchievement(identifier);
achievement.setPercentComplete(percentComplete);
achievement.setShowsCompletionBanner(true);
// Create an array with the achievement
NSArray<GKAchievement> achievements = new NSArray<GKAchievement>(achievement);
GKAchievement.reportAchievements(achievements, new VoidBlock1<NSError>() {
@Override
public void invoke (NSError error) {
if (error != null) {
System.out.println("ninsuccess achievement " + error.toString());
// listener.achievementReportFailed(error);
} else {
System.out.println("success achievement");
// listener.achievementReportCompleted();
}
}
});
}
/*
public void loadAchievements () {
// If player is not authenticated, do nothing
if (!GKLocalPlayer.getLocalPlayer().isAuthenticated()) {
listener.achievementsLoadFailed(buildUnauthenticatedPlayerError());
return;
}
GKAchievement.loadAchievements(new VoidBlock2<NSArray<GKAchievement>, NSError>() {
@Override
public void invoke (NSArray<GKAchievement> array, NSError error) {
if (error != null) {
listener.achievementsLoadFailed(error);
} else {
ArrayList<GKAchievement> achievements = new ArrayList<GKAchievement>();
for (GKAchievement achievement : array) {
achievements.add(achievement);
}
listener.achievementsLoadCompleted(achievements);
}
}
});
}
*/
/** Reset the achievements progress for the local player. All the entries for the local player are removed from the server. */
/*
public void resetAchievements () {
// If player is not authenticated, do nothing
if (!GKLocalPlayer.getLocalPlayer().isAuthenticated()) {
listener.achievementsResetFailed(buildUnauthenticatedPlayerError());
return;
}
GKAchievement.resetAchievements(new VoidBlock1<NSError>() {
@Override
public void invoke (NSError error) {
if (error != null) {
listener.achievementsResetFailed(error);
} else {
listener.achievementsResetCompleted();
}
}
});
}
*/
}

View File

@@ -31,6 +31,7 @@ public class IOSLauncher extends IOSApplication.Delegate {
protected IOSApplication createApplication() {
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
new GameCenter().login();
// config.colorFormat = GLKViewDrawableColorFormat.SRGBA8888;
// config.depthFormat = GLKViewDrawableDepthFormat._24;
config.orientationPortrait = false;