Skip to content

Commit

Permalink
Refactor code to use the new configuration store.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lymia committed Dec 17, 2023
1 parent 028c061 commit 7248edc
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
# Translation file for English

# Shown when the user's operating system is not supported. In practice, something Civ V doesn't run on or a Mac.
error.unknownplatform = Your operating system is not supported by MPPatch.
error.unknown_platform = Your operating system is not supported by MPPatch.

# Shown when the user's operating system is macOS, which is not currently supported.
error.macos_support = macOS is not currently supported by MPPatch.\n\
Support is planned for a future version, but does not work right now.

# Shown when an unexpected error occurs.
error.genericerror = An unexpected error occured:\n{0}
Expand Down
37 changes: 24 additions & 13 deletions src/main/scala/moe/lymia/mppatch/ui/ConfigurationStore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import play.api.libs.json.Writes.*
import java.nio.file.{Path, Paths}
import java.util.Locale
import javax.swing.JFrame
import scala.collection.mutable

object ConfigurationStore extends LaunchFrameError {
private val prefs = java.util.prefs.Preferences.userNodeForPackage(getClass)
Expand All @@ -56,17 +57,18 @@ object ConfigurationStore extends LaunchFrameError {
}

private val configVersion = new ConfigKey[Int]("installer_config_version")
val installationDirs = new ConfigKey[Seq[String]]("installer_v1_installation_dirs", Seq())
val installationDirs = new ConfigKey[Set[String]]("installer_v1_installation_dirs", Set())
val suppressedDirs = new ConfigKey[Set[String]]("installer_v1_suppressed_dirs", Set())
def installationConf(path: Path) = {
val canonical = path.toRealPath().toString
new ConfigKey[InstallationConfiguration](s"installer_v1_conf|$canonical")
new ConfigKey[InstallationConfiguration](s"installer_v1_conf|$canonical", InstallationConfiguration.default)
}

val legacyInstallationDirectory: ConfigKey[String] = new RawStringConfigKey("installationDirectory")
val legacyEnableDebug: ConfigKey[Boolean] = new ConfigKey("enableDebug", false)
val legacyEnableLogging: ConfigKey[Boolean] = new ConfigKey("enableLogging", true)
val legacyEnableMultiplayerPatch: ConfigKey[Boolean] = new ConfigKey("enableMultiplayerPatch", true)
val legacyEnableLuaJIT: ConfigKey[Boolean] = new ConfigKey("enableLuaJIT", true)
private val legacyInstallationDirectory = new RawStringConfigKey("installationDirectory")
private val legacyEnableDebug = new ConfigKey("enableDebug", false)
private val legacyEnableLogging = new ConfigKey("enableLogging", true)
private val legacyEnableMultiplayerPatch = new ConfigKey("enableMultiplayerPatch", true)
private val legacyEnableLuaJIT = new ConfigKey("enableLuaJIT", true)

private def hasLegacyValues: Boolean =
legacyInstallationDirectory.hasValue || legacyEnableDebug.hasValue || legacyEnableLogging.hasValue ||
Expand All @@ -77,20 +79,29 @@ object ConfigurationStore extends LaunchFrameError {
val defaultDirectory = legacyInstallationDirectory.valueOption match {
case Some(x) =>
val realPath = Paths.get(x).toRealPath().toString
installationDirs.value = installationDirs.value :+ realPath
installationDirs.value = installationDirs.value + realPath
Some(Paths.get(x))
case None =>
val _ = installationDirs.value // make sure the key exists, but don't do anything else
findDefaultDirectory
}
defaultDirectory match {
case Some(defaultDirectory) =>
val seq = mutable.HashSet.empty[String]
if (legacyEnableDebug.value) seq.add("debug")
if (legacyEnableLogging.value) seq.add("logging")
if (legacyEnableMultiplayerPatch.value) seq.add("multiplayer")
if (legacyEnableLuaJIT.value) seq.add("luajit")
installationConf(defaultDirectory).value = InstallationConfiguration(
enableDebug = legacyEnableDebug.value,
enableLogging = legacyEnableLogging.value,
enableMultiplayerPatch = legacyEnableMultiplayerPatch.value,
enableLuaJit = legacyEnableLuaJIT.value
isManuallyAdded = legacyInstallationDirectory.hasValue,
packages = seq.toSet
)

legacyInstallationDirectory.clear()
legacyEnableDebug.clear()
legacyEnableLogging.clear()
legacyEnableMultiplayerPatch.clear()
legacyEnableLuaJIT.clear()
case _ =>
}
} else if (configVersion.hasValue && configVersion.value != 1) {
Expand All @@ -100,6 +111,6 @@ object ConfigurationStore extends LaunchFrameError {
throw new InstallerException("Cancelling configuration downgrade", null)
}
} else {
// do nothing
configVersion.value = 1
}
}
41 changes: 0 additions & 41 deletions src/main/scala/moe/lymia/mppatch/ui/InstallationManager.scala

This file was deleted.

21 changes: 14 additions & 7 deletions src/main/scala/moe/lymia/mppatch/ui/MPPatchInstaller.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import moe.lymia.mppatch.util.{Logger, SimpleLogger, VersionInfo}

import java.io.{File, FileOutputStream, OutputStreamWriter, PrintWriter}
import java.nio.charset.StandardCharsets
import java.nio.file.Path
import java.nio.file.{Files, Path}
import java.text.DateFormat
import java.util.Locale
import javax.swing.{JFrame, JOptionPane, UIManager}
Expand Down Expand Up @@ -116,7 +116,7 @@ object MPPatchInstaller extends LaunchFrameError {

// check runtime environment
if (isAppImage) {
log.info("Running from appimage")
log.info("Running from .AppImage")
log.info(f"AppImage binary: ${appImageFileLocation.get}")
log.info(f"AppImage directory: ${appImageContents.get}")
} else if (isNsis) {
Expand All @@ -126,7 +126,7 @@ object MPPatchInstaller extends LaunchFrameError {
} else {
log.info("Running from .jar")
}
log.info(f"Platform: ${PlatformType.currentPlatform}")
log.info(f"Platform: ${platform.platformName}")
log.info(f"Base directory: ${baseDirectory}")
log.logRaw("")

Expand Down Expand Up @@ -159,11 +159,18 @@ object MPPatchInstaller extends LaunchFrameError {
}
}

lazy val platform = PlatformType.currentPlatform match {
case PlatformType.Win32 => Platform(PlatformType.Win32).get
case PlatformType.MacOS => error("error.macos_support")
case PlatformType.Linux => Platform(PlatformType.Linux).get
case _ => error("error.unknown_platform")
}

lazy val defaultPackageSource = ResourceDataSource("builtin_patch")

private def defaultCivilizationPath: Option[Path] = {
val pkg = new PatchPackage(ResourceDataSource("builtin_patch"))
val platform = Platform(PlatformType.currentPlatform).get
val validPaths =
for (path <- platform.defaultSystemPaths if pkg.detectInstallationPlatform(path).isDefined) yield path
val pkg = new PatchPackage(defaultPackageSource)
val validPaths = for (path <- platform.defaultSystemPaths if new Installation(path).isValid(pkg)) yield path
validPaths.headOption
}
}
39 changes: 9 additions & 30 deletions src/main/scala/moe/lymia/mppatch/ui/MainFrame.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,41 +37,31 @@ class MainFrame(val locale: Locale) extends FrameBase[JFrame] {
protected var targetVersion: JTextField = _
protected var currentStatus: JTextField = _

private def packages = {
val logging = if (ConfigurationStore.legacyEnableLogging.value) Set("logging") else Set[String]()
val multiplayer = if (ConfigurationStore.legacyEnableMultiplayerPatch.value) Set("multiplayer") else Set[String]()
val luajit = if (ConfigurationStore.legacyEnableLuaJIT.value) Set("luajit") else Set[String]()
val debug = if (ConfigurationStore.legacyEnableDebug.value) Set("debug") else Set[String]()
debug ++ multiplayer ++ luajit ++ logging
}

private val platform = Platform.currentPlatform.getOrElse(error("error.unknownplatform"))
private def checkPath(path: Path) =
Files.exists(path) && Files.isDirectory(path) &&
patchPackage.detectInstallationPlatform(path).isDefined
private def resolvePaths(paths: Seq[Path]) = paths.find(checkPath)
private val installationManager = new InstallationManager()

private val syncLock = new Object
private var patchPackage: PatchPackage = _
private var patchPackage: PatchPackage = _
private var isUserChange = false
private var isValid = false
private var installer: Option[PatchInstaller] = None

private def getInstallerUnsafe = installer.getOrElse(sys.error("installer does not exist"))
private def installation = new Installation(getInstallerUnsafe.basePath)
private def packages = installation.config.packages

def getPatch = patchPackage
def getInstaller = installer
def changeInstaller(path: Path, changeByUser: Boolean = true): Unit = syncLock synchronized {
log.info(s"Changing installer path to ${path.toString}")
val installPlatform = patchPackage.detectInstallationPlatform(path).get
val instance = new PatchInstaller(path, installPlatform, platform)
val instance = new PatchInstaller(path, installPlatform, MPPatchInstaller.platform)
isUserChange = changeByUser
if (Files.exists(path)) {
isValid = checkPath(path)
isValid = new Installation(path).isValid(patchPackage)
installer.foreach(_.releaseLock())
if (isValid) {
instance.acquireLock()
if (changeByUser) ConfigurationStore.legacyInstallationDirectory.value = path.toFile.toString
if (changeByUser) installationManager.addDirectory(path)
}
installer = Some(instance)
} else {
Expand All @@ -86,22 +76,11 @@ class MainFrame(val locale: Locale) extends FrameBase[JFrame] {
log.info("Changing patch package...")
patchPackage = new PatchPackage(pack)
reloadInstaller()
installationManager.patchPackage = patchPackage
}

changePatchPackage(ResourceDataSource("builtin_patch"))

private def pathFromRegistry() = resolvePaths(platform.defaultSystemPaths) match {
case Some(x) => changeInstaller(x, false)
case None =>
}
if (ConfigurationStore.legacyInstallationDirectory.hasValue) {
val configPath = Paths.get(ConfigurationStore.legacyInstallationDirectory.value)
if (checkPath(configPath)) changeInstaller(configPath, false)
else {
ConfigurationStore.legacyInstallationDirectory.clear()
pathFromRegistry()
}
} else pathFromRegistry()
changeInstaller(installationManager.installations.head.rootDir, changeByUser = false)

private var lastPatchStatus: Option[PatchStatus] = _
private def checkPatchStatus() = {
Expand Down
16 changes: 8 additions & 8 deletions src/main/scala/moe/lymia/mppatch/ui/SettingsDialog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ class SettingsDialog(val locale: Locale, main: MainFrame) extends FrameBase[JDia
private def applySettings(): Unit = {
main.changeInstaller(Paths.get(installPath.getText))

ConfigurationStore.legacyEnableDebug.value = enableDebug.isSelected
ConfigurationStore.legacyEnableLogging.value = enableLogging.isSelected
ConfigurationStore.legacyEnableMultiplayerPatch.value = enableMultiplayerPatch.isSelected
ConfigurationStore.legacyEnableLuaJIT.value = enableLuaJIT.isSelected
// TODO ConfigurationStore.legacyEnableDebug.value = enableDebug.isSelected
// TODO ConfigurationStore.legacyEnableLogging.value = enableLogging.isSelected
// TODO ConfigurationStore.legacyEnableMultiplayerPatch.value = enableMultiplayerPatch.isSelected
// TODO ConfigurationStore.legacyEnableLuaJIT.value = enableLuaJIT.isSelected

main.update()
}
Expand Down Expand Up @@ -79,16 +79,16 @@ class SettingsDialog(val locale: Locale, main: MainFrame) extends FrameBase[JDia
}

enableLogging = options.gridCheckRow(1, "logging")
enableLogging.setSelected(ConfigurationStore.legacyEnableLogging.value)
// TODO enableLogging.setSelected(ConfigurationStore.legacyEnableLogging.value)

enableMultiplayerPatch = options.gridCheckRow(2, "modding")
enableMultiplayerPatch.setSelected(ConfigurationStore.legacyEnableMultiplayerPatch.value)
// TODO enableMultiplayerPatch.setSelected(ConfigurationStore.legacyEnableMultiplayerPatch.value)

enableLuaJIT = options.gridCheckRow(3, "luajit")
enableLuaJIT.setSelected(ConfigurationStore.legacyEnableLuaJIT.value)
// TODO enableLuaJIT.setSelected(ConfigurationStore.legacyEnableLuaJIT.value)

enableDebug = options.gridCheckRow(4, "debug")
enableDebug.setSelected(ConfigurationStore.legacyEnableDebug.value)
// TODO enableDebug.setSelected(ConfigurationStore.legacyEnableDebug.value)
}

frame.add(
Expand Down
105 changes: 105 additions & 0 deletions src/main/scala/moe/lymia/mppatch/ui/installations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2015-2023 Lymia Kanokawa <lymia@lymia.moe>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package moe.lymia.mppatch.ui

import moe.lymia.mppatch.core.{PatchPackage, Platform, PlatformType}
import moe.lymia.mppatch.util.io.DataSource
import play.api.libs.json.{Json, OFormat}

import java.nio.file.{Files, Path, Paths}
import scala.collection.mutable

case class InstallationConfiguration(
isManuallyAdded: Boolean,
packages: Set[String]
)
object InstallationConfiguration {
val default = InstallationConfiguration(
isManuallyAdded = false,
packages = Set("logging", "luajit", "multiplayer")
)
implicit val jsonFormat: OFormat[InstallationConfiguration] = Json.format[InstallationConfiguration]
}

class Installation(val rootDir: Path) {
def config = ConfigurationStore.installationConf(rootDir).value
def config_=(config: InstallationConfiguration) = ConfigurationStore.installationConf(rootDir).value = config

def isValid(pkg: PatchPackage) =
Files.exists(rootDir) && Files.isDirectory(rootDir) && pkg.detectInstallationPlatform(rootDir).isDefined
}

class InstallationManager {
private var installationDirList = Seq[Installation]()
private var patchPackage0 = new PatchPackage(MPPatchInstaller.defaultPackageSource)

def installations = installationDirList
def patchPackage = patchPackage0
def patchPackage_=(v: PatchPackage) = {
patchPackage0 = v
reset()
}

private def reset(): Unit = {
val detectedPaths = MPPatchInstaller.platform.defaultSystemPaths
val paths = ConfigurationStore.installationDirs.value.map(x => Paths.get(x))

val installationDirs = mutable.HashMap[String, Installation]()
for (path <- detectedPaths if patchPackage0.detectInstallationPlatform(path).isDefined)
installationDirs(path.toRealPath().toString) = new Installation(path)
for (path <- paths) installationDirs(path.toRealPath().toString) = new Installation(path)

for (dir <- ConfigurationStore.suppressedDirs.value) installationDirs.remove(dir)

ConfigurationStore.installationDirs.value = installationDirs.filter(x => x._2.config.isManuallyAdded).keys.toSet
installationDirList = installationDirs.keys.toSeq.sorted.map(x => installationDirs(x))
}
def setPatchPackage(source: DataSource): Unit = {
patchPackage0 = new PatchPackage(source)
reset()
}
reset()

def addDirectory(dir: Path) = {
val canonical = dir.toRealPath().toString

ConfigurationStore.suppressedDirs.value = ConfigurationStore.suppressedDirs.value - canonical
ConfigurationStore.installationDirs.value = ConfigurationStore.installationDirs.value + canonical

val key = ConfigurationStore.installationConf(dir)
key.value = key.value.copy(isManuallyAdded = true)

reset()
}
def removeDirectory(dir: Path) = {
val canonical = dir.toRealPath().toString

ConfigurationStore.suppressedDirs.value = ConfigurationStore.suppressedDirs.value + canonical
ConfigurationStore.installationDirs.value = ConfigurationStore.installationDirs.value - canonical

val key = ConfigurationStore.installationConf(dir)
key.value = key.value.copy(isManuallyAdded = false)

reset()
}
}

0 comments on commit 7248edc

Please sign in to comment.