mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
Local and/or jpg mod previews (#9394)
* Allow mod preview image to be a jpg * Allow preview images from WIP mods lacking github url * Wiki preview.jpg * Allow mod preview image to be a jpg - review
This commit is contained in:
parent
7f4b7bbd21
commit
1de866c7ed
@ -253,9 +253,11 @@ object Github {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun tryGetPreviewImage(modUrl:String, defaultBranch: String): Pixmap?{
|
fun tryGetPreviewImage(modUrl:String, defaultBranch: String): Pixmap?{
|
||||||
val fileLocation = "$modUrl/$defaultBranch/preview.png"
|
val fileLocation = "$modUrl/$defaultBranch/preview"
|
||||||
.replace("github.com", "raw.githubusercontent.com")
|
.replace("github.com", "raw.githubusercontent.com")
|
||||||
val file = download(fileLocation) ?: return null
|
val file = download("$fileLocation.jpg")
|
||||||
|
?: download("$fileLocation.png")
|
||||||
|
?: return null
|
||||||
val byteArray = file.readBytes()
|
val byteArray = file.readBytes()
|
||||||
val buffer = ByteBuffer.allocateDirect(byteArray.size).put(byteArray).position(0)
|
val buffer = ByteBuffer.allocateDirect(byteArray.size).put(byteArray).position(0)
|
||||||
return Pixmap(buffer)
|
return Pixmap(buffer)
|
||||||
|
@ -2,6 +2,7 @@ package com.unciv.ui.screens.pickerscreens
|
|||||||
|
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
import com.badlogic.gdx.graphics.Texture
|
import com.badlogic.gdx.graphics.Texture
|
||||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
@ -52,6 +53,7 @@ import com.unciv.utils.launchOnGLThread
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.nio.ByteBuffer
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,6 +66,18 @@ class ModManagementScreen(
|
|||||||
previousInstalledMods: HashMap<String, ModUIData>? = null,
|
previousInstalledMods: HashMap<String, ModUIData>? = null,
|
||||||
previousOnlineMods: HashMap<String, ModUIData>? = null
|
previousOnlineMods: HashMap<String, ModUIData>? = null
|
||||||
): PickerScreen(disableScroll = true), RecreateOnResize {
|
): PickerScreen(disableScroll = true), RecreateOnResize {
|
||||||
|
companion object {
|
||||||
|
// Tweakable constants
|
||||||
|
/** For preview.png */
|
||||||
|
const val maxAllowedPreviewImageSize = 200f
|
||||||
|
/** Github queries use this limit */
|
||||||
|
const val amountPerPage = 100
|
||||||
|
|
||||||
|
val modsToHideAsUrl by lazy {
|
||||||
|
val blockedModsFile = Gdx.files.internal("jsons/ManuallyBlockedMods.json")
|
||||||
|
json().fromJsonFile(Array<String>::class.java, blockedModsFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val modTable = Table().apply { defaults().pad(10f) }
|
private val modTable = Table().apply { defaults().pad(10f) }
|
||||||
private val scrollInstalledMods = AutoScrollPane(modTable)
|
private val scrollInstalledMods = AutoScrollPane(modTable)
|
||||||
@ -72,8 +86,6 @@ class ModManagementScreen(
|
|||||||
private val modActionTable = Table().apply { defaults().pad(10f) }
|
private val modActionTable = Table().apply { defaults().pad(10f) }
|
||||||
private val optionsManager = ModManagementOptions(this)
|
private val optionsManager = ModManagementOptions(this)
|
||||||
|
|
||||||
val amountPerPage = 100
|
|
||||||
|
|
||||||
private var lastSelectedButton: Button? = null
|
private var lastSelectedButton: Button? = null
|
||||||
private var lastSyncMarkedButton: Button? = null
|
private var lastSyncMarkedButton: Button? = null
|
||||||
private var selectedMod: Github.Repo? = null
|
private var selectedMod: Github.Repo? = null
|
||||||
@ -95,6 +107,7 @@ class ModManagementScreen(
|
|||||||
// cleanup - background processing needs to be stopped on exit and memory freed
|
// cleanup - background processing needs to be stopped on exit and memory freed
|
||||||
private var runningSearchJob: Job? = null
|
private var runningSearchJob: Job? = null
|
||||||
private var stopBackgroundTasks = false
|
private var stopBackgroundTasks = false
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
// make sure the worker threads will not continue trying their time-intensive job
|
// make sure the worker threads will not continue trying their time-intensive job
|
||||||
runningSearchJob?.cancel()
|
runningSearchJob?.cancel()
|
||||||
@ -349,14 +362,18 @@ class ModManagementScreen(
|
|||||||
* @param repo: the repository instance as received from the GitHub api
|
* @param repo: the repository instance as received from the GitHub api
|
||||||
*/
|
*/
|
||||||
private fun addModInfoToActionTable(repo: Github.Repo) {
|
private fun addModInfoToActionTable(repo: Github.Repo) {
|
||||||
addModInfoToActionTable(repo.html_url, repo.default_branch, repo.pushed_at, repo.owner.login, repo.size)
|
addModInfoToActionTable(
|
||||||
|
repo.name, repo.html_url, repo.default_branch,
|
||||||
|
repo.pushed_at, repo.owner.login, repo.size
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/** Recreate the information part of the right-hand column
|
/** Recreate the information part of the right-hand column
|
||||||
* @param modName: The mod name (name from the RuleSet)
|
* @param modName: The mod name (name from the RuleSet)
|
||||||
* @param modOptions: The ModOptions as enriched by us with GitHub metadata when originally downloaded
|
* @param modOptions: The ModOptions as enriched by us with GitHub metadata when originally downloaded
|
||||||
*/
|
*/
|
||||||
private fun addModInfoToActionTable(modOptions: ModOptions) {
|
private fun addModInfoToActionTable(modName: String, modOptions: ModOptions) {
|
||||||
addModInfoToActionTable(
|
addModInfoToActionTable(
|
||||||
|
modName,
|
||||||
modOptions.modUrl,
|
modOptions.modUrl,
|
||||||
modOptions.defaultBranch,
|
modOptions.defaultBranch,
|
||||||
modOptions.lastUpdated,
|
modOptions.lastUpdated,
|
||||||
@ -368,6 +385,7 @@ class ModManagementScreen(
|
|||||||
private val repoUrlToPreviewImage = HashMap<String, Texture?>()
|
private val repoUrlToPreviewImage = HashMap<String, Texture?>()
|
||||||
|
|
||||||
private fun addModInfoToActionTable(
|
private fun addModInfoToActionTable(
|
||||||
|
modName: String,
|
||||||
repoUrl: String,
|
repoUrl: String,
|
||||||
default_branch: String,
|
default_branch: String,
|
||||||
updatedAt: String,
|
updatedAt: String,
|
||||||
@ -380,6 +398,9 @@ class ModManagementScreen(
|
|||||||
|
|
||||||
val imageHolder = Table()
|
val imageHolder = Table()
|
||||||
|
|
||||||
|
if (repoUrl.isEmpty())
|
||||||
|
addLocalPreviewImage(imageHolder, modName)
|
||||||
|
else
|
||||||
addPreviewImage(imageHolder, repoUrl, default_branch)
|
addPreviewImage(imageHolder, repoUrl, default_branch)
|
||||||
|
|
||||||
modActionTable.add(imageHolder).row()
|
modActionTable.add(imageHolder).row()
|
||||||
@ -395,7 +416,7 @@ class ModManagementScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// offer link to open the repo itself in a browser
|
// offer link to open the repo itself in a browser
|
||||||
if (repoUrl != "") {
|
if (repoUrl.isNotEmpty()) {
|
||||||
modActionTable.add("Open Github page".toTextButton().onClick {
|
modActionTable.add("Open Github page".toTextButton().onClick {
|
||||||
Gdx.net.openURI(repoUrl)
|
Gdx.net.openURI(repoUrl)
|
||||||
}).row()
|
}).row()
|
||||||
@ -409,6 +430,15 @@ class ModManagementScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setTextureAsPreview(imageHolder: Table, texture: Texture) {
|
||||||
|
val cell = imageHolder.add(Image(texture))
|
||||||
|
val largestImageSize = max(texture.width, texture.height)
|
||||||
|
if (largestImageSize > maxAllowedPreviewImageSize) {
|
||||||
|
val resizeRatio = maxAllowedPreviewImageSize / largestImageSize
|
||||||
|
cell.size(texture.width * resizeRatio, texture.height * resizeRatio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun addPreviewImage(
|
private fun addPreviewImage(
|
||||||
imageHolder: Table,
|
imageHolder: Table,
|
||||||
repoUrl: String,
|
repoUrl: String,
|
||||||
@ -416,19 +446,10 @@ class ModManagementScreen(
|
|||||||
) {
|
) {
|
||||||
if (!repoUrl.startsWith("http")) return // invalid url
|
if (!repoUrl.startsWith("http")) return // invalid url
|
||||||
|
|
||||||
fun setTextureAsPreview(texture: Texture) {
|
|
||||||
val maxAllowedImageSize = 200f
|
|
||||||
val cell = imageHolder.add(Image(texture))
|
|
||||||
val largestImageSize = max(texture.width, texture.height)
|
|
||||||
if (largestImageSize > maxAllowedImageSize) {
|
|
||||||
val resizeRatio = maxAllowedImageSize / largestImageSize
|
|
||||||
cell.size(texture.width * resizeRatio, texture.height * resizeRatio)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (repoUrlToPreviewImage.containsKey(repoUrl)) {
|
if (repoUrlToPreviewImage.containsKey(repoUrl)) {
|
||||||
val texture = repoUrlToPreviewImage[repoUrl]
|
val texture = repoUrlToPreviewImage[repoUrl]
|
||||||
if (texture != null) setTextureAsPreview(texture)
|
if (texture != null) setTextureAsPreview(imageHolder, texture)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,11 +464,20 @@ class ModManagementScreen(
|
|||||||
val texture = Texture(imagePixmap)
|
val texture = Texture(imagePixmap)
|
||||||
imagePixmap.dispose()
|
imagePixmap.dispose()
|
||||||
repoUrlToPreviewImage[repoUrl] = texture
|
repoUrlToPreviewImage[repoUrl] = texture
|
||||||
setTextureAsPreview(texture)
|
setTextureAsPreview(imageHolder, texture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addLocalPreviewImage(imageHolder: Table, modName: String) {
|
||||||
|
// No concurrency, order of magnitude 20ms
|
||||||
|
val modFolder = Gdx.files.local("mods/$modName")
|
||||||
|
val previewFile = modFolder.child("preview.jpg").takeIf { it.exists() }
|
||||||
|
?: modFolder.child("preview.png").takeIf { it.exists() }
|
||||||
|
?: return
|
||||||
|
setTextureAsPreview(imageHolder, Texture(previewFile))
|
||||||
|
}
|
||||||
|
|
||||||
/** Create the special "Download from URL" button */
|
/** Create the special "Download from URL" button */
|
||||||
private fun getDownloadFromUrlButton(): TextButton {
|
private fun getDownloadFromUrlButton(): TextButton {
|
||||||
val downloadButton = "Download mod from URL".toTextButton()
|
val downloadButton = "Download mod from URL".toTextButton()
|
||||||
@ -586,7 +616,7 @@ class ModManagementScreen(
|
|||||||
selectedMod = null
|
selectedMod = null
|
||||||
modActionTable.clear()
|
modActionTable.clear()
|
||||||
// show mod information first
|
// show mod information first
|
||||||
addModInfoToActionTable(mod.modOptions)
|
addModInfoToActionTable(mod.name, mod.modOptions)
|
||||||
|
|
||||||
// offer 'permanent visual mod' toggle
|
// offer 'permanent visual mod' toggle
|
||||||
val visualMods = game.settings.visualMods
|
val visualMods = game.settings.visualMods
|
||||||
@ -727,10 +757,4 @@ class ModManagementScreen(
|
|||||||
|
|
||||||
override fun recreate(): BaseScreen = ModManagementScreen(installedModInfo, onlineModInfo)
|
override fun recreate(): BaseScreen = ModManagementScreen(installedModInfo, onlineModInfo)
|
||||||
|
|
||||||
companion object {
|
|
||||||
val modsToHideAsUrl by lazy {
|
|
||||||
val blockedModsFile = Gdx.files.internal("jsons/ManuallyBlockedMods.json")
|
|
||||||
json().fromJsonFile(Array<String>::class.java, blockedModsFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ When loading a mod, it needs to be in its own folder in `/mods` - this is how yo
|
|||||||
|
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
You can add an image that will be displayed to users in the mod management by adding a "preview.png" file.
|
You can add an image that will be displayed to users in the mod management by adding a "preview.jpg" _or_ "preview.png" file.
|
||||||
|
|
||||||
Existing mods can be found [here](https://github.com/topics/unciv-mod)!
|
Existing mods can be found [here](https://github.com/topics/unciv-mod)!
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user