mirror of
https://github.com/rafaelvcaetano/melonDS-android.git
synced 2024-11-23 13:49:43 +00:00
Add base support for RetroAchievements hardcore mode
This commit is contained in:
parent
4bca90ee42
commit
c2658424b3
@ -2,7 +2,7 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"database": {
|
"database": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"identityHash": "31374048dc97dc955a845a6920edacaa",
|
"identityHash": "afbfe1a8a5ee33a9307efcca89acecbd",
|
||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"tableName": "cheat_database",
|
"tableName": "cheat_database",
|
||||||
@ -365,7 +365,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "ra_user_achievement",
|
"tableName": "ra_user_achievement",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`game_id` INTEGER NOT NULL, `achievement_id` INTEGER NOT NULL, `is_unlocked` INTEGER NOT NULL, PRIMARY KEY(`game_id`, `achievement_id`))",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`game_id` INTEGER NOT NULL, `achievement_id` INTEGER NOT NULL, `is_unlocked` INTEGER NOT NULL, `is_hardcore` INTEGER NOT NULL, PRIMARY KEY(`game_id`, `achievement_id`, `is_hardcore`))",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "gameId",
|
"fieldPath": "gameId",
|
||||||
@ -384,13 +384,20 @@
|
|||||||
"columnName": "is_unlocked",
|
"columnName": "is_unlocked",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": true
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isHardcore",
|
||||||
|
"columnName": "is_hardcore",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
"autoGenerate": false,
|
"autoGenerate": false,
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"game_id",
|
"game_id",
|
||||||
"achievement_id"
|
"achievement_id",
|
||||||
|
"is_hardcore"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"indices": [],
|
"indices": [],
|
||||||
@ -398,7 +405,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"tableName": "ra_game_set_metadata",
|
"tableName": "ra_game_set_metadata",
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`game_id` INTEGER NOT NULL, `last_achievement_set_updated` INTEGER, `last_user_data_updated` INTEGER, PRIMARY KEY(`game_id`))",
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`game_id` INTEGER NOT NULL, `last_achievement_set_updated` INTEGER, `last_user_data_updated` INTEGER, `last_hardcore_user_data_updated` INTEGER, PRIMARY KEY(`game_id`))",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"fieldPath": "gameId",
|
"fieldPath": "gameId",
|
||||||
@ -413,10 +420,16 @@
|
|||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldPath": "lastUserDataUpdated",
|
"fieldPath": "lastSoftcoreUserDataUpdated",
|
||||||
"columnName": "last_user_data_updated",
|
"columnName": "last_user_data_updated",
|
||||||
"affinity": "INTEGER",
|
"affinity": "INTEGER",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "lastHardcoreUserDataUpdated",
|
||||||
|
"columnName": "last_hardcore_user_data_updated",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
@ -491,7 +504,7 @@
|
|||||||
"views": [],
|
"views": [],
|
||||||
"setupQueries": [
|
"setupQueries": [
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '31374048dc97dc955a845a6920edacaa')"
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'afbfe1a8a5ee33a9307efcca89acecbd')"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -42,8 +42,8 @@ abstract class RAAchievementsDao {
|
|||||||
@Query("SELECT * FROM ra_game WHERE game_id = :gameId")
|
@Query("SELECT * FROM ra_game WHERE game_id = :gameId")
|
||||||
abstract suspend fun getGame(gameId: Long): RAGameEntity?
|
abstract suspend fun getGame(gameId: Long): RAGameEntity?
|
||||||
|
|
||||||
@Query("SELECT * FROM ra_user_achievement WHERE game_id = :gameId AND is_unlocked = 1")
|
@Query("SELECT * FROM ra_user_achievement WHERE game_id = :gameId AND is_hardcore = :forHardcoreMode AND is_unlocked = 1")
|
||||||
abstract suspend fun getGameUserUnlockedAchievements(gameId: Long): List<RAUserAchievementEntity>
|
abstract suspend fun getGameUserUnlockedAchievements(gameId: Long, forHardcoreMode: Boolean): List<RAUserAchievementEntity>
|
||||||
|
|
||||||
@Query("DELETE FROM ra_user_achievement WHERE game_id = :gameId")
|
@Query("DELETE FROM ra_user_achievement WHERE game_id = :gameId")
|
||||||
protected abstract suspend fun deleteGameUserUnlockedAchievements(gameId: Long)
|
protected abstract suspend fun deleteGameUserUnlockedAchievements(gameId: Long)
|
||||||
|
@ -9,5 +9,6 @@ import java.time.Instant
|
|||||||
data class RAGameSetMetadata(
|
data class RAGameSetMetadata(
|
||||||
@PrimaryKey @ColumnInfo(name = "game_id") val gameId: Long,
|
@PrimaryKey @ColumnInfo(name = "game_id") val gameId: Long,
|
||||||
@ColumnInfo(name = "last_achievement_set_updated") val lastAchievementSetUpdated: Instant?,
|
@ColumnInfo(name = "last_achievement_set_updated") val lastAchievementSetUpdated: Instant?,
|
||||||
@ColumnInfo(name = "last_user_data_updated") val lastUserDataUpdated: Instant?,
|
@ColumnInfo(name = "last_user_data_updated") val lastSoftcoreUserDataUpdated: Instant?,
|
||||||
|
@ColumnInfo(name = "last_hardcore_user_data_updated") val lastHardcoreUserDataUpdated: Instant?,
|
||||||
)
|
)
|
||||||
|
@ -5,10 +5,11 @@ import androidx.room.Entity
|
|||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
tableName = "ra_user_achievement",
|
tableName = "ra_user_achievement",
|
||||||
primaryKeys = ["game_id", "achievement_id"],
|
primaryKeys = ["game_id", "achievement_id", "is_hardcore"],
|
||||||
)
|
)
|
||||||
data class RAUserAchievementEntity(
|
data class RAUserAchievementEntity(
|
||||||
@ColumnInfo(name = "game_id") val gameId: Long,
|
@ColumnInfo(name = "game_id") val gameId: Long,
|
||||||
@ColumnInfo(name = "achievement_id") val achievementId: Long,
|
@ColumnInfo(name = "achievement_id") val achievementId: Long,
|
||||||
@ColumnInfo(name = "is_unlocked") val isUnlocked: Boolean,
|
@ColumnInfo(name = "is_unlocked") val isUnlocked: Boolean,
|
||||||
|
@ColumnInfo(name = "is_hardcore") val isHardcore: Boolean,
|
||||||
)
|
)
|
||||||
|
@ -5,4 +5,22 @@ import me.magnum.rcheevosapi.model.RAAchievement
|
|||||||
data class RAUserAchievement(
|
data class RAUserAchievement(
|
||||||
val achievement: RAAchievement,
|
val achievement: RAAchievement,
|
||||||
val isUnlocked: Boolean,
|
val isUnlocked: Boolean,
|
||||||
)
|
val forHardcoreMode: Boolean,
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of points that this achievement is worth for the user in the current state. This depends on the actual number of points that the achievements awards,
|
||||||
|
* whether the user has unlocked it or not and if it was unlocked in hardcore or softcore mode.
|
||||||
|
*/
|
||||||
|
fun pointsWorth(): Int {
|
||||||
|
return if (isUnlocked) {
|
||||||
|
if (forHardcoreMode) {
|
||||||
|
achievement.points * 2
|
||||||
|
} else {
|
||||||
|
achievement.points
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,10 +9,10 @@ interface RetroAchievementsRepository {
|
|||||||
suspend fun getUserAuthentication(): RAUserAuth?
|
suspend fun getUserAuthentication(): RAUserAuth?
|
||||||
suspend fun login(username: String, password: String): Result<Unit>
|
suspend fun login(username: String, password: String): Result<Unit>
|
||||||
suspend fun logout()
|
suspend fun logout()
|
||||||
suspend fun getGameUserAchievements(gameHash: String): Result<List<RAUserAchievement>>
|
suspend fun getGameUserAchievements(gameHash: String, forHardcoreMode: Boolean): Result<List<RAUserAchievement>>
|
||||||
suspend fun getGameRichPresencePatch(gameHash: String): String?
|
suspend fun getGameRichPresencePatch(gameHash: String): String?
|
||||||
suspend fun getAchievement(achievementId: Long): Result<RAAchievement?>
|
suspend fun getAchievement(achievementId: Long): Result<RAAchievement?>
|
||||||
suspend fun awardAchievement(achievement: RAAchievement)
|
suspend fun awardAchievement(achievement: RAAchievement, forHardcoreMode: Boolean)
|
||||||
suspend fun submitPendingAchievements(): Result<Unit>
|
suspend fun submitPendingAchievements(): Result<Unit>
|
||||||
suspend fun startSession(gameHash: String)
|
suspend fun startSession(gameHash: String)
|
||||||
suspend fun sendSessionHeartbeat(gameHash: String, richPresenceDescription: String?)
|
suspend fun sendSessionHeartbeat(gameHash: String, richPresenceDescription: String?)
|
||||||
|
@ -51,6 +51,7 @@ interface SettingsRepository {
|
|||||||
fun getSoftInputOpacity(): Int
|
fun getSoftInputOpacity(): Int
|
||||||
|
|
||||||
fun isRetroAchievementsRichPresenceEnabled(): Boolean
|
fun isRetroAchievementsRichPresenceEnabled(): Boolean
|
||||||
|
fun isRetroAchievementsHardcoreEnabled(): Boolean
|
||||||
|
|
||||||
fun areCheatsEnabled(): Boolean
|
fun areCheatsEnabled(): Boolean
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ class AndroidRetroAchievementsRepository(
|
|||||||
raUserAuthStore.clearUserAuth()
|
raUserAuthStore.clearUserAuth()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getGameUserAchievements(gameHash: String): Result<List<RAUserAchievement>> {
|
override suspend fun getGameUserAchievements(gameHash: String, forHardcoreMode: Boolean): Result<List<RAUserAchievement>> {
|
||||||
val gameIdResult = getGameIdFromGameHash(gameHash)
|
val gameIdResult = getGameIdFromGameHash(gameHash)
|
||||||
if (gameIdResult.isFailure) {
|
if (gameIdResult.isFailure) {
|
||||||
return Result.failure(gameIdResult.exceptionOrNull()!!)
|
return Result.failure(gameIdResult.exceptionOrNull()!!)
|
||||||
@ -74,7 +74,7 @@ class AndroidRetroAchievementsRepository(
|
|||||||
return Result.failure(gameAchievementsResult.exceptionOrNull()!!)
|
return Result.failure(gameAchievementsResult.exceptionOrNull()!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
val userUnlocksResult = fetchGameUserUnlockedAchievements(gameId, currentMetadata)
|
val userUnlocksResult = fetchGameUserUnlockedAchievements(gameId, forHardcoreMode, currentMetadata)
|
||||||
if (userUnlocksResult.isFailure) {
|
if (userUnlocksResult.isFailure) {
|
||||||
return Result.failure(userUnlocksResult.exceptionOrNull()!!)
|
return Result.failure(userUnlocksResult.exceptionOrNull()!!)
|
||||||
}
|
}
|
||||||
@ -86,6 +86,7 @@ class AndroidRetroAchievementsRepository(
|
|||||||
RAUserAchievement(
|
RAUserAchievement(
|
||||||
achievement = it,
|
achievement = it,
|
||||||
isUnlocked = userUnlocks.contains(it.id),
|
isUnlocked = userUnlocks.contains(it.id),
|
||||||
|
forHardcoreMode = forHardcoreMode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return Result.success(userAchievements)
|
return Result.success(userAchievements)
|
||||||
@ -108,14 +109,16 @@ class AndroidRetroAchievementsRepository(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun awardAchievement(achievement: RAAchievement) {
|
override suspend fun awardAchievement(achievement: RAAchievement, forHardcoreMode: Boolean) {
|
||||||
submitAchievementAward(achievement.id, achievement.gameId, false, true)
|
submitAchievementAward(achievement.id, achievement.gameId, forHardcoreMode).onFailure {
|
||||||
|
scheduleAchievementSubmissionJob()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun submitPendingAchievements(): Result<Unit> {
|
override suspend fun submitPendingAchievements(): Result<Unit> {
|
||||||
achievementsDao.getPendingAchievementSubmissions().forEach {
|
achievementsDao.getPendingAchievementSubmissions().forEach {
|
||||||
// Do not schedule resubmission if this fails. The current submission job should schedule another attempt
|
// Do not schedule resubmission if this fails. The current submission job should schedule another attempt
|
||||||
val submissionResult = submitAchievementAward(it.achievementId, RAGameId(it.gameId), it.forHardcoreMode, false)
|
val submissionResult = submitAchievementAward(it.achievementId, RAGameId(it.gameId), it.forHardcoreMode)
|
||||||
if (submissionResult.isFailure) {
|
if (submissionResult.isFailure) {
|
||||||
return submissionResult
|
return submissionResult
|
||||||
}
|
}
|
||||||
@ -136,9 +139,14 @@ class AndroidRetroAchievementsRepository(
|
|||||||
raApi.sendPing(gameId, richPresenceDescription)
|
raApi.sendPing(gameId, richPresenceDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun submitAchievementAward(achievementId: Long, gameId: RAGameId, forHardcoreMode: Boolean, scheduleResubmissionOnFailure: Boolean): Result<Unit> {
|
private suspend fun submitAchievementAward(achievementId: Long, gameId: RAGameId, forHardcoreMode: Boolean): Result<Unit> {
|
||||||
// Award the achievement immediately locally
|
// Award the achievement immediately locally
|
||||||
val userAchievement = RAUserAchievementEntity(gameId.id, achievementId, true)
|
val userAchievement = RAUserAchievementEntity(
|
||||||
|
gameId = gameId.id,
|
||||||
|
achievementId = achievementId,
|
||||||
|
isUnlocked = true,
|
||||||
|
isHardcore = forHardcoreMode,
|
||||||
|
)
|
||||||
achievementsDao.addUserAchievement(userAchievement)
|
achievementsDao.addUserAchievement(userAchievement)
|
||||||
|
|
||||||
return raApi.awardAchievement(achievementId, forHardcoreMode).onFailure {
|
return raApi.awardAchievement(achievementId, forHardcoreMode).onFailure {
|
||||||
@ -149,9 +157,6 @@ class AndroidRetroAchievementsRepository(
|
|||||||
forHardcoreMode = forHardcoreMode,
|
forHardcoreMode = forHardcoreMode,
|
||||||
)
|
)
|
||||||
achievementsDao.addPendingAchievementSubmission(pendingAchievementSubmissionEntity)
|
achievementsDao.addPendingAchievementSubmission(pendingAchievementSubmissionEntity)
|
||||||
if (scheduleResubmissionOnFailure) {
|
|
||||||
scheduleAchievementSubmissionJob()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,24 +222,25 @@ class AndroidRetroAchievementsRepository(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchGameUserUnlockedAchievements(gameId: RAGameId, gameSetMetadata: CurrentGameSetMetadata): Result<List<Long>> {
|
private suspend fun fetchGameUserUnlockedAchievements(gameId: RAGameId, forHardcoreMode: Boolean, gameSetMetadata: CurrentGameSetMetadata): Result<List<Long>> {
|
||||||
return if (mustRefreshUserData(gameSetMetadata.currentMetadata)) {
|
return if (mustRefreshUserData(gameSetMetadata.currentMetadata, forHardcoreMode)) {
|
||||||
raApi.getUserUnlockedAchievements(gameId, false).onSuccess { userUnlocks ->
|
raApi.getUserUnlockedAchievements(gameId, forHardcoreMode).onSuccess { userUnlocks ->
|
||||||
val userAchievementEntities = userUnlocks.map {
|
val userAchievementEntities = userUnlocks.map {
|
||||||
RAUserAchievementEntity(
|
RAUserAchievementEntity(
|
||||||
gameId.id,
|
gameId = gameId.id,
|
||||||
it,
|
achievementId = it,
|
||||||
true,
|
isUnlocked = true,
|
||||||
|
isHardcore = forHardcoreMode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val newMetadata = gameSetMetadata.withNewUserAchievementsUpdate()
|
val newMetadata = gameSetMetadata.withNewUserAchievementsUpdate(forHardcoreMode)
|
||||||
achievementsDao.updateGameUserUnlockedAchievements(gameId.id, userAchievementEntities)
|
achievementsDao.updateGameUserUnlockedAchievements(gameId.id, userAchievementEntities)
|
||||||
achievementsDao.updateGameSetMetadata(newMetadata)
|
achievementsDao.updateGameSetMetadata(newMetadata)
|
||||||
}.recoverCatching { exception ->
|
}.recoverCatching { exception ->
|
||||||
if (gameSetMetadata.isUserAchievementDataKnown()) {
|
if (gameSetMetadata.isUserAchievementDataKnown(forHardcoreMode)) {
|
||||||
// Load DB data because we know that it was previously loaded
|
// Load DB data because we know that it was previously loaded
|
||||||
achievementsDao.getGameUserUnlockedAchievements(gameId.id).map {
|
achievementsDao.getGameUserUnlockedAchievements(gameId.id, forHardcoreMode).map {
|
||||||
it.achievementId
|
it.achievementId
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -244,7 +250,7 @@ class AndroidRetroAchievementsRepository(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
runCatching {
|
runCatching {
|
||||||
achievementsDao.getGameUserUnlockedAchievements(gameId.id).map {
|
achievementsDao.getGameUserUnlockedAchievements(gameId.id, forHardcoreMode).map {
|
||||||
it.achievementId
|
it.achievementId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,13 +274,19 @@ class AndroidRetroAchievementsRepository(
|
|||||||
return Duration.between(gameSetMetadata.lastAchievementSetUpdated, Instant.now()) >= Duration.ofDays(7)
|
return Duration.between(gameSetMetadata.lastAchievementSetUpdated, Instant.now()) >= Duration.ofDays(7)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mustRefreshUserData(gameSetMetadata: RAGameSetMetadata?): Boolean {
|
private fun mustRefreshUserData(gameSetMetadata: RAGameSetMetadata?, forHardcoreMode: Boolean): Boolean {
|
||||||
if (gameSetMetadata?.lastUserDataUpdated == null) {
|
val lastUserDataUpdateTimestamp = if (forHardcoreMode) {
|
||||||
|
gameSetMetadata?.lastHardcoreUserDataUpdated
|
||||||
|
} else {
|
||||||
|
gameSetMetadata?.lastSoftcoreUserDataUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastUserDataUpdateTimestamp == null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync user achievement data once a day
|
// Sync user achievement data once a day
|
||||||
return Duration.between(gameSetMetadata.lastUserDataUpdated, Instant.now()) >= Duration.ofDays(1)
|
return Duration.between(lastUserDataUpdateTimestamp, Instant.now()) >= Duration.ofDays(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scheduleAchievementSubmissionJob() {
|
private fun scheduleAchievementSubmissionJob() {
|
||||||
@ -296,14 +308,20 @@ class AndroidRetroAchievementsRepository(
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
fun withNewAchievementSetUpdate(): RAGameSetMetadata {
|
fun withNewAchievementSetUpdate(): RAGameSetMetadata {
|
||||||
return (currentMetadata?.copy(lastAchievementSetUpdated = Instant.now()) ?: RAGameSetMetadata(gameId.id, Instant.now(), null)).also {
|
return (currentMetadata?.copy(lastAchievementSetUpdated = Instant.now()) ?: RAGameSetMetadata(gameId.id, Instant.now(), null, null)).also {
|
||||||
currentMetadata = it
|
currentMetadata = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withNewUserAchievementsUpdate(): RAGameSetMetadata {
|
fun withNewUserAchievementsUpdate(forHardcoreMode: Boolean): RAGameSetMetadata {
|
||||||
return (currentMetadata?.copy(lastUserDataUpdated = Instant.now()) ?: RAGameSetMetadata(gameId.id, null, Instant.now())).also {
|
return if (forHardcoreMode) {
|
||||||
currentMetadata = it
|
currentMetadata?.copy(lastHardcoreUserDataUpdated = Instant.now()) ?: RAGameSetMetadata(gameId.id, null, null, Instant.now()).also {
|
||||||
|
currentMetadata = it
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentMetadata?.copy(lastSoftcoreUserDataUpdated = Instant.now()) ?: RAGameSetMetadata(gameId.id, null, Instant.now(), null).also {
|
||||||
|
currentMetadata = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,8 +329,12 @@ class AndroidRetroAchievementsRepository(
|
|||||||
return currentMetadata?.lastAchievementSetUpdated != null
|
return currentMetadata?.lastAchievementSetUpdated != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isUserAchievementDataKnown(): Boolean {
|
fun isUserAchievementDataKnown(forHardcoreMode: Boolean): Boolean {
|
||||||
return currentMetadata?.lastUserDataUpdated != null
|
return if (forHardcoreMode) {
|
||||||
|
currentMetadata?.lastHardcoreUserDataUpdated != null
|
||||||
|
} else {
|
||||||
|
currentMetadata?.lastSoftcoreUserDataUpdated != null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -370,6 +370,10 @@ class SharedPreferencesSettingsRepository(
|
|||||||
return preferences.getBoolean("ra_rich_presence", true)
|
return preferences.getBoolean("ra_rich_presence", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isRetroAchievementsHardcoreEnabled(): Boolean {
|
||||||
|
return preferences.getBoolean("ra_hardcore_enabled", false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun areCheatsEnabled(): Boolean {
|
override fun areCheatsEnabled(): Boolean {
|
||||||
return preferences.getBoolean("cheats_enabled", false)
|
return preferences.getBoolean("cheats_enabled", false)
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ class EmulatorViewModel @Inject constructor(
|
|||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (retroAchievementsRepository.isUserAuthenticated()) {
|
if (retroAchievementsRepository.isUserAuthenticated()) {
|
||||||
val achievementData = retroAchievementsRepository.getGameUserAchievements(rom.retroAchievementsHash).map { achievements ->
|
val achievementData = retroAchievementsRepository.getGameUserAchievements(rom.retroAchievementsHash, false).map { achievements ->
|
||||||
achievements.filter { !it.isUnlocked }.map { RASimpleAchievement(it.achievement.id, it.achievement.memoryAddress) }
|
achievements.filter { !it.isUnlocked }.map { RASimpleAchievement(it.achievement.id, it.achievement.memoryAddress) }
|
||||||
}.fold(
|
}.fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
@ -315,7 +315,7 @@ class EmulatorViewModel @Inject constructor(
|
|||||||
.onSuccess {
|
.onSuccess {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
_achievementTriggeredEvent.emit(it)
|
_achievementTriggeredEvent.emit(it)
|
||||||
retroAchievementsRepository.awardAchievement(it)
|
retroAchievementsRepository.awardAchievement(it, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class RomRetroAchievementsViewModel @Inject constructor(
|
|||||||
private fun loadAchievements() {
|
private fun loadAchievements() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (retroAchievementsRepository.isUserAuthenticated()) {
|
if (retroAchievementsRepository.isUserAuthenticated()) {
|
||||||
retroAchievementsRepository.getGameUserAchievements(rom.retroAchievementsHash).fold(
|
retroAchievementsRepository.getGameUserAchievements(rom.retroAchievementsHash, false).fold(
|
||||||
onSuccess = { achievements ->
|
onSuccess = { achievements ->
|
||||||
val sortedAchievements = achievements.sortedBy {
|
val sortedAchievements = achievements.sortedBy {
|
||||||
// Display unlocked achievements first
|
// Display unlocked achievements first
|
||||||
@ -82,7 +82,7 @@ class RomRetroAchievementsViewModel @Inject constructor(
|
|||||||
return RomAchievementsSummary(
|
return RomAchievementsSummary(
|
||||||
totalAchievements = userAchievements.size,
|
totalAchievements = userAchievements.size,
|
||||||
completedAchievements = userAchievements.count { it.isUnlocked },
|
completedAchievements = userAchievements.count { it.isUnlocked },
|
||||||
totalPoints = userAchievements.sumOf { if (it.isUnlocked) it.achievement.points else 0 },
|
totalPoints = userAchievements.sumOf { it.pointsWorth() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -191,6 +191,7 @@ fun PreviewRomAchievementUi() {
|
|||||||
userAchievement = RAUserAchievement(
|
userAchievement = RAUserAchievement(
|
||||||
achievement = mockRAAchievementPreview(),
|
achievement = mockRAAchievementPreview(),
|
||||||
isUnlocked = true,
|
isUnlocked = true,
|
||||||
|
forHardcoreMode = false,
|
||||||
),
|
),
|
||||||
onViewAchievement = {},
|
onViewAchievement = {},
|
||||||
)
|
)
|
||||||
|
@ -293,8 +293,8 @@ private fun PreviewContent() {
|
|||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
content = RomRetroAchievementsUiState.Ready(
|
content = RomRetroAchievementsUiState.Ready(
|
||||||
listOf(
|
listOf(
|
||||||
RAUserAchievement(mockRAAchievementPreview(id = 1), false),
|
RAUserAchievement(mockRAAchievementPreview(id = 1), false, false),
|
||||||
RAUserAchievement(mockRAAchievementPreview(id = 2, title = "This is another amazing achievement", description = "But this one cannot be missed."), false),
|
RAUserAchievement(mockRAAchievementPreview(id = 2, title = "This is another amazing achievement", description = "But this one cannot be missed."), false, false),
|
||||||
),
|
),
|
||||||
RomAchievementsSummary(50, 20, 85),
|
RomAchievementsSummary(50, 20, 85),
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user