Fix: Resolve crash on startup due to ProGuard/Gson TypeToken issue

- Added necessary ProGuard rules to keep HighScore class, generic signatures, and annotations.

- Fixed bug where music started on title screen instead of game start.

- Fixed bug where session stats were blank on game over screen by ensuring stats are displayed correctly after high score entry.

- Fixed bug where game music did not restart after playing again.
This commit is contained in:
cmclark00 2025-04-01 17:34:40 -04:00
parent c1da5ba20f
commit 04b87e8f19
4 changed files with 145 additions and 20 deletions

View file

@ -122,12 +122,27 @@ class MainActivity : AppCompatActivity(),
// Add these new properties at the class level
private var currentCustomizationMenuSelection = 0
// CAPTURE session stats needed for display into MainActivity member variables
private var lastSessionScore = 0
private var lastSessionLines = 0
private var lastSessionPieces = 0
private var lastSessionTime = 0L
private var lastSessionLevel = 0
private var lastSessionSingles = 0
private var lastSessionDoubles = 0
private var lastSessionTriples = 0
private var lastSessionQuads = 0
override fun onCreate(savedInstanceState: Bundle?) {
// Register activity result launcher for high score entry
highScoreEntryLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
// No matter what the result is, we just show the game over container
// When returning from HighScoreEntryActivity:
// 1. Hide progression screen
progressionScreen.visibility = View.GONE
binding.gameOverContainer.visibility = View.VISIBLE
// 2. Make game over container visible (it's already laid out)
binding.gameOverContainer.visibility = View.VISIBLE
// 3. *** Call showGameOverScreenDirectly to populate the stats ***
showGameOverScreenDirectly(lastSessionScore) // Use the captured score
// Keep all game UI elements hidden
binding.gameControlsContainer.visibility = View.GONE
@ -406,7 +421,33 @@ class MainActivity : AppCompatActivity(),
val newHighScore = highScoreManager.isHighScore(finalScore)
statsManager.endSession() // End session after calculations
Log.d(TAG, "Game Over. Score: $finalScore, Level: ${viewModel.currentLevel.value}, Lines: ${gameBoard.lines}, Start Level: ${viewModel.selectedLevel.value}, New High Score: $newHighScore, XP Gained: $xpGained")
// CAPTURE session stats needed for display into MainActivity member variables
lastSessionScore = statsManager.getSessionScore()
lastSessionLines = statsManager.getSessionLines()
lastSessionPieces = statsManager.getSessionPieces()
lastSessionTime = statsManager.getSessionTime()
lastSessionLevel = statsManager.getSessionLevel()
lastSessionSingles = statsManager.getSessionSingles()
lastSessionDoubles = statsManager.getSessionDoubles()
lastSessionTriples = statsManager.getSessionTriples()
lastSessionQuads = statsManager.getSessionQuads()
// *** Add detailed logging here ***
Log.d(TAG, "[GameOverDebug] Captured Stats:")
Log.d(TAG, "[GameOverDebug] Score: $lastSessionScore (from manager: ${statsManager.getSessionScore()})")
Log.d(TAG, "[GameOverDebug] Lines: $lastSessionLines (from manager: ${statsManager.getSessionLines()})")
Log.d(TAG, "[GameOverDebug] Pieces: $lastSessionPieces (from manager: ${statsManager.getSessionPieces()})")
Log.d(TAG, "[GameOverDebug] Time: $lastSessionTime (from manager: ${statsManager.getSessionTime()})")
Log.d(TAG, "[GameOverDebug] Level: $lastSessionLevel (from manager: ${statsManager.getSessionLevel()})")
Log.d(TAG, "[GameOverDebug] Singles: $lastSessionSingles (from manager: ${statsManager.getSessionSingles()})")
Log.d(TAG, "[GameOverDebug] Doubles: $lastSessionDoubles (from manager: ${statsManager.getSessionDoubles()})")
Log.d(TAG, "[GameOverDebug] Triples: $lastSessionTriples (from manager: ${statsManager.getSessionTriples()})")
Log.d(TAG, "[GameOverDebug] Quads: $lastSessionQuads (from manager: ${statsManager.getSessionQuads()})")
// End the session (updates lifetime stats)
statsManager.endSession()
Log.d(TAG, "Game Over. Captured Score: $lastSessionScore, Level: $lastSessionLevel, Lines: $lastSessionLines, Start Level: ${viewModel.selectedLevel.value}, New High Score: $newHighScore, XP Gained: $xpGained")
// Show appropriate screen: Progression or Game Over directly
if (xpGained > 0 || newHighScore) {
@ -570,8 +611,8 @@ class MainActivity : AppCompatActivity(),
/**
* Shows the final game over screen with stats.
*/
private fun showGameOverScreenDirectly(score: Int) {
Log.d(TAG, "Showing final game over screen with score: $score")
private fun showGameOverScreenDirectly(score: Int) { // Keep score param for logging if needed elsewhere
Log.d(TAG, "Showing final game over screen with score from param: $score, from StatsManager: ${statsManager.getSessionScore()}")
// Ensure game UI is hidden
binding.gameControlsContainer.visibility = View.GONE
binding.holdPieceView.visibility = View.GONE
@ -584,20 +625,20 @@ class MainActivity : AppCompatActivity(),
// Update session stats display in the gameOverContainer
val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
timeFormat.timeZone = TimeZone.getTimeZone("UTC")
val gameTime = System.currentTimeMillis() - gameStartTime // Recalculate or pass from onGameOver?
// Let's recalculate for simplicity here.
// val gameTime = System.currentTimeMillis() - gameStartTime // No longer needed here
// Set text directly using interpolation (workaround attempt)
binding.sessionScoreText.text = "Score: $score"
binding.sessionLinesText.text = "Lines: ${gameBoard.lines}"
binding.sessionPiecesText.text = "Pieces: $piecesPlaced"
binding.sessionTimeText.text = "Time: ${timeFormat.format(gameTime)}"
binding.sessionLevelText.text = "Level: ${viewModel.currentLevel.value ?: 1}"
// --- Consistently use StatsManager session getters ---
binding.sessionScoreText.text = "Score: ${statsManager.getSessionScore()}"
binding.sessionLinesText.text = "Lines: ${statsManager.getSessionLines()}"
binding.sessionPiecesText.text = "Pieces: ${statsManager.getSessionPieces()}"
binding.sessionTimeText.text = "Time: ${timeFormat.format(statsManager.getSessionTime())}"
binding.sessionLevelText.text = "Level: ${statsManager.getSessionLevel()}"
binding.sessionSinglesText.text = "Singles: ${statsManager.getSessionSingles()}"
binding.sessionDoublesText.text = "Doubles: ${statsManager.getSessionDoubles()}"
binding.sessionTriplesText.text = "Triples: ${statsManager.getSessionTriples()}"
binding.sessionQuadsText.text = "Quads: ${statsManager.getSessionQuads()}"
// --- End StatsManager usage ---
// Make the container visible
binding.gameOverContainer.visibility = View.VISIBLE
@ -900,6 +941,9 @@ class MainActivity : AppCompatActivity(),
*/
private fun startGame() {
Log.d(TAG, "Starting game at level ${viewModel.selectedLevel.value}")
// Reset session stats FIRST
statsManager.startNewSession()
// Reset game state
viewModel.resetGame() // Resets score and level in ViewModel
viewModel.setLevel(viewModel.selectedLevel.value ?: 1) // Set initial level from selection
@ -973,7 +1017,33 @@ class MainActivity : AppCompatActivity(),
val newHighScore = highScoreManager.isHighScore(finalScore)
statsManager.endSession() // End session after calculations
Log.d(TAG, "Game Over. Score: $finalScore, Level: ${viewModel.currentLevel.value}, Lines: ${gameBoard.lines}, Start Level: ${viewModel.selectedLevel.value}, New High Score: $newHighScore, XP Gained: $xpGained")
// CAPTURE session stats needed for display into MainActivity member variables
lastSessionScore = statsManager.getSessionScore()
lastSessionLines = statsManager.getSessionLines()
lastSessionPieces = statsManager.getSessionPieces()
lastSessionTime = statsManager.getSessionTime()
lastSessionLevel = statsManager.getSessionLevel()
lastSessionSingles = statsManager.getSessionSingles()
lastSessionDoubles = statsManager.getSessionDoubles()
lastSessionTriples = statsManager.getSessionTriples()
lastSessionQuads = statsManager.getSessionQuads()
// *** Add detailed logging here ***
Log.d(TAG, "[GameOverDebug] Captured Stats:")
Log.d(TAG, "[GameOverDebug] Score: $lastSessionScore (from manager: ${statsManager.getSessionScore()})")
Log.d(TAG, "[GameOverDebug] Lines: $lastSessionLines (from manager: ${statsManager.getSessionLines()})")
Log.d(TAG, "[GameOverDebug] Pieces: $lastSessionPieces (from manager: ${statsManager.getSessionPieces()})")
Log.d(TAG, "[GameOverDebug] Time: $lastSessionTime (from manager: ${statsManager.getSessionTime()})")
Log.d(TAG, "[GameOverDebug] Level: $lastSessionLevel (from manager: ${statsManager.getSessionLevel()})")
Log.d(TAG, "[GameOverDebug] Singles: $lastSessionSingles (from manager: ${statsManager.getSessionSingles()})")
Log.d(TAG, "[GameOverDebug] Doubles: $lastSessionDoubles (from manager: ${statsManager.getSessionDoubles()})")
Log.d(TAG, "[GameOverDebug] Triples: $lastSessionTriples (from manager: ${statsManager.getSessionTriples()})")
Log.d(TAG, "[GameOverDebug] Quads: $lastSessionQuads (from manager: ${statsManager.getSessionQuads()})")
// End the session (updates lifetime stats)
statsManager.endSession()
Log.d(TAG, "Game Over. Captured Score: $lastSessionScore, Level: $lastSessionLevel, Lines: $lastSessionLines, Start Level: ${viewModel.selectedLevel.value}, New High Score: $newHighScore, XP Gained: $xpGained")
// Show appropriate screen: Progression or Game Over directly
if (xpGained > 0 || newHighScore) {
@ -1007,6 +1077,7 @@ class MainActivity : AppCompatActivity(),
// Start background music if enabled
if (viewModel.isMusicEnabled.value == true) { // Read from ViewModel
gameMusic.prepareMusic() // Ensure player is ready
gameMusic.start()
}
@ -1014,8 +1085,8 @@ class MainActivity : AppCompatActivity(),
gameView.start()
// Observer ensures gameMusic is enabled/disabled correctly via gameMusic.setEnabled()
// Reset session stats
statsManager.startNewSession()
// Reset session stats - MOVED TO TOP
// statsManager.startNewSession()
progressionManager.startNewSession()
gameBoard.updateLevel(viewModel.selectedLevel.value ?: 1)
}
@ -1222,6 +1293,9 @@ class MainActivity : AppCompatActivity(),
} else if (binding.pauseContainer.visibility == View.VISIBLE) {
// If pause menu is showing, handle as a resume
resumeGame()
} else if (binding.customizationContainer.visibility == View.VISIBLE) {
// If customization menu is showing, hide it
hideCustomizationMenu()
} else if (binding.gameOverContainer.visibility == View.VISIBLE) {
// If game over is showing, go back to title
hideGameOver()