diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt index 65cb652..e8c2049 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt @@ -13,15 +13,23 @@ fun AnimatedSpriteImage( characterId: String, animationType: DigimonAnimationType = DigimonAnimationType.IDLE, modifier: Modifier = Modifier, - contentScale: ContentScale = ContentScale.Fit + contentScale: ContentScale = ContentScale.Fit, + reloadMappings: Boolean = false ) { val context = LocalContext.current - val spriteManager = remember { BattleSpriteManager(context) } + val spriteManager = remember { IndividualSpriteManager(context) } val animationStateMachine = remember { DigimonAnimationStateMachine(characterId, context) } val coroutineScope = rememberCoroutineScope() var bitmap by remember { mutableStateOf(null) } + // Reload mappings when reloadMappings parameter changes + LaunchedEffect(reloadMappings) { + if (reloadMappings) { + animationStateMachine.reloadMappings() + } + } + // Start the animation when the component is first created LaunchedEffect(characterId) { coroutineScope.launch { @@ -41,17 +49,16 @@ fun AnimatedSpriteImage( } // Update sprite when animation state changes - LaunchedEffect(animationStateMachine.currentSpriteIndex) { - val spriteName = animationStateMachine.getCurrentSpriteName() - val atlasName = animationStateMachine.getCurrentAtlasName() + LaunchedEffect(animationStateMachine.currentFrameNumber) { + val frameNumber = animationStateMachine.getCurrentFrame() - println("Loading animated sprite: $spriteName from atlas: $atlasName") - bitmap = spriteManager.loadSprite(spriteName, atlasName) + println("Loading animated sprite frame: $frameNumber for character: $characterId") + bitmap = spriteManager.loadSpriteFrame(characterId, frameNumber) if (bitmap == null) { - println("Failed to load animated sprite: $spriteName from atlas: $atlasName") + println("Failed to load animated sprite frame: $frameNumber for character: $characterId") } else { - println("Successfully loaded animated sprite: $spriteName from atlas: $atlasName") + println("Successfully loaded animated sprite frame: $frameNumber for character: $characterId") } } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/AttackSpriteManager.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/AttackSpriteManager.kt index d44bb43..064350b 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/battle/AttackSpriteManager.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/AttackSpriteManager.kt @@ -31,8 +31,8 @@ class AttackSpriteManager(private val context: Context) { private val gson = Gson() private val characterDataCache = mutableMapOf() - // Base path for attack textures - private val attackTexturesPath = "battle_sprites/extracted_assets/extracted_atksprites" + // Base path for attack textures (updated for new folder structure) + private val attackTexturesPath = "battle_sprites/extracted_atksprites" fun getAttackSprite(characterId: String, isLarge: Boolean = false): Bitmap? { println("AttackSpriteManager: Getting attack sprite for characterId=$characterId, isLarge=$isLarge") diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt index 2042dbd..77028d3 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt @@ -6,7 +6,6 @@ import androidx.compose.runtime.setValue import kotlinx.coroutines.delay import android.content.Context import java.io.File -import com.google.gson.Gson enum class DigimonAnimationType { IDLE, @@ -25,7 +24,7 @@ enum class DigimonAnimationType { data class AnimationState( val type: DigimonAnimationType, - val spriteIndex: Int, // 00, 01, 02, etc. + val frameNumber: Int, // 1-12 for individual PNG files val duration: Long = 100L, // Duration in milliseconds val loop: Boolean = true ) @@ -37,30 +36,31 @@ class DigimonAnimationStateMachine( var currentAnimation by mutableStateOf(DigimonAnimationType.IDLE) private set - var currentSpriteIndex by mutableStateOf(0) + var currentFrameNumber by mutableStateOf(1) private set var isPlaying by mutableStateOf(false) private set - // Animation mapping based on m_Name values - private val mNameToAnimationType = mapOf( - "01" to DigimonAnimationType.IDLE, - "02" to DigimonAnimationType.IDLE2, - "03" to DigimonAnimationType.WALK, - "04" to DigimonAnimationType.WALK2, - "05" to DigimonAnimationType.RUN, - "06" to DigimonAnimationType.RUN2, - "07" to DigimonAnimationType.WORKOUT, - "08" to DigimonAnimationType.WORKOUT2, - "09" to DigimonAnimationType.HAPPY, - "10" to DigimonAnimationType.SLEEP, - "11" to DigimonAnimationType.ATTACK, - "12" to DigimonAnimationType.FLEE + // Direct mapping of frame numbers (1-12) to animation types + // This is based on the standard Digimon sprite frame order + private val frameToAnimationType = mapOf( + 1 to DigimonAnimationType.IDLE, + 2 to DigimonAnimationType.IDLE2, + 3 to DigimonAnimationType.WALK, + 4 to DigimonAnimationType.WALK2, + 5 to DigimonAnimationType.RUN, + 6 to DigimonAnimationType.RUN2, + 7 to DigimonAnimationType.WORKOUT, + 8 to DigimonAnimationType.WORKOUT2, + 9 to DigimonAnimationType.HAPPY, + 10 to DigimonAnimationType.SLEEP, + 11 to DigimonAnimationType.ATTACK, + 12 to DigimonAnimationType.FLEE ) - // Cache for sprite file mappings - private var spriteFileMappings: Map> = emptyMap() + // Reverse mapping for getting frame numbers for each animation type + private val animationTypeToFrames = frameToAnimationType.entries.groupBy({ it.value }, { it.key }) // Animation durations for each type private val animationDurations = mapOf( @@ -79,58 +79,8 @@ class DigimonAnimationStateMachine( ) init { - loadSpriteFileMappings() - } - - private fun loadSpriteFileMappings() { - try { - val spriteBaseDir = File(context.filesDir, "battle_sprites/extracted_assets/sprites") - val gson = Gson() - - val mappings = mutableMapOf>() - - // Initialize all animation types - DigimonAnimationType.values().forEach { animationType -> - mappings[animationType] = mutableListOf() - } - - println("Loading sprite mappings for character: $characterId") - - // Scan all sprite files for this character - val spriteFiles = spriteBaseDir.listFiles { file -> - file.name.startsWith("${characterId}_sprite_") && file.name.endsWith(".json") - } - - println("Found ${spriteFiles?.size ?: 0} sprite files for $characterId") - - spriteFiles?.forEach { spriteFile -> - println("Processing sprite file: ${spriteFile.name}") - val spriteDataJson = spriteFile.readText() - val spriteData = gson.fromJson(spriteDataJson, SpriteData::class.java) - - println(" m_Name: ${spriteData.m_Name}") - - // Get the animation type from m_Name - val animationType = mNameToAnimationType[spriteData.m_Name] - if (animationType != null) { - // Extract the sprite index from filename (e.g., "dim000_mon01_sprite_00.json" -> "00") - val spriteIndex = spriteFile.name.substringAfter("_sprite_").substringBefore(".json") - mappings[animationType]?.add(spriteIndex) - println(" Mapped to animation type: $animationType with sprite index: $spriteIndex") - } else { - println(" Unknown m_Name: ${spriteData.m_Name}") - } - } - - // Convert to immutable map - spriteFileMappings = mappings.mapValues { it.value.sorted() } - - println("Final sprite mappings for $characterId: $spriteFileMappings") - - } catch (e: Exception) { - println("Error loading sprite file mappings: ${e.message}") - e.printStackTrace() - } + println("Initialized DigimonAnimationStateMachine for character: $characterId") + println("Available animation types: ${animationTypeToFrames.keys}") } suspend fun playAnimation(animationType: DigimonAnimationType) { @@ -141,27 +91,22 @@ class DigimonAnimationStateMachine( currentAnimation = animationType isPlaying = true - val frameSequence = spriteFileMappings[animationType] ?: listOf("00") + val frameNumbers = animationTypeToFrames[animationType] ?: listOf(1) val duration = animationDurations[animationType] ?: 100L - // Ensure we have at least one frame - if (frameSequence.isEmpty()) { - println("Warning: No sprite files found for animation type $animationType") - currentSpriteIndex = 0 - return - } + println("Playing animation: $animationType with frames: $frameNumbers") // For non-looping animations like ATTACK, play once and return to IDLE if (animationType == DigimonAnimationType.ATTACK) { - currentSpriteIndex = frameSequence.firstOrNull()?.toIntOrNull() ?: 0 + currentFrameNumber = frameNumbers.firstOrNull() ?: 1 delay(duration) playAnimation(DigimonAnimationType.IDLE) } else { // For looping animations, cycle through frames var frameIndex = 0 while (isPlaying && currentAnimation == animationType) { - val spriteIndex = frameSequence[frameIndex % frameSequence.size] - currentSpriteIndex = spriteIndex.toIntOrNull() ?: 0 + val frameNumber = frameNumbers[frameIndex % frameNumbers.size] + currentFrameNumber = frameNumber delay(duration) frameIndex++ } @@ -177,26 +122,21 @@ class DigimonAnimationStateMachine( currentAnimation = DigimonAnimationType.IDLE isPlaying = true - val idleFrames = spriteFileMappings[DigimonAnimationType.IDLE] ?: listOf("00") - - val idle2Frames = spriteFileMappings[DigimonAnimationType.HAPPY] ?: listOf("08") + val idleFrames = animationTypeToFrames[DigimonAnimationType.IDLE] ?: listOf(1) + val idle2Frames = animationTypeToFrames[DigimonAnimationType.IDLE2] ?: listOf(2) // Combine frames for cycling idle animation val combinedFrames = (idleFrames + idle2Frames).distinct() - if (combinedFrames.isEmpty()) { - println("Warning: No idle sprite files found") - currentSpriteIndex = 0 - return - } + println("Playing idle animation with frames: $combinedFrames") val duration = animationDurations[DigimonAnimationType.IDLE] ?: 500L // Cycle through idle frames var frameIndex = 0 while (isPlaying && currentAnimation == DigimonAnimationType.IDLE) { - val spriteIndex = combinedFrames[frameIndex % combinedFrames.size] - currentSpriteIndex = spriteIndex.toIntOrNull() ?: 0 + val frameNumber = combinedFrames[frameIndex % combinedFrames.size] + currentFrameNumber = frameNumber delay(duration) frameIndex++ } @@ -206,11 +146,17 @@ class DigimonAnimationStateMachine( isPlaying = false } - fun getCurrentSpriteName(): String { - return "${characterId}_sprite_${String.format("%02d", currentSpriteIndex)}" + fun getCurrentFrame(): Int { + return currentFrameNumber } - fun getCurrentAtlasName(): String { + fun getCurrentCharacterId(): String { return characterId } + + // Method to reload mappings (useful for testing) + fun reloadMappings() { + println("Reloading mappings for character: $characterId") + // No need to reload since we use direct frame mapping + } } \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/IndividualSpriteManager.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/IndividualSpriteManager.kt new file mode 100644 index 0000000..f4b0d25 --- /dev/null +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/IndividualSpriteManager.kt @@ -0,0 +1,142 @@ +package com.github.nacabaro.vbhelper.battle + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import java.io.File + +class IndividualSpriteManager(private val context: Context) { + private val spriteCache = mutableMapOf() + + // Base directory where individual sprite PNGs are stored + private val spriteBaseDir = File(context.filesDir, "battle_sprites/extracted_assets/sprites") + + /** + * Load a specific sprite frame for a character + * @param characterId The character ID (e.g., "dim012_mon03") + * @param frameNumber The frame number (1-12) + * @return Bitmap of the sprite frame, or null if not found + */ + fun loadSpriteFrame(characterId: String, frameNumber: Int): Bitmap? { + val cacheKey = "${characterId}_frame_${frameNumber}" + + // Check cache first + if (spriteCache.containsKey(cacheKey)) { + return spriteCache[cacheKey] + } + + // Debug: Check if base directory exists + if (!spriteBaseDir.exists()) { + println("Sprite base directory does not exist: ${spriteBaseDir.absolutePath}") + return null + } + + try { + // Construct the sprite file path + val spriteFileName = "${characterId}_${String.format("%02d", frameNumber)}.png" + val spriteFile = File(spriteBaseDir, "$characterId/$spriteFileName") + + if (!spriteFile.exists()) { + println("Sprite file not found: ${spriteFile.absolutePath}") + return null + } + + // Load the PNG file directly + val bitmap = BitmapFactory.decodeFile(spriteFile.absolutePath) + if (bitmap == null) { + println("Failed to decode sprite file: ${spriteFile.absolutePath}") + return null + } + + println("Successfully loaded sprite frame: $spriteFileName (${bitmap.width}x${bitmap.height})") + + // Cache the result + spriteCache[cacheKey] = bitmap + + return bitmap + + } catch (e: Exception) { + println("Error loading sprite frame: ${e.message}") + e.printStackTrace() + return null + } + } + + /** + * Get all available sprite frames for a character + * @param characterId The character ID + * @return List of frame numbers (1-12) that exist for this character + */ + fun getAvailableFrames(characterId: String): List { + try { + val characterDir = File(spriteBaseDir, characterId) + if (!characterDir.exists()) { + println("Character directory not found: ${characterDir.absolutePath}") + return emptyList() + } + + val spriteFiles = characterDir.listFiles { file -> + file.name.startsWith("${characterId}_") && file.name.endsWith(".png") + } ?: emptyArray() + + return spriteFiles.mapNotNull { file -> + // Extract frame number from filename (e.g., "dim012_mon03_01.png" -> 1) + val frameNumberStr = file.name.substringAfter("_").substringBefore(".png") + frameNumberStr.toIntOrNull() + }.sorted() + + } catch (e: Exception) { + println("Error getting available frames: ${e.message}") + e.printStackTrace() + return emptyList() + } + } + + /** + * Get all available characters + * @return List of character IDs that have sprite directories + */ + fun getAvailableCharacters(): List { + try { + if (!spriteBaseDir.exists()) { + return emptyList() + } + + val characterDirs = spriteBaseDir.listFiles { file -> + file.isDirectory && file.name.matches(Regex("dim\\d+_mon\\d+.*")) + } ?: emptyArray() + + return characterDirs.map { it.name }.sorted() + + } catch (e: Exception) { + println("Error getting available characters: ${e.message}") + e.printStackTrace() + return emptyList() + } + } + + /** + * Clear the sprite cache + */ + fun clearCache() { + spriteCache.clear() + } + + /** + * Check if a character has sprite files + * @param characterId The character ID to check + * @return true if the character has sprite files, false otherwise + */ + fun hasCharacterSprites(characterId: String): Boolean { + val characterDir = File(spriteBaseDir, characterId) + if (!characterDir.exists()) { + return false + } + + val spriteFiles = characterDir.listFiles { file -> + file.name.startsWith("${characterId}_") && file.name.endsWith(".png") + } ?: emptyArray() + + return spriteFiles.isNotEmpty() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteFileManager.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteFileManager.kt index 0298f3d..5dd3699 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteFileManager.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteFileManager.kt @@ -9,26 +9,90 @@ class SpriteFileManager(private val context: Context) { fun copySpriteFilesToInternalStorage() { try { - // Create the base directory for extracted_assets - val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets") - if (!extractedAssetsDir.exists()) { - extractedAssetsDir.mkdirs() + println("Starting sprite file copy process...") + + // Debug: List what's in the assets directory + val assetManager = context.assets + val battleSpritesFiles = assetManager.list("battle_sprites") + println("battle_sprites directory in assets contains: ${battleSpritesFiles?.joinToString(", ")}") + + val extractedAssetsFiles = assetManager.list("battle_sprites/extracted_assets") + println("battle_sprites/extracted_assets directory in assets contains: ${extractedAssetsFiles?.joinToString(", ")}") + + // Check specifically for extracted_atksprites in assets (now directly under battle_sprites) + val atkspritesInAssets = assetManager.list("battle_sprites/extracted_atksprites") + println("extracted_atksprites in assets contains: ${atkspritesInAssets?.size ?: 0} files") + if (atkspritesInAssets != null && atkspritesInAssets.isNotEmpty()) { + println("First few attack files in assets: ${atkspritesInAssets.take(5).joinToString(", ")}") } - // Create the base directory for extracted_digimon_stats - val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats") - if (!extractedStatsDir.exists()) { - extractedStatsDir.mkdirs() + // Check for extracted_battlebgs in assets (now directly under battle_sprites) + val battlebgsInAssets = assetManager.list("battle_sprites/extracted_battlebgs") + println("extracted_battlebgs in assets contains: ${battlebgsInAssets?.size ?: 0} files") + if (battlebgsInAssets != null && battlebgsInAssets.isNotEmpty()) { + println("First few battle background files in assets: ${battlebgsInAssets.take(5).joinToString(", ")}") } - // Copy extracted_assets files from assets to internal storage - copyAssetDirectory("battle_sprites/extracted_assets", extractedAssetsDir) + // Try to list all possible subdirectories in battle_sprites + println("Checking all possible subdirectories in battle_sprites...") + battleSpritesFiles?.forEach { subdir -> + try { + val subdirFiles = assetManager.list("battle_sprites/$subdir") + println(" $subdir contains: ${subdirFiles?.size ?: 0} files") + if (subdirFiles != null && subdirFiles.isNotEmpty()) { + println(" First few files: ${subdirFiles.take(3).joinToString(", ")}") + } + } catch (e: Exception) { + println(" Error listing $subdir: ${e.message}") + } + } - // Copy extracted_digimon_stats files from assets to internal storage - copyAssetDirectory("battle_sprites/extracted_digimon_stats", extractedStatsDir) + // Create the base directory for battle_sprites + val battleSpritesDir = File(context.filesDir, "battle_sprites") + if (!battleSpritesDir.exists()) { + battleSpritesDir.mkdirs() + println("Created battle_sprites directory: ${battleSpritesDir.absolutePath}") + } else { + println("battle_sprites directory already exists: ${battleSpritesDir.absolutePath}") + } - println("Sprite files copied successfully to: ${extractedAssetsDir.absolutePath}") - println("Stats files copied successfully to: ${extractedStatsDir.absolutePath}") + // Copy all subdirectories from battle_sprites assets to internal storage + println("Copying all battle_sprites subdirectories...") + battleSpritesFiles?.forEach { subdir -> + val sourcePath = "battle_sprites/$subdir" + val targetDir = File(battleSpritesDir, subdir) + println("Copying $sourcePath to ${targetDir.absolutePath}") + copyAssetDirectory(sourcePath, targetDir) + } + + println("Sprite files copied successfully to: ${battleSpritesDir.absolutePath}") + + // Verify that attack sprites were copied + val atkspritesDir = File(battleSpritesDir, "extracted_atksprites") + if (atkspritesDir.exists()) { + val attackFiles = atkspritesDir.listFiles() + println("Attack sprites directory exists with ${attackFiles?.size ?: 0} files") + if (attackFiles != null && attackFiles.isNotEmpty()) { + println("First few attack files: ${attackFiles.take(5).map { it.name }}") + } + } else { + println("WARNING: extracted_atksprites directory does not exist!") + // List what's actually in the battle_sprites directory + val battleSpritesContents = battleSpritesDir.listFiles() + println("battle_sprites directory contains: ${battleSpritesContents?.map { it.name }?.joinToString(", ")}") + } + + // Verify that battle backgrounds were copied + val battlebgsDir = File(battleSpritesDir, "extracted_battlebgs") + if (battlebgsDir.exists()) { + val bgFiles = battlebgsDir.listFiles() + println("Battle backgrounds directory exists with ${bgFiles?.size ?: 0} files") + if (bgFiles != null && bgFiles.isNotEmpty()) { + println("First few battle background files: ${bgFiles.take(5).map { it.name }}") + } + } else { + println("WARNING: extracted_battlebgs directory does not exist!") + } } catch (e: Exception) { println("Error copying sprite files: ${e.message}") @@ -41,6 +105,9 @@ class SpriteFileManager(private val context: Context) { val assetManager = context.assets val files = assetManager.list(assetPath) ?: return + println("Copying asset directory: $assetPath (${files.size} items)") + println("Files found: ${files.joinToString(", ")}") + for (file in files) { val assetFilePath = if (assetPath.isEmpty()) file else "$assetPath/$file" val targetFile = File(targetDir, file) @@ -50,21 +117,50 @@ class SpriteFileManager(private val context: Context) { targetFile.parentFile!!.mkdirs() } - // Check if it's a directory - val subFiles = assetManager.list(assetFilePath) - if (subFiles != null && subFiles.isNotEmpty()) { - // It's a directory, create it and copy contents - if (!targetFile.exists()) { - targetFile.mkdirs() + // Check if it's a directory by trying to list its contents + try { + val subFiles = assetManager.list(assetFilePath) + if (subFiles != null && subFiles.isNotEmpty()) { + // It's a directory, create it and copy contents + println("Copying subdirectory: $assetFilePath (${subFiles.size} files)") + if (!targetFile.exists()) { + targetFile.mkdirs() + } + copyAssetDirectory(assetFilePath, targetFile) + } else { + // It's a file, copy it + copyAssetFile(assetFilePath, targetFile) } - copyAssetDirectory(assetFilePath, targetFile) - } else { - // It's a file, copy it + } catch (e: Exception) { + // If we can't list contents, it's probably a file + println("Treating $assetFilePath as file (could not list contents)") copyAssetFile(assetFilePath, targetFile) } } + + // Special handling for extracted_atksprites - try to copy it directly if it wasn't found + if (assetPath == "battle_sprites/extracted_assets") { + println("Special handling: Checking for extracted_atksprites directory...") + try { + val atkspritesFiles = assetManager.list("battle_sprites/extracted_assets/extracted_atksprites") + if (atkspritesFiles != null && atkspritesFiles.isNotEmpty()) { + println("Found extracted_atksprites with ${atkspritesFiles.size} files") + val atkspritesDir = File(targetDir, "extracted_atksprites") + if (!atkspritesDir.exists()) { + atkspritesDir.mkdirs() + } + copyAssetDirectory("battle_sprites/extracted_assets/extracted_atksprites", atkspritesDir) + } else { + println("extracted_atksprites directory not found in assets") + } + } catch (e: Exception) { + println("Error checking extracted_atksprites: ${e.message}") + } + } + } catch (e: Exception) { println("Error copying asset directory $assetPath: ${e.message}") + e.printStackTrace() } } @@ -84,34 +180,34 @@ class SpriteFileManager(private val context: Context) { } fun checkSpriteFilesExist(): Boolean { - val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets") - val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats") + val battleSpritesDir = File(context.filesDir, "battle_sprites") + val extractedAssetsDir = File(battleSpritesDir, "extracted_assets") + val extractedStatsDir = File(battleSpritesDir, "extracted_digimon_stats") + val atkspritesDir = File(battleSpritesDir, "extracted_atksprites") + val battlebgsDir = File(battleSpritesDir, "extracted_battlebgs") + val battleSpritesExist = battleSpritesDir.exists() && battleSpritesDir.listFiles()?.isNotEmpty() == true val assetsExist = extractedAssetsDir.exists() && extractedAssetsDir.listFiles()?.isNotEmpty() == true val statsExist = extractedStatsDir.exists() && extractedStatsDir.listFiles()?.isNotEmpty() == true + val atkspritesExist = atkspritesDir.exists() && atkspritesDir.listFiles()?.isNotEmpty() == true + val battlebgsExist = battlebgsDir.exists() && battlebgsDir.listFiles()?.isNotEmpty() == true - return assetsExist && statsExist + println("Checking sprite files exist:") + println(" battle_sprites exists: $battleSpritesExist") + println(" extracted_assets exists: $assetsExist") + println(" extracted_digimon_stats exists: $statsExist") + println(" extracted_atksprites exists: $atkspritesExist") + println(" extracted_battlebgs exists: $battlebgsExist") + + return battleSpritesExist && assetsExist && statsExist && atkspritesExist && battlebgsExist } fun clearSpriteFiles() { try { - val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets") - val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats") - - if (extractedAssetsDir.exists()) { - deleteDirectory(extractedAssetsDir) - println("Cleared extracted_assets directory") - } - - if (extractedStatsDir.exists()) { - deleteDirectory(extractedStatsDir) - println("Cleared extracted_digimon_stats directory") - } - - // Also clear the battle_sprites directory if it's empty val battleSpritesDir = File(context.filesDir, "battle_sprites") - if (battleSpritesDir.exists() && battleSpritesDir.listFiles()?.isEmpty() == true) { - battleSpritesDir.delete() + + if (battleSpritesDir.exists()) { + deleteDirectory(battleSpritesDir) println("Cleared battle_sprites directory") } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteImage.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteImage.kt index 7956511..f7d4430 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteImage.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/SpriteImage.kt @@ -6,34 +6,33 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import com.github.nacabaro.vbhelper.battle.BattleSpriteManager @Composable fun SpriteImage( - spriteName: String, - atlasName: String, + characterId: String, + frameNumber: Int, modifier: Modifier = Modifier, contentScale: ContentScale = ContentScale.Fit ) { val context = LocalContext.current - val spriteManager = remember { BattleSpriteManager(context) } + val spriteManager = remember { IndividualSpriteManager(context) } var bitmap by remember { mutableStateOf(null) } - LaunchedEffect(spriteName, atlasName) { - println("Loading sprite: $spriteName from atlas: $atlasName") - bitmap = spriteManager.loadSprite(spriteName, atlasName) + LaunchedEffect(characterId, frameNumber) { + println("Loading sprite frame: $frameNumber for character: $characterId") + bitmap = spriteManager.loadSpriteFrame(characterId, frameNumber) if (bitmap == null) { - println("Failed to load sprite: $spriteName from atlas: $atlasName") + println("Failed to load sprite frame: $frameNumber for character: $characterId") } else { - println("Successfully loaded sprite: $spriteName from atlas: $atlasName") + println("Successfully loaded sprite frame: $frameNumber for character: $characterId") } } bitmap?.let { bmp -> Image( bitmap = bmp.asImageBitmap(), - contentDescription = "Sprite: $spriteName", + contentDescription = "Sprite: $characterId frame $frameNumber", modifier = modifier, contentScale = contentScale ) diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt index 10afc2f..4582e3e 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt @@ -45,7 +45,6 @@ import com.github.nacabaro.vbhelper.battle.APIBattleCharacter import android.util.Log import com.github.nacabaro.vbhelper.components.TopBanner import com.github.nacabaro.vbhelper.battle.RetrofitHelper -import com.github.nacabaro.vbhelper.battle.SpriteImage import com.github.nacabaro.vbhelper.battle.AttackSpriteImage import com.github.nacabaro.vbhelper.battle.SpriteFileManager import com.github.nacabaro.vbhelper.battle.ArenaBattleSystem @@ -286,7 +285,8 @@ fun PlayerBattleView( modifier = Modifier .size(80.dp) .scale(-1f, 1f), // Flip player Digimon horizontally - contentScale = ContentScale.Fit + contentScale = ContentScale.Fit, + reloadMappings = false ) // Attack sprite visibility and positioning based on attack phase @@ -500,7 +500,8 @@ fun OpponentBattleView( characterId = activeCharacter?.charaId ?: "dim011_mon01", animationType = animationType, modifier = Modifier.size(80.dp), - contentScale = ContentScale.Fit + contentScale = ContentScale.Fit, + reloadMappings = false ) // Attack sprite visibility and positioning based on attack phase @@ -642,12 +643,13 @@ fun BattlesScreen() { // Initialize sprite files on first load LaunchedEffect(Unit) { + println("BATTLESCREEN: LaunchedEffect triggered - checking sprite files...") val spriteFileManager = SpriteFileManager(context) if (!spriteFileManager.checkSpriteFilesExist()) { - println("Copying sprite files to internal storage...") + println("BATTLESCREEN: Copying sprite files to internal storage...") spriteFileManager.copySpriteFilesToInternalStorage() } else { - println("Sprite files already exist in internal storage") + println("BATTLESCREEN: Sprite files already exist in internal storage") } } @@ -856,7 +858,8 @@ fun BattlesScreen() { characterId = testCharacterId, animationType = currentTestAnimation, modifier = Modifier.size(120.dp), - contentScale = ContentScale.Fit + contentScale = ContentScale.Fit, + reloadMappings = false ) Spacer(modifier = Modifier.height(16.dp))