Skip to content

Commit

Permalink
refactor(sync-info)!: sync info breaking changes (#11)
Browse files Browse the repository at this point in the history
* docs: update 'Mod.name' property comment

* chore(sync-script): exit process with status 1 instead of 0 in case showErrorMessageAndTerminate() did not exit
  • Loading branch information
EchoEllet authored Jun 29, 2024
1 parent 5bc2992 commit 2b04486
Show file tree
Hide file tree
Showing 19 changed files with 158 additions and 128 deletions.
2 changes: 1 addition & 1 deletion admin/src/main/kotlin/launchers/LauncherDataSource.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package launchers

import minecraftAssetProviders.MinecraftAssetProvider
import syncInfo.models.Mod
import syncInfo.models.mod.Mod
import java.nio.file.Path

// TODO: Rename launcherInstanceDirectoryPath to dotMinecraftDirectoryPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.jsonObject
import launchers.Instance
import launchers.LauncherDataSource
import syncInfo.models.Mod
import syncInfo.models.mod.Mod
import utils.JsonIgnoreUnknownKeys
import utils.JsonPrettyPrint
import utils.SystemFileProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import kotlinx.serialization.json.jsonObject
import launchers.Instance
import launchers.LauncherDataSource
import launchers.modrinth.ModrinthLauncherInstance.ModrinthLauncherProject
import syncInfo.models.Mod
import syncInfo.models.mod.Mod
import utils.JsonIgnoreUnknownKeys
import utils.SystemFileProvider
import utils.listFilteredPaths
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import curseForgeDataSource
import launchers.Instance
import launchers.LauncherDataSource
import okio.IOException
import syncInfo.models.Mod
import syncInfo.models.mod.Mod
import utils.SystemFileProvider
import utils.listFilteredPaths
import java.nio.file.Path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package launchers.prismLauncher
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import syncInfo.models.FileIntegrityInfo
import syncInfo.models.Mod
import syncInfo.models.mod.Mod

/**
* Prism launcher stores the mod info inside a folder [PrismLauncherDataSource.MODS_METADATA_DIRECTORY_NAME] which is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package minecraftAssetProviders.modrinth.models

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import syncInfo.models.Mod.ModSupport
import syncInfo.models.mod.Mod.ModSupport

/**
* From https://docs.modrinth.com/#tag/projects/operation/getProject
Expand Down Expand Up @@ -87,13 +87,12 @@ data class ModrinthProject(
/**
* @return Convert [ProjectSide] to [ModSupport] which is data-specific to the project
* */
fun toModSupport(): ModSupport {
return when (this) {
fun toModSupport(): ModSupport =
when (this) {
Required -> ModSupport.Required
Optional -> ModSupport.Optional
Unsupported -> ModSupport.Unsupported
}
}
}

@Serializable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package services.modsConverter

import constants.AdminConstants
import syncInfo.models.Mod
import syncInfo.models.mod.Mod

sealed class ModsConvertResult {
data class Success(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package services.modsConverter

import launchers.MinecraftLauncher
import services.modsConverter.models.ModsConvertMode
import syncInfo.models.Mod
import syncInfo.models.mod.Mod

interface ModsConverter {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import launchers.LauncherDataSourceFactory
import launchers.MinecraftLauncher
import services.modsConverter.models.ModsConvertMode
import syncInfo.models.SyncInfo
import syncInfo.models.mod.ModSyncInfo
import utils.JsonPrettyPrint
import java.nio.file.Paths
import kotlin.io.path.exists
Expand Down Expand Up @@ -108,7 +109,7 @@ class ModsConverterImpl : ModsConverter {
val json = if (prettyFormat) JsonPrettyPrint else Json
val modsOutputText: String =
when (convertMode) {
ModsConvertMode.InsideSyncInfo -> json.encodeToString(SyncInfo(mods = mods))
ModsConvertMode.InsideSyncInfo -> json.encodeToString(SyncInfo(modSyncInfo = ModSyncInfo(mods = mods)))
ModsConvertMode.AsModsList -> json.encodeToString(mods)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import utils.baseUrl
import java.net.URL

object MinecraftAssetProviderUtils {
fun getAssetProvider(downloadUrl: String): Result<MinecraftAssetProvider> {
return try {
fun getAssetProvider(downloadUrl: String): Result<MinecraftAssetProvider> =
try {
val assetProvider =
MinecraftAssetProvider.knownProviders.firstOrNull {
val url = URL(downloadUrl)
Expand All @@ -23,14 +23,13 @@ object MinecraftAssetProviderUtils {
e.printStackTrace()
Result.failure(e)
}
}

/**
* @return The used providers for all the assets (e.g., Mods, Resource-packs etc...)
* */
fun getAssetsProviders(syncInfo: SyncInfo): Result<Set<MinecraftAssetProvider>> {
val assetsProviders = mutableSetOf<MinecraftAssetProvider>()
syncInfo.mods.mapTo(assetsProviders) { getAssetProvider(it.downloadUrl).getOrThrow() }
syncInfo.modSyncInfo.mods.mapTo(assetsProviders) { getAssetProvider(it.downloadUrl).getOrThrow() }
// TODO: Add all kind of assets like Resource-packs and shaders
return Result.success(assetsProviders)
}
Expand Down
3 changes: 1 addition & 2 deletions common/src/main/kotlin/syncInfo/models/FileIntegrity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* A class that hold the data that is used for verifying a fle
* will be used in [Mod] and another type of resources to verify them
* A class that holds the data that is used for verifying a file
*
* Used to verify the file's integrity
* and trigger a re-download if the file is invalid or has been tampered with
Expand Down
90 changes: 6 additions & 84 deletions common/src/main/kotlin/syncInfo/models/SyncInfo.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package syncInfo.models

import kotlinx.serialization.Serializable
import syncInfo.models.mod.ModSyncInfo
import syncInfo.models.server.ServerSyncInfo

// When adding new data fields to this data class, ensure they are added in the correct order
// to maintain consistency with the JSON structure.

/**
* This data class represents the JSON structure containing sync information from a remote server.
* To simplify editing the JSON data, most variables like mods and related options to the mods are included directly.
*
* */
@Serializable
data class SyncInfo(
Expand All @@ -32,91 +32,13 @@ data class SyncInfo(
* */
val preferredAssetFileVerification: PreferredFileVerificationOption? = PreferredFileVerificationOption.Medium,
/**
* The list of mods to sync, take a look at [Mod] for more details
* All required and optional properties for the mod syncing process
* */
val mods: List<Mod> = emptyList(),
val modSyncInfo: ModSyncInfo = ModSyncInfo(),
/**
* Will override [shouldVerifyAssetFilesIntegrity] for the mods
*
* By default, the script only validates the file name and usually the file name contains
* the mod and minecraft version, so when you update some mods, the old versions will be deleted and be
* downloaded once again, if you also want the script to verify each file and if it matches the file from the source
* if not, then it will be deleted and re-downloaded again
*
* Also, if some mods got corrupted because of killing the process, then this would be helpful to make sure
* you have healthy mod files
*
* **Notice**: This option will only take effect for the mods that have at least one non-null value in the [FileIntegrityInfo]
* for example if [FileIntegrityInfo.sha256] or [FileIntegrityInfo.sizeInBytes] is not null, you can use one, some or all
* of them, it's up to you, in short if you want to verify a mod to be matched on the one the server, you have
* to assign a value to at least one, use [FileIntegrityInfo.sha256] or [FileIntegrityInfo.sha512]
* as it's validating the content to make sure it's valid and secure,
* validating using [FileIntegrityInfo.sizeInBytes] is a little bit faster (the difference is very negligible)
*
* If you want to verify all the mods, then all the mods need to have at least one value for one
* of those discussed above
*
* If you want to completely disable the verifying process,
* pass false to [shouldVerifyModFilesIntegrity] and will ignore
* even if the data in the [FileIntegrityInfo] are specified
*
* @see Mod.overrideShouldVerifyFileIntegrity to override this value for a specific mod
*
* */
val shouldVerifyModFilesIntegrity: Boolean? = null,
/**
* if [Environment] value is [Environment.Client] then will download/sync only the mods that'd need to be
* on te client side like client side mods and the mods that's needed to be in both Client and Server
*
* The exact opposite apply for [Environment.Server]
*
* This will depend on [Mod.clientSupport] and [Mod.serverSupport] values.
*
* **Notice**: If you automate the process of generating the mods info and get it from the Mod provider/ launcher,
* it might depend on the info that's on the provider (e.g, Modrinth) and it could be that the developers of the mod
* marked the mod as server side only and unsupported on the client side, while it's true for mods like [Geyser](https://modrinth.com/mod/geyser)
*
* It is usually optional on the client side.
* An example mod is [FallingTree](https://modrinth.com/mod/fallingtree)
* is marked as **server side only** and unsupported on the **client side** while it's **optional** for single player,
* it could work in single player in the **integrated server**;
* it's not needed on the **client side** to join a **multiplayer server**
*
* */
val shouldSyncOnlyModsForCurrentEnvironment: Boolean = true,
/**
* Should the script allow the player to install mods other than the synced mods by the script?
* if true then the script won't touch any mods that is not installed by the script, otherwise will delete it and
* won't allow using any other mods, still can be bypassed, it's better to install a server side mod
* that check the installed mods (still can be bypassed)
*
* TODO: Currently (BUG) if you let's say have sodium installed (sodium.jar), the synced mod by the script would be (sodium.synced.jar)
* however the user can still install (sodium.jar) resulting in mod duplication which will cause the game to not run
* (for most mod loaders), we can solve this by reading the mod id from the jar and make sure there are no duplication
* */
val allowUsingOtherMods: Boolean = false,
/**
* A way for the script to download mods and save them like (`my-mod.synced.jar`) instead of (`my-mod.jar`)
* the script need this so it can know if the mod installed by it or not to support [allowUsingOtherMods]
* when true, so it will ignore the mods installed by the player
*
* Pass null if you want to disable this and install the mod file name just like how it's on the source.
* In that case make sure to not pass true to [allowUsingOtherMods] because it won't work
*
* If you want to change it to something like (`my-mod.sync.jar`) pass `.sync` instead
*
* if there is already existing players that has the installed mods with a specific [modSyncMarker] and you change
* it from (`.synced` to `.sync` for example), then the script would identify the mods with (`.sync`) as mods
* installed by the player resulting in duplication, However, this occurs only if [allowUsingOtherMods] is true, otherwise
* will be deleted and downloaded again in case of this changed
* */
val modSyncMarker: String? = ".synced",
/**
* The list of servers to sync, so when you change the server address or move to another host,
* the players are no longer required to update it, it will be all automated, you can add multiple servers
* in case you have different servers for different regions or some other use-case, for example
* All required and optional properties for the server syncing process
* */
val servers: List<Server> = emptyList(),
val serverSyncInfo: ServerSyncInfo = ServerSyncInfo(),
) {
companion object
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package syncInfo.models
package syncInfo.models.mod

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import syncInfo.models.Environment
import syncInfo.models.FileIntegrityInfo
import syncInfo.models.SyncInfo

// When adding a new property, consider converting/import the new
// data from other launchers data format if possible
Expand All @@ -20,8 +23,8 @@ data class Mod(
* */
val fileIntegrityInfo: FileIntegrityInfo = FileIntegrityInfo(),
/**
* The mod name (optional) for now will be only used in the gui, if you don't specify it, then will get
* the file name from [mod]
* The mod name (optional) that might be displayed in GUI, if not present
* will fall back to the file name from [downloadUrl]
* */
val name: String? = null,
/**
Expand Down Expand Up @@ -53,10 +56,10 @@ data class Mod(
* */
val description: String? = null,
/**
* Will override [SyncInfo.shouldVerifyModFilesIntegrity] and [SyncInfo.shouldVerifyAssetFilesIntegrity]
* Will override [ModSyncInfo.shouldVerifyModFilesIntegrity] and [SyncInfo.shouldVerifyAssetFilesIntegrity]
* for a specific mod
*
* @see SyncInfo.shouldVerifyModFilesIntegrity for more details.
* @see ModSyncInfo.shouldVerifyModFilesIntegrity for more details.
* */
val overrideShouldVerifyFileIntegrity: Boolean? = null,
) {
Expand Down
90 changes: 90 additions & 0 deletions common/src/main/kotlin/syncInfo/models/mod/ModSyncInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package syncInfo.models.mod

import kotlinx.serialization.Serializable
import syncInfo.models.Environment
import syncInfo.models.FileIntegrityInfo
import syncInfo.models.SyncInfo

@Serializable
data class ModSyncInfo(
/**
* The list of mods to sync, take a look at [Mod] for more details
* */
val mods: List<Mod> = emptyList(),
/**
* Will override [SyncInfo.shouldVerifyAssetFilesIntegrity] for the mods
*
* By default, the script only validates the file name and usually the file name contains
* the mod and minecraft version, so when you update some mods, the old versions will be deleted and be
* downloaded once again, if you also want the script to verify each file and if it matches the file from the source
* if not, then it will be deleted and re-downloaded again
*
* Also, if some mods got corrupted because of killing the process, then this would be helpful to make sure
* you have healthy mod files
*
* **Notice**: This option will only take effect for the mods that have at least one non-null value in the [FileIntegrityInfo]
* for example if [FileIntegrityInfo.sha256] or [FileIntegrityInfo.sizeInBytes] is not null, you can use one, some or all
* of them, it's up to you, in short if you want to verify a mod to be matched on the one the server, you have
* to assign a value to at least one, use [FileIntegrityInfo.sha256] or [FileIntegrityInfo.sha512]
* as it's validating the content to make sure it's valid and secure,
* validating using [FileIntegrityInfo.sizeInBytes] is a little bit faster (the difference is very negligible)
*
* If you want to verify all the mods, then all the mods need to have at least one value for one
* of those discussed above
*
* If you want to completely disable the verifying process,
* pass false to [shouldVerifyModFilesIntegrity] and will ignore
* even if the data in the [FileIntegrityInfo] are specified
*
* @see Mod.overrideShouldVerifyFileIntegrity to override this value for a specific mod
*
* */
val shouldVerifyModFilesIntegrity: Boolean? = null,
/**
* if [Environment] value is [Environment.Client] then will download/sync only the mods that'd need to be
* on te client side like client side mods and the mods that's needed to be in both Client and Server
*
* The exact opposite apply for [Environment.Server]
*
* This will depend on [Mod.clientSupport] and [Mod.serverSupport] values.
*
* **Notice**: If you automate the process of generating the mods info and get it from the Mod provider/ launcher,
* it might depend on the info that's on the provider (e.g, Modrinth) and it could be that the developers of the mod
* marked the mod as server side only and unsupported on the client side, while it's true for mods like [Geyser](https://modrinth.com/mod/geyser)
*
* It is usually optional on the client side.
* An example mod is [FallingTree](https://modrinth.com/mod/fallingtree)
* is marked as **server side only** and unsupported on the **client side** while it's **optional** for single player,
* it could work in single player in the **integrated server**;
* it's not needed on the **client side** to join a **multiplayer server**
*
* */
val shouldSyncOnlyModsForCurrentEnvironment: Boolean = true,
/**
* Should the script allow the player to install mods other than the synced mods by the script?
* if true then the script won't touch any mods that is not installed by the script, otherwise will delete it and
* won't allow using any other mods, still can be bypassed, it's better to install a server side mod
* that check the installed mods (can be bypassed)
*
* TODO: Currently (BUG) if you let's say have sodium installed (sodium.jar), the synced mod by the script would be (sodium.synced.jar)
* however the user can still install (sodium.jar) resulting in mod duplication which will cause the game to not run
* (for most mod loaders), we can solve this by reading the mod id from the jar and make sure there are no duplication
* */
val allowUsingOtherMods: Boolean = false,
/**
* A way for the script to download mods and save them like (`my-mod.synced.jar`) instead of (`my-mod.jar`)
* the script need this so it can know if the mod installed by it or not to support [allowUsingOtherMods]
* when true, so it will ignore the mods installed by the player
*
* Pass null if you want to disable this and install the mod file name just like how it's on the source.
* In that case make sure to not pass true to [allowUsingOtherMods] because it won't work
*
* If you want to change it to something like (`my-mod.sync.jar`) pass `.sync` instead
*
* if there is already existing players that has the installed mods with a specific [modSyncMarker] and you change
* it from (`.synced` to `.sync` for example), then the script would identify the mods with (`.sync`) as mods
* installed by the player resulting in duplication, However, this occurs only if [allowUsingOtherMods] is true, otherwise
* will be deleted and downloaded again in case of this changed
* */
val modSyncMarker: String? = ".synced",
)
Loading

0 comments on commit 2b04486

Please sign in to comment.