Skip to content

Commit

Permalink
Implement AndroidSaveManager
Browse files Browse the repository at this point in the history
  • Loading branch information
justindriggers committed Mar 3, 2024
1 parent 3d615b8 commit 226039d
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 12 deletions.
2 changes: 2 additions & 0 deletions carbonara/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ add_library(carbonara SHARED
app/src/main/cpp/ApplicationAdapter.cpp
app/src/main/cpp/main.cpp
app/src/main/cpp/jni/Callbacks.cpp
app/src/main/cpp/jni/SharedPreferences.cpp
app/src/main/cpp/platform/AndroidAAudioFileLoader.cpp
app/src/main/cpp/platform/AndroidInputManager.cpp
app/src/main/cpp/platform/AndroidLogger.cpp
app/src/main/cpp/platform/AndroidOpenGLFileLoader.cpp
app/src/main/cpp/platform/AndroidSaveManager.cpp
app/src/main/cpp/platform/AndroidTimeManager.cpp
)

Expand Down
2 changes: 1 addition & 1 deletion carbonara/app/src/main/cpp/ApplicationAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ ApplicationAdapter::ApplicationAdapter(android_app& app) {
auto leaderboardManager = std::make_shared<AndroidLeaderboardManager>();
auto lifecycleManager = std::make_shared<AndroidLifecycleManager>();

auto saveManager = std::make_shared<AndroidSaveManager>();
auto saveManager = std::make_shared<AndroidSaveManager>(app);
auto timeManager = std::make_shared<AndroidTimeManager>();

_engine = std::make_unique<Engine>(logger, audioManager, inputManager,
Expand Down
120 changes: 120 additions & 0 deletions carbonara/app/src/main/cpp/jni/SharedPreferences.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include "SharedPreferences.h"

#include <stdexcept>

#include <jni.h>

namespace linguine::carbonara {

SharedPreferences::SharedPreferences(android_app& app, std::string name, Mode mode)
: _app(app) {
auto result = _app.activity->vm->GetEnv(reinterpret_cast<void**>(&_env), JNI_VERSION_1_6);

if (result == JNI_EDETACHED) {
result = _app.activity->vm->AttachCurrentThread(&_env, nullptr);
}

if (result != JNI_OK) {
throw std::runtime_error("Error retrieving JNI environment");
}

auto gameActivityClass = _env->GetObjectClass(_app.activity->javaGameActivity);
auto getSharedPreferencesMethod = _env->GetMethodID(gameActivityClass, "getSharedPreferences",
"(Ljava/lang/String;I)Landroid/content/SharedPreferences;");

if (!getSharedPreferencesMethod) {
throw std::runtime_error("Invalid method: getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;");
}

_sharedPreferences = _env->CallObjectMethod(_app.activity->javaGameActivity,//0x736d2c4721
getSharedPreferencesMethod,
_env->NewStringUTF(name.data()), mode);

auto sharedPreferencesClass = _env->GetObjectClass(_sharedPreferences);
_editMethod = _env->GetMethodID(sharedPreferencesClass, "edit",
"()Landroid/content/SharedPreferences$Editor;");

if (!_editMethod) {
throw std::runtime_error("Invalid method: edit()Landroid/content/SharedPreferences$Editor;");
}

_getBooleanMethod = _env->GetMethodID(sharedPreferencesClass, "getBoolean",
"(Ljava/lang/String;Z)Z");

if (!_getBooleanMethod) {
throw std::runtime_error("Invalid method: getBoolean(Ljava/lang/String;Z)Z");
}

_getIntMethod = _env->GetMethodID(sharedPreferencesClass, "getInt",
"(Ljava/lang/String;I)I");

if (!_getIntMethod) {
throw std::runtime_error("Invalid method: getInt(Ljava/lang/String;I)I");
}
}

SharedPreferences::Editor SharedPreferences::edit() {
auto editor = _env->CallObjectMethod(_sharedPreferences, _editMethod);
return { *_env, editor };
}

bool SharedPreferences::getBoolean(std::string key, bool defaultValue) {
return _env->CallBooleanMethod(_sharedPreferences, _getBooleanMethod,
_env->NewStringUTF(key.data()), defaultValue);
}

int32_t SharedPreferences::getInt(std::string key, int32_t defaultValue) {
return _env->CallIntMethod(_sharedPreferences, _getIntMethod,
_env->NewStringUTF(key.data()), defaultValue);
}

SharedPreferences::Editor::Editor(JNIEnv& env, jobject editor)
: _editor(editor), _env(env) {
auto editorClass = _env.GetObjectClass(_editor);

_putBooleanMethod = _env.GetMethodID(editorClass, "putBoolean",
"(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor;");

if (!_putBooleanMethod) {
throw std::runtime_error("Invalid method: putBoolean(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor;");
}

_putIntMethod = _env.GetMethodID(editorClass, "putInt",
"(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor;");

if (!_putIntMethod) {
throw std::runtime_error("Invalid method: putInt(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor;");
}

_applyMethod = _env.GetMethodID(editorClass, "apply", "()V");

if (!_applyMethod) {
throw std::runtime_error("Invalid method: apply()V");
}
}

SharedPreferences::Editor& SharedPreferences::Editor::putBoolean(std::string key, bool value) {
auto editor = _env.CallObjectMethod(_editor, _putBooleanMethod, _env.NewStringUTF(key.data()), value);

if (!_env.IsSameObject(editor, _editor)) {
throw std::runtime_error("Unexpected method result");
}

return *this;
}

SharedPreferences::Editor& SharedPreferences::Editor::putInt(std::string key, int32_t value) {
auto editor = _env.CallObjectMethod(_editor, _putIntMethod, _env.NewStringUTF(key.data()), value);

if (!_env.IsSameObject(editor, _editor)) {
throw std::runtime_error("Unexpected method result");
}

return *this;
}

void SharedPreferences::Editor::apply() {
_env.CallObjectMethod(_editor, _applyMethod);
}

} // namespace linguine::carbonara
52 changes: 52 additions & 0 deletions carbonara/app/src/main/cpp/jni/SharedPreferences.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#include <string>

#include <game-activity/native_app_glue/android_native_app_glue.h>

namespace linguine::carbonara {

class SharedPreferences {
public:
class Editor {
public:
Editor(JNIEnv& env, jobject editor);

Editor& putBoolean(std::string key, bool value);

Editor& putInt(std::string key, int32_t value);

void apply();

private:
JNIEnv& _env;
jobject _editor;

jmethodID _putBooleanMethod{};
jmethodID _putIntMethod{};
jmethodID _applyMethod{};
};

enum Mode {
Private = 0
};

explicit SharedPreferences(android_app& app, std::string name, Mode mode);

Editor edit();

bool getBoolean(std::string key, bool defaultValue);

int32_t getInt(std::string key, int32_t defaultValue);

private:
android_app& _app;
JNIEnv* _env{};

jobject _sharedPreferences{};
jmethodID _editMethod{};
jmethodID _getIntMethod{};
jmethodID _getBooleanMethod{};
};

} // namespace linguine::carbonara
27 changes: 27 additions & 0 deletions carbonara/app/src/main/cpp/platform/AndroidSaveManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "AndroidSaveManager.h"

namespace linguine::carbonara {

void AndroidSaveManager::load() {
_points = _sharedPreferences.getInt("points", 0);
_lives = static_cast<uint8_t>(_sharedPreferences.getInt("lives", 0));
_isMusicEnabled = _sharedPreferences.getBoolean("music", true);
_isSoundEffectsEnabled = _sharedPreferences.getBoolean("sfx", true);
_isScreenShakeEnabled = _sharedPreferences.getBoolean("shake", true);
_handedness = _sharedPreferences.getInt("handedness", 0) == 0 ? Handedness::Right : Handedness::Left;
_isNewPlayer = _sharedPreferences.getBoolean("new", true);
}

void AndroidSaveManager::save() {
_sharedPreferences.edit()
.putInt("points", _points)
.putInt("lives", _lives)
.putBoolean("music", _isMusicEnabled)
.putBoolean("sfx", _isSoundEffectsEnabled)
.putBoolean("shake", _isScreenShakeEnabled)
.putInt("handedness", _handedness == SaveManager::Handedness::Right ? 0 : 1)
.putBoolean("new", _isNewPlayer)
.apply();
}

} // namespace linguine::carbonara
20 changes: 9 additions & 11 deletions carbonara/app/src/main/cpp/platform/AndroidSaveManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,26 @@

#include "SaveManager.h"

#include "jni/SharedPreferences.h"

namespace linguine::carbonara {

class AndroidSaveManager : public SaveManager {
public:
AndroidSaveManager() : SaveManager() {
explicit AndroidSaveManager(android_app& app)
: SaveManager(), _sharedPreferences(app, "state", SharedPreferences::Mode::Private) {
load();
}

~AndroidSaveManager() override = default;

protected:
void load() override {
_points = 0;
_lives = 0;
_isMusicEnabled = true;
_isSoundEffectsEnabled = true;
_isScreenShakeEnabled = true;
_handedness = Handedness::Right;
_isNewPlayer = true;
}
void load() override;

void save() override;

void save() override {}
private:
SharedPreferences _sharedPreferences;
};

} // namespace linguine::carbonara

0 comments on commit 226039d

Please sign in to comment.