diff --git a/core/pack.go b/core/pack.go index aa2047e..c6bffbf 100644 --- a/core/pack.go +++ b/core/pack.go @@ -3,6 +3,7 @@ package core import ( "errors" "fmt" + "golang.org/x/exp/slices" "io" "os" "path/filepath" @@ -171,7 +172,16 @@ func (pack Pack) GetSupportedMCVersions() ([]string, error) { return nil, errors.New("no minecraft version specified in modpack") } allVersions := append(append([]string(nil), viper.GetStringSlice("acceptable-game-versions")...), mcVersion) - return allVersions, nil + // Deduplicate values + allVersionsDeduped := []string(nil) + for i, v := range allVersions { + // If another copy of this value exists past this point in the array, don't insert + // (i.e. prefer a later copy over an earlier copy, so the main version is last) + if !slices.Contains(allVersions[i+1:], v) { + allVersionsDeduped = append(allVersionsDeduped, v) + } + } + return allVersionsDeduped, nil } func (pack Pack) GetPackName() string { diff --git a/curseforge/curseforge.go b/curseforge/curseforge.go index 11eeead..8630e42 100644 --- a/curseforge/curseforge.go +++ b/curseforge/curseforge.go @@ -297,24 +297,48 @@ func findLatestFile(modInfoData modInfo, mcVersions []string, packLoaders []stri for _, v := range modInfoData.LatestFiles { mcVerIdx := core.HighestSliceIndex(mcVersions, v.GameVersions) loaderIdx, loaderValid := filterFileInfoLoaderIndex(packLoaders, v) - // Choose "newest" version by largest ID - // Prefer higher indexes of mcVersions - if mcVerIdx > -1 && loaderValid && (mcVerIdx > bestMcVer || loaderIdx > bestLoaderType || v.ID > fileID) { + + if mcVerIdx < 0 || !loaderValid { + continue + } + // Compare first by Minecraft version (prefer higher indexes of mcVersions) + compare := int32(mcVerIdx - bestMcVer) + if compare == 0 { + // Prefer higher loader indexes + compare = int32(loaderIdx - bestLoaderType) + } + if compare == 0 { + // Other comparisons are equal, compare by ID instead + compare = int32(v.ID - fileID) + } + if compare > 0 { fileID = v.ID - fileInfoData = &v + fileInfoDataCopy := v // Fix for loop variable reference (which gets reassigned on every iteration!) + fileInfoData = &fileInfoDataCopy fileName = v.FileName bestMcVer = mcVerIdx bestLoaderType = loaderIdx } } - // TODO: change to timestamp-based comparison?? // TODO: manage alpha/beta/release correctly, check update channel? for _, v := range modInfoData.GameVersionLatestFiles { mcVerIdx := slices.Index(cfMcVersions, v.GameVersion) loaderIdx, loaderValid := filterLoaderTypeIndex(packLoaders, v.Modloader) - // Choose "newest" version by largest ID - // Prefer higher indexes of mcVersions - if mcVerIdx > -1 && loaderValid && (mcVerIdx > bestMcVer || loaderIdx > bestLoaderType || v.ID > fileID) { + + if mcVerIdx < 0 || !loaderValid { + continue + } + // Compare first by Minecraft version (prefer higher indexes of mcVersions) + compare := int32(mcVerIdx - bestMcVer) + if compare == 0 { + // Prefer higher loader indexes + compare = int32(loaderIdx - bestLoaderType) + } + if compare == 0 { + // Other comparisons are equal, compare by ID instead + compare = int32(v.ID - fileID) + } + if compare > 0 { fileID = v.ID fileInfoData = nil // (no file info in GameVersionLatestFiles) fileName = v.Name diff --git a/modrinth/modrinth.go b/modrinth/modrinth.go index 2806d0e..0e310dd 100644 --- a/modrinth/modrinth.go +++ b/modrinth/modrinth.go @@ -242,11 +242,16 @@ func findLatestVersion(versions []*modrinthApi.Version, gameVersions []string, u } if compare == 0 { - if loaderIdx < latestValidLoaderIdx { // Prefer loaders; principally Quilt over Fabric, mods over datapacks (Modrinth backend handles filtering) - compare = 1 - } else if gameVersionIdx > bestGameVersion { // Prefer later specified game versions (main version specified last) - compare = 1 - } else if v.DatePublished.After(*latestValidVersion.DatePublished) { // FlexVer comparison is equal or disabled, compare date instead + // Prefer later specified game versions (main version specified last) + compare = int32(gameVersionIdx - bestGameVersion) + } + if compare == 0 { + // Prefer loaders; principally Quilt over Fabric, mods over datapacks (Modrinth backend handles filtering) + compare = int32(latestValidLoaderIdx - loaderIdx) + } + if compare == 0 { + // Other comparisons are equal, compare date instead + if v.DatePublished.After(*latestValidVersion.DatePublished) { compare = 1 } }