Skip to content

Commit f9d21d2

Browse files
committed
Cache online mod list for fast load
1 parent f5946bc commit f9d21d2

File tree

4 files changed

+46
-17
lines changed

4 files changed

+46
-17
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ android/release/
144144

145145
# Transient Unciv files
146146
android/assets/GameSettings.json
147+
/android/assets/ModListCache.json
147148
android/assets/lasterror.txt
148149
android/assets/fonts/
149150
android/assets/maps/

Diff for: core/src/com/unciv/logic/files/UncivFiles.kt

+32-11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.unciv.models.metadata.GameSettings
2222
import com.unciv.models.metadata.doMigrations
2323
import com.unciv.models.metadata.isMigrationNecessary
2424
import com.unciv.models.ruleset.RulesetCache
25+
import com.unciv.ui.screens.modmanager.ModUIData
2526
import com.unciv.ui.screens.savescreens.Gzip
2627
import com.unciv.utils.Concurrency
2728
import com.unciv.utils.Log
@@ -34,6 +35,7 @@ private const val SAVE_FILES_FOLDER = "SaveFiles"
3435
private const val MULTIPLAYER_FILES_FOLDER = "MultiplayerGames"
3536
private const val AUTOSAVE_FILE_NAME = "Autosave"
3637
const val SETTINGS_FILE_NAME = "GameSettings.json"
38+
const val MOD_LIST_CACHE_FILE_NAME = "ModListCache.json"
3739

3840
class UncivFiles(
3941
/**
@@ -142,14 +144,6 @@ class UncivFiles(
142144
return deleteSave(getSave(gameName))
143145
}
144146

145-
/**
146-
* @return `true` if successful.
147-
* @throws SecurityException when delete access was denied
148-
*/
149-
fun deleteMultiplayerSave(gameName: String): Boolean {
150-
return deleteSave(getMultiplayerSave(gameName))
151-
}
152-
153147
/**
154148
* Only use this with a [FileHandle] obtained by one of the methods of this class!
155149
*
@@ -162,6 +156,7 @@ class UncivFiles(
162156
}
163157

164158
//endregion
159+
165160
//region Saving
166161

167162
fun saveGame(game: GameInfo, gameName: String, saveCompletionCallback: (Exception?) -> Unit = { if (it != null) throw it }): FileHandle {
@@ -253,9 +248,6 @@ class UncivFiles(
253248
return gameInfoFromString(gameData)
254249
}
255250

256-
fun loadGamePreviewByName(gameName: String) =
257-
loadGamePreviewFromFile(getMultiplayerSave(gameName))
258-
259251
fun loadGamePreviewFromFile(gameFile: FileHandle): GameInfoPreview {
260252
return json().fromJson(GameInfoPreview::class.java, gameFile) ?: throw emptyFile(gameFile)
261253
}
@@ -296,6 +288,7 @@ class UncivFiles(
296288

297289

298290
//endregion
291+
299292
//region Settings
300293

301294
private fun getGeneralSettingsFile(): FileHandle {
@@ -357,6 +350,34 @@ class UncivFiles(
357350
return game
358351
}
359352

353+
//endregion
354+
355+
//region Mod caching
356+
fun saveModCache(modDataList: List<ModUIData>){
357+
val file = getLocalFile(MOD_LIST_CACHE_FILE_NAME)
358+
try {
359+
json().toJson(modDataList, file)
360+
}
361+
catch (ex: Exception){ // Not a huge deal if this fails
362+
Log.error("Error saving mod cache", ex)
363+
}
364+
}
365+
366+
367+
fun loadModCache(): List<ModUIData>{
368+
val file = getLocalFile(MOD_LIST_CACHE_FILE_NAME)
369+
if (!file.exists()) return emptyList()
370+
try {
371+
return json().fromJsonFile(Array<ModUIData>::class.java, file)
372+
.toList()
373+
}
374+
catch (ex: Exception){ // Not a huge deal if this fails
375+
Log.error("Error loading mod cache", ex)
376+
return emptyList()
377+
}
378+
}
379+
380+
360381
//endregion
361382

362383
companion object {

Diff for: core/src/com/unciv/ui/screens/modmanager/ModManagementScreen.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ class ModManagementScreen private constructor(
109109

110110
// Enable re-sorting and syncing entries in 'installed' and 'repo search' ScrollPanes
111111
// Keep metadata and buttons in separate pools
112-
private val installedModInfo = previousInstalledMods ?: HashMap(10) // HashMap<String, ModUIData> inferred
113-
private val onlineModInfo = previousOnlineMods ?: HashMap(90) // HashMap<String, ModUIData> inferred
112+
private val installedModInfo = previousInstalledMods ?: HashMap(10)
113+
private val onlineModInfo = previousOnlineMods ?: HashMap(game.files.loadModCache().associateBy { it.name })
114114
private val modButtons: HashMap<ModUIData, ModDecoratedButton> = HashMap(100)
115115

116116
// cleanup - background processing needs to be stopped on exit and memory freed
@@ -349,6 +349,10 @@ class ModManagementScreen private constructor(
349349
onlineModsTable.add(getCachedModButton(mod)).row()
350350
}
351351

352+
Concurrency.run("Cache mod list"){
353+
game.files.saveModCache(onlineModInfo.values.toList())
354+
}
355+
352356
// Now the tasks after the 'page' of search results has been fully processed
353357
// The search has reached the last page!
354358
if (repoSearch.items.size < amountPerPage) {

Diff for: core/src/com/unciv/ui/screens/modmanager/ModUIData.kt

+7-4
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ import com.unciv.ui.components.fonts.Fonts
1212
* (This is important on resize - ModUIData are passed to the new screen)
1313
* Note it is guaranteed either ruleset or repo are non-null, never both.
1414
*/
15-
internal class ModUIData private constructor(
15+
class ModUIData private constructor(
1616
val name: String,
1717
val description: String,
18-
val ruleset: Ruleset?,
19-
val repo: GithubAPI.Repo?,
18+
val ruleset: Ruleset? = null,
19+
val repo: GithubAPI.Repo? = null,
2020
var isVisual: Boolean = false,
2121
var hasUpdate: Boolean = false
2222
) {
23+
// For deserialization from cache file
24+
constructor():this("","")
25+
2326
constructor(ruleset: Ruleset, isVisual: Boolean): this (
2427
ruleset.name,
2528
ruleset.getSummary().let {
@@ -46,7 +49,7 @@ internal class ModUIData private constructor(
4649
else -> ""
4750
}
4851

49-
fun matchesFilter(filter: ModManagementOptions.Filter): Boolean = when {
52+
internal fun matchesFilter(filter: ModManagementOptions.Filter): Boolean = when {
5053
!matchesCategory(filter) -> false
5154
filter.text.isEmpty() -> true
5255
name.contains(filter.text, true) -> true

0 commit comments

Comments
 (0)