From 249e61969e2cebe9f9afaa1ab9ce4ae777e81cd1 Mon Sep 17 00:00:00 2001 From: BeZide93 Date: Sun, 2 Nov 2025 00:48:07 +0100 Subject: [PATCH] changed comments to english --- .../org/kenjinx/android/cheats/CheatFs.kt | 72 ++++++++++--------- .../java/org/kenjinx/android/cheats/ModFs.kt | 34 ++++----- .../org/kenjinx/android/views/HomeViews.kt | 30 ++++---- src/LibKenjinx/rd.xml | 4 +- src/Ryujinx.HLE/HOS/TamperMachine.cs | 10 +-- 5 files changed, 77 insertions(+), 73 deletions(-) diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/cheats/CheatFs.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/cheats/CheatFs.kt index bde41a778..a93277426 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/cheats/CheatFs.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/cheats/CheatFs.kt @@ -12,7 +12,7 @@ data class CheatItem(val buildId: String, val name: String) { val key get() = "$buildId-$name" } -/* -------- Pfade -------- */ +/* -------- Paths -------- */ private fun cheatsDirExternal(activity: Activity, titleId: String): File { val base = activity.getExternalFilesDir(null) // /storage/emulated/0/Android/data//files @@ -37,7 +37,7 @@ private fun parseCheatNames(text: String): List { .toList() } -/* -------- Public: Cheats laden -------- */ +/* -------- Public: Load cheats -------- */ fun loadCheatsFromDisk(activity: Activity, titleId: String): List { val dirs = allCheatDirs(activity, titleId) @@ -62,10 +62,10 @@ fun loadCheatsFromDisk(activity: Activity, titleId: String): List { .sortedWith(compareBy({ it.buildId.lowercase() }, { it.name.lowercase() })) } -/* -------- Public: Auswahl SOFORT auf Disk anwenden -------- */ +/* -------- Public: Apply selection IMMEDIATELY on disk -------- */ fun applyCheatSelectionOnDisk(activity: Activity, titleId: String, enabledKeys: Set) { - // Wir wählen genau EINE BUILDID-Datei (die „beste“), und schalten darin Sections. + // We pick exactly ONE BUILDID file (the “best”) and toggle sections within it. val dirs = allCheatDirs(activity, titleId) val allTxt = dirs.flatMap { d -> d.listFiles { f -> f.isFile && f.name.endsWith(".txt", ignoreCase = true) }?.toList() ?: emptyList() @@ -79,7 +79,7 @@ fun applyCheatSelectionOnDisk(activity: Activity, titleId: String, enabledKeys: val text = runCatching { buildFile.readText(Charset.forName("UTF-8")) }.getOrElse { "" } if (text.isEmpty()) return - // Enabled-Set normalisieren: Keys sind "-" + // Normalize enabled set: keys are "-" val enabledSections = enabledKeys.asSequence() .mapNotNull { key -> val dash = key.indexOf('-') @@ -97,7 +97,7 @@ fun applyCheatSelectionOnDisk(activity: Activity, titleId: String, enabledKeys: } } -/* -------- Implementierung: Auswahl anwenden (nur ';' als Kommentar) -------- */ +/* -------- Implementation: apply selection (use ';' only for comments) -------- */ private fun pickBestBuildFile(files: List): File { fun looksHexName(p: File): Boolean { @@ -121,8 +121,8 @@ private fun sectionNameFromHeader(line: String): String { } /** - * Entfernt EIN führendes Kommentarzeichen (';') + optionales Leerzeichen. - * Nur am absoluten Zeilenanfang (keine führenden Spaces erlaubt). + * Removes ONE leading comment marker (';') + optional space. + * Only at absolute column 0 (no leading spaces allowed). */ private fun uncommentOnce(raw: String): String { if (raw.isEmpty()) return raw @@ -132,8 +132,8 @@ private fun uncommentOnce(raw: String): String { } /** - * Kommentiert die Zeile aus, wenn sie nicht bereits mit ';' beginnt. - * Atmosphère nutzt ';' – das verwenden wir ausschließlich. + * Comments out the line if it doesn't already start with ';'. + * Atmosphère uses ';' — we strictly use that here as well. */ private fun commentOut(raw: String): String { val t = raw.trimStart() @@ -143,12 +143,12 @@ private fun commentOut(raw: String): String { } /** - * Schreibt die Datei neu: - * - Keine Marker einfügen - * - Pro Section den Body gemäß enabled/disabled (enabledSections) kommentieren/entkommentieren - * - Reine Kommentar-/Leerzeilen (nur ';') bleiben erhalten + * Rewrites the file: + * - Do not insert markers + * - For each section, comment/uncomment the body according to enabledSections + * - Preserve pure comment/blank lines (only ';') */ -// Hilfsfunktionen: trailing Blankzeilen trimmen / Header normalisieren +// Helpers: trim trailing blank lines / normalize header private fun trimTrailingBlankLines(lines: MutableList) { while (lines.isNotEmpty() && lines.last().trim().isEmpty()) { lines.removeAt(lines.lastIndex) @@ -156,18 +156,18 @@ private fun trimTrailingBlankLines(lines: MutableList) { } private fun joinHeaderBufferOnce(header: List): String { - // Header-Zeilen unverändert, aber trailing Blanks entfernen und genau 1 Leerzeile danach + // Keep header lines unchanged, but remove trailing blanks and insert exactly one blank line after val buf = header.toMutableList() trimTrailingBlankLines(buf) return if (buf.isEmpty()) "" else buf.joinToString("\n") + "\n\n" } /** - * Schreibt die Datei neu: - * - Keine Marker einfügen - * - Pro Section den Body gemäß enabled/disabled (enabledSections) kommentieren/entkommentieren - * - Reine Kommentar-/Leerzeilen bleiben erhalten - * - Zwischen Sections genau EINE Leerzeile, am Ende genau EIN Newline. + * Rewrites the file: + * - Do not insert markers + * - For each section, comment/uncomment the body according to enabledSections + * - Preserve pure comment/blank lines + * - Ensure exactly ONE blank line between sections, and exactly ONE trailing newline at EOF. */ private fun rewriteCheatFile(original: String, enabledSections: Set): String { val lines = original.replace("\uFEFF", "").lines() @@ -183,18 +183,18 @@ private fun rewriteCheatFile(original: String, enabledSections: Set): St fun flushCurrent() { val sec = currentSection ?: return - // trailing Blankzeilen im Block entfernen, damit keine doppelten Abstände wachsen + // Remove trailing blank lines in the block to avoid growing gaps trimTrailingBlankLines(currentBlock) val enabled = enabledSections.contains(sec.lowercase()) - // Zwischen Sections genau eine Leerzeile einfügen (aber nicht vor der ersten) + // Insert exactly one blank line between sections (but not before the first) if (wroteAnySection) out.append('\n') out.append('[').append(sec).append(']').append('\n') if (enabled) { - // Entkommentieren (nur ein führendes ';' an Spalte 0) + // Uncomment (only one leading ';' at column 0) for (l in currentBlock) { val trimmed = l.trim() if (trimmed.isEmpty() || (trimmed.startsWith(";") && trimmed.length <= 1)) { @@ -210,7 +210,7 @@ private fun rewriteCheatFile(original: String, enabledSections: Set): St } } } else { - // Disablen: alles, was nicht schon mit ';' beginnt und nicht leer ist, auskommentieren + // Disable: anything not starting with ';' and not blank gets commented out for (l in currentBlock) { val t = l.trim() if (t.isEmpty() || t.startsWith(";")) { @@ -242,20 +242,22 @@ private fun rewriteCheatFile(original: String, enabledSections: Set): St } flushCurrent() - // Header vorn einsetzen (mit genau einer Leerzeile danach, falls vorhanden) + // Prepend header (with exactly one blank line after, if present) val headerText = joinHeaderBufferOnce(headerBuffer) if (headerText.isNotEmpty()) { out.insert(0, headerText) } - // Globale Normalisierung: 3+ Newlines -> 2, und am Ende genau EIN '\n' - var result = out.toString() - .replace(Regex("\n{3,}"), "\n\n") // nie mehr als 1 Leerzeile zwischen Abschnitten - .trimEnd() + "\n" // genau ein Newline am Ende + // Global normalization: collapse 3+ newlines to 2, and ensure exactly ONE trailing '\n' + val result = out.toString() + .replace(Regex("\n{3,}"), "\n\n") // never more than 1 blank line between sections + .trimEnd() + "\n" // exactly one newline at the end return result } + private fun cheatsDirPreferredForWrite(activity: Activity, titleId: String): File { + // Preferred write location: external app-specific storage val dir = cheatsDirExternal(activity, titleId) if (!dir.exists()) dir.mkdirs() return dir @@ -285,12 +287,12 @@ private fun uniqueFile(targetDir: File, baseName: String): File { } /** - * Importiert eine .txt aus einem SAF-Uri in den Cheats-Ordner des Titels. - * Gibt das Zieldatei-Objekt zurück, wenn erfolgreich. + * Imports a .txt from a SAF Uri into the title's cheats folder. + * Returns the destination File on success. */ fun importCheatTxt(activity: Activity, titleId: String, source: Uri): Result { return runCatching { - // Lese-Rechte ggf. dauerhaft sichern + // Persist read permission if possible try { activity.contentResolver.takePersistableUriPermission( source, @@ -310,8 +312,8 @@ fun importCheatTxt(activity: Activity, titleId: String, source: Uri): Result/files/sdcard/atmosphere/contents @@ -18,7 +18,7 @@ private fun modsRootExternal(activity: Activity): File { } private fun modsTitleDir(activity: Activity, titleIdUpper: String): File { - // TITLEID muss groß geschrieben sein + // TITLEID must be uppercase return File(modsRootExternal(activity), titleIdUpper) } @@ -26,14 +26,14 @@ private fun modDir(activity: Activity, titleIdUpper: String, modName: String): F return File(modsTitleDir(activity, titleIdUpper), modName) } -/* -------- Auflisten & Löschen -------- */ +/* -------- List & Delete -------- */ fun listMods(activity: Activity, titleId: String): List { val titleIdUpper = titleId.trim().uppercase() val dir = modsTitleDir(activity, titleIdUpper) if (!dir.exists() || !dir.isDirectory) return emptyList() - return dir.listFiles { f -> f.isDirectory } // NAME-Ordner + return dir.listFiles { f -> f.isDirectory } // NAME folders ?.map { it.name } ?.sortedBy { it.lowercase() } ?: emptyList() @@ -67,7 +67,7 @@ data class ImportProgress( get() = if (totalBytes <= 0) 0f else (bytesRead.coerceAtMost(totalBytes).toFloat() / totalBytes.toFloat()) } -// NEU: Multi-Import. Top-Level-Ordner in der ZIP sind die Mod-Namen. +// NEW: Multi-import. Top-level folders inside the ZIP are treated as mod names. data class ImportModsResult( val imported: List, val ok: Boolean @@ -91,9 +91,9 @@ fun importModsZip( } } - // Für jeden Top-Level-Ordner (Mod-Name) einmalig vorbereiten (ggf. alten Ordner löschen). + // Prepare each top-level folder (mod name) once (delete existing folder if present). val preparedMods = mutableSetOf() - val importedMods = linkedSetOf() // Reihenfolge stabil + val importedMods = linkedSetOf() // stable order return try { activity.contentResolver.openInputStream(zipUri).use { raw -> @@ -103,15 +103,15 @@ fun importModsZip( val buffer = ByteArray(DEFAULT_BUFFER_SIZE) while (entry != null) { - val rawName = entry.name.replace('\\', '/') // normalisieren - // Sicherheitsfilter & leere Namen überspringen + val rawName = entry.name.replace('\\', '/') // normalize + // Safety filter & skip empty names if (rawName.isBlank() || rawName.startsWith("/") || rawName.contains("..")) { zis.closeEntry() entry = zis.nextEntry continue } - // Top-Level: erster Segment vor dem ersten '/' + // Top-level: first segment before the first '/' val slash = rawName.indexOf('/') val topLevel = if (slash > 0) rawName.substring(0, slash) else rawName if (topLevel.isBlank()) { @@ -120,18 +120,18 @@ fun importModsZip( continue } - // restlicher Pfad innerhalb des Mod-Ordners + // Remaining path inside the mod folder val relPath = if (slash >= 0 && slash + 1 < rawName.length) rawName.substring(slash + 1) else "" - // Nur Einträge verarbeiten, die innerhalb eines Modordners liegen (wir wollen NAME/... Strukturen) + // Only process entries that are inside a mod folder (we expect NAME/... structures) if (relPath.isBlank() && entry.isDirectory.not()) { - // Datei direkt im Top-Level (z.B. NAME.txt) ignorieren + // File directly at top level (e.g., NAME.txt) → ignore zis.closeEntry() entry = zis.nextEntry continue } - // Mod-Ordner vorbereiten (einmalig: ggf. alten Ordner entfernen) + // Prepare mod folder (once; remove old folder if present) if (preparedMods.add(topLevel)) { val modFolder = modDir(activity, titleIdUpper, topLevel) if (modFolder.exists()) modFolder.safeDeleteRecursively() @@ -139,9 +139,9 @@ fun importModsZip( importedMods += topLevel } - // Zielpfad: .../TITLEID// + // Destination path: .../TITLEID// val dest = if (relPath.isBlank()) { - // nur ein Ordner-Eintrag (NAME/ oder NAME/exefs/) + // just a directory entry (NAME/ or NAME/exefs/) File(modDir(activity, titleIdUpper, topLevel), "") } else { File(modDir(activity, titleIdUpper, topLevel), relPath) @@ -170,7 +170,7 @@ fun importModsZip( ImportModsResult(imported = importedMods.toList(), ok = importedMods.isNotEmpty()) } catch (t: Throwable) { Log.w("ModFs", "importModsZip failed: ${t.message}") - // Best effort: schon angelegte Mods sauber entfernen + // Best effort: clean up already created mod folders importedMods.forEach { name -> runCatching { modDir(activity, titleIdUpper, name).safeDeleteRecursively() } } diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/HomeViews.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/HomeViews.kt index ef7c796cc..406745f16 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/HomeViews.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/HomeViews.kt @@ -148,14 +148,14 @@ class HomeViews { val importBusy = remember { mutableStateOf(false) } val importStatusText = remember { mutableStateOf("") } - // Shortcut-Dialog-State + // Shortcut dialog state val showShortcutDialog = remember { mutableStateOf(false) } val shortcutName = remember { mutableStateOf("") } val context = LocalContext.current val activity = LocalContext.current as? Activity - // NEW: Cheats Import (.txt) + // NEW: Cheats import (.txt) val importCheatLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.OpenDocument() ) { uri: Uri? -> @@ -163,7 +163,7 @@ class HomeViews { val act = viewModel.activity val titleId = gm?.titleId ?: "" if (uri != null && act != null && titleId.isNotEmpty()) { - // nur .txt akzeptieren + // only accept .txt val okExt = runCatching { DocumentFile.fromSingleUri(act, uri)?.name?.lowercase()?.endsWith(".txt") == true }.getOrElse { false } @@ -175,7 +175,7 @@ class HomeViews { val res = importCheatTxt(act, titleId, uri) if (res.isSuccess) { Toast.makeText(act, "Imported: ${res.getOrNull()?.name}", Toast.LENGTH_SHORT).show() - // danach Liste aktualisieren + // then refresh list cheatsForSelected.value = loadCheatsFromDisk(act, titleId) } else { Toast.makeText(act, "Import failed: ${res.exceptionOrNull()?.message}", Toast.LENGTH_LONG).show() @@ -190,7 +190,7 @@ class HomeViews { val act = viewModel.activity val titleId = gm?.titleId ?: "" if (uri != null && act != null && titleId.isNotEmpty()) { - // Persist permission (lesen) + // Persist permission (read) try { act.contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) } catch (_: Exception) {} @@ -212,7 +212,7 @@ class HomeViews { "Copying… ${(prog.fraction * 100).toInt()}%" } - // Liste aktualisieren + // refresh list modsForSelected.value = listMods(act, titleId) importBusy.value = false @@ -519,7 +519,7 @@ class HomeViews { thread { showLoading.value = true - // NEW: Push Cheats vor dem Start (Auto-Start Pfad) + // NEW: Push cheats before start (auto-start path) val gm = viewModel.mainViewModel.loadGameModel.value!! val tId = gm.titleId ?: "" val act = viewModel.activity @@ -555,7 +555,7 @@ class HomeViews { IconButton(onClick = { if (viewModel.mainViewModel?.selected != null) { - // NEW: Push Cheats vor dem Start (Run-Button) + // NEW: Push cheats before start (Run button) val gmSel = viewModel.mainViewModel!!.selected!! val tId = gmSel.titleId ?: "" val act = viewModel.activity @@ -693,12 +693,12 @@ class HomeViews { modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { - // LINKS: Import .txt + // LEFT: Import .txt TextButton(onClick = { importCheatLauncher.launch(arrayOf("text/plain", "text/*", "*/*")) }) { Text("Import .txt") } - // RECHTS: Cancel + Save + // RIGHT: Cancel + Save Row { TextButton(onClick = { openCheatsDialog.value = false }) { Text("Cancel") } TextButton(onClick = { @@ -788,7 +788,7 @@ class HomeViews { modifier = Modifier.padding(bottom = 8.dp) ) - // Import-Zeile + // Import row Row( modifier = Modifier .fillMaxWidth() @@ -818,7 +818,7 @@ class HomeViews { ) } - // Liste der Mods + // List of mods if (modsForSelected.value.isEmpty()) { Text("No mods found for this title.") } else { @@ -865,7 +865,7 @@ class HomeViews { } } } - // --- Shortcut-Dialog + // --- Shortcut dialog if (showShortcutDialog.value) { val gm = viewModel.mainViewModel?.selected AlertDialog( @@ -972,7 +972,7 @@ class HomeViews { thread { showLoading.value = true - // NEW: Push Cheats vor dem Start + // NEW: Push cheats before start val tId = gameModel.titleId ?: "" val act = viewModel.activity @@ -1069,7 +1069,7 @@ class HomeViews { thread { showLoading.value = true - // NEW: Push Cheats vor dem Start + // NEW: Push cheats before start val tId = gameModel.titleId ?: "" val act = viewModel.activity diff --git a/src/LibKenjinx/rd.xml b/src/LibKenjinx/rd.xml index 416d790f1..89e273853 100644 --- a/src/LibKenjinx/rd.xml +++ b/src/LibKenjinx/rd.xml @@ -531,7 +531,7 @@ Dynamic="Required All" /> - + - + diff --git a/src/Ryujinx.HLE/HOS/TamperMachine.cs b/src/Ryujinx.HLE/HOS/TamperMachine.cs index 60f0583d1..7f52a7ed4 100644 --- a/src/Ryujinx.HLE/HOS/TamperMachine.cs +++ b/src/Ryujinx.HLE/HOS/TamperMachine.cs @@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS _programs.Enqueue(program); _programDictionary.TryAdd($"{buildId}-{name}", program); - // NEU: Standardmäßig einschalten (bei Android gibt es (noch) keine UI, die EnableCheats aufruft) + // NEW: Enable by default (on Android there's currently no UI that calls EnableCheats). program.IsEnabled = true; } @@ -141,11 +141,13 @@ namespace Ryujinx.HLE.HOS // Re-enqueue the tampering program because the process is still valid. _programs.Enqueue(program); - // NEU: Wenn der Cheat (noch) disabled ist – nur weiter rotieren, nicht ausführen. + + // NEW: If the cheat is (still) disabled, keep rotating but do not execute. if (!program.IsEnabled) { return true; } + Logger.Debug?.Print(LogClass.TamperMachine, $"Running tampering program {program.Name}"); try @@ -171,7 +173,7 @@ namespace Ryujinx.HLE.HOS // Logger.Debug?.Print(LogClass.TamperMachine, ex.Message); //} - // NEU: kompletter Stacktrace + // NEW: full stack trace Logger.Debug?.Print(LogClass.TamperMachine, ex.ToString()); } @@ -191,7 +193,7 @@ namespace Ryujinx.HLE.HOS } } - // Clear the input because player one is not conected. + // Clear the input because player one is not connected. Volatile.Write(ref _pressedKeys, 0); } }