diff --git a/app/src/main/java/com/droiddeck/launcher/runtime/BattleNet.kt b/app/src/main/java/com/droiddeck/launcher/runtime/BattleNet.kt
index fa58c26ea..a98e3d0cf 100644
--- a/app/src/main/java/com/droiddeck/launcher/runtime/BattleNet.kt
+++ b/app/src/main/java/com/droiddeck/launcher/runtime/BattleNet.kt
@@ -61,6 +61,9 @@ object BattleNet {
val STORE: List
get() = TITLES.distinctBy { it.code }.filter { it.uid != "d3cn" && it.code != "WoWC" && it.code != "WoWF" }
+ // Blizzard's China client installs some products under a CN uid; they are the same games and keep their store identity.
+ private val CN_UIDS = mapOf("s2_cn" to "s2", "osic" to "osi", "anbs_cn" to "anbs")
+
fun notInstalled(title: Title, installedIds: Collection) =
installedIds.mapNotNull { id -> id?.let(::title)?.code }.none { it == title.code }
@@ -164,8 +167,10 @@ object BattleNet {
internal fun title(uid: String): Title? {
val id = uid.lowercase()
TITLES.firstOrNull { it.uid == id }?.let { return it }
+ CN_UIDS[id]?.let { alias -> TITLES.firstOrNull { it.uid == alias }?.let { return it } }
val base = id.substringBeforeLast('_', "")
- return if (base.isNotEmpty() && id.substringAfterLast('_') in LOCALES) TITLES.firstOrNull { it.uid == base } else null
+ if (base.isEmpty() || id.substringAfterLast('_') !in LOCALES) return null
+ return TITLES.firstOrNull { it.uid == base } ?: CN_UIDS[base]?.let { alias -> TITLES.firstOrNull { it.uid == alias } }
}
internal fun titleForProduct(product: String): Title? {
diff --git a/app/src/test/java/com/droiddeck/launcher/runtime/BattleNetTest.kt b/app/src/test/java/com/droiddeck/launcher/runtime/BattleNetTest.kt
index 77800dc1e..c3d821d07 100644
--- a/app/src/test/java/com/droiddeck/launcher/runtime/BattleNetTest.kt
+++ b/app/src/test/java/com/droiddeck/launcher/runtime/BattleNetTest.kt
@@ -259,6 +259,7 @@ class BattleNetTest {
BattleNet.hostFolder(context, "Z:/root/Games/Stores/Battle.net/Hearthstone/"))
}
+
@Test fun wowForeverIsListedBesideRetailInTheSharedWorldOfWarcraftFolder() {
val pfx = File(BattleNet.prefix(context), "pfx").apply { mkdirs() }
val wow = File(pfx, "drive_c/Program Files (x86)/World of Warcraft").apply { mkdirs() }
@@ -329,6 +330,24 @@ class BattleNetTest {
assertEquals(listOf(File(wow, "_forever_")), BattleNet.games(context).map { it.folder })
db.writeBytes(message(forever, retail))
assertEquals(listOf(File(wow, "_forever_"), wow), BattleNet.games(context).map { it.folder })
+
+ @Test fun aGameInstalledUnderBlizzardsChineseUidIsStillListed() {
+ val pfx = File(BattleNet.prefix(context), "pfx").apply { mkdirs() }
+ File(pfx, "drive_c/ProgramData/Battle.net/Agent").mkdirs()
+ File(pfx, "drive_c/ProgramData/Battle.net/Agent/product.db").writeBytes(message(
+ field(1, message(field(1, "osic"), field(3, message(field(1, "Z:/root/Games/Stores/Battle.net/Diablo II Resurrected"))))),
+ field(1, message(field(1, "s2_cn"), field(3, message(field(1, "Z:/root/Games/Stores/Battle.net/StarCraft II"))))),
+ ))
+ for (folder in listOf("Diablo II Resurrected", "StarCraft II")) {
+ File(LinuxRuntime.rootDir(context), "root/Games/Stores/Battle.net/$folder").mkdirs()
+ }
+ val games = BattleNet.games(context)
+ assertEquals(listOf("osic", "s2_cn"), games.map { it.installUid })
+ assertEquals(listOf("osi", "s2"), games.map { it.uid })
+ assertEquals(listOf("Diablo II: Resurrected" to "OSI", "StarCraft II" to "S2"), games.map { it.name to it.code })
+ assertFalse(BattleNet.notInstalled(BattleNet.title("osi")!!, listOf("osic")))
+ assertFalse(BattleNet.notInstalled(BattleNet.title("s2")!!, games.map { it.installUid }))
+
}
@Test fun aGamesShortcutHasBattleNetLaunchItInItsPrefix() {