From 7bedd820c26b497f5661203c1291b369c07aff39 Mon Sep 17 00:00:00 2001 From: comp500 Date: Tue, 4 May 2021 19:07:29 +0100 Subject: [PATCH] Add option to specify additional game versions (closes #25) --- README.md | 5 +++++ core/pack.go | 9 +++++++++ curseforge/curseforge.go | 33 +++++++++++++++++++++++++++++++-- curseforge/install.go | 15 +++++++++++---- modrinth/install.go | 5 +++-- modrinth/modrinth.go | 20 +++++++++++++++++--- 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 515c48d..7b34d5a 100644 --- a/README.md +++ b/README.md @@ -73,3 +73,8 @@ For use on servers, add the `-g` flag to disable the GUI and `-s server` to down - `packwiz cf install Sodium` (by search) - `packwiz cf install --addon-id 394468 --file-id 3067101` (if all else fails) - If files aren't being found, try running the `packwiz refresh` command to update the index! + +## Options +- Additional options can be configured in the `[options]` section of `pack.toml`, as follows: + - `mods-folder` The folder to save mod metadata files into, for the install commands + - `acceptable-game-versions` A list of additional Minecraft versions to accept when installing or updating mods \ No newline at end of file diff --git a/core/pack.go b/core/pack.go index 4af86b7..06f7fd0 100644 --- a/core/pack.go +++ b/core/pack.go @@ -26,6 +26,7 @@ type Pack struct { Client map[string]toml.Primitive `toml:"client"` Server map[string]toml.Primitive `toml:"server"` Export map[string]map[string]interface{} `toml:"export"` + Options map[string]interface{} `toml:"options"` } // LoadPack loads the modpack metadata to a Pack struct @@ -35,6 +36,14 @@ func LoadPack() (Pack, error) { return Pack{}, err } + // Read options into viper + if modpack.Options != nil { + err := viper.MergeConfigMap(modpack.Options) + if err != nil { + return Pack{}, err + } + } + if len(modpack.Index.File) == 0 { modpack.Index.File = "index.toml" } diff --git a/curseforge/curseforge.go b/curseforge/curseforge.go index 3dbab0e..eff839c 100644 --- a/curseforge/curseforge.go +++ b/curseforge/curseforge.go @@ -2,6 +2,7 @@ package curseforge import ( "errors" + "github.com/spf13/viper" "regexp" "strconv" "strings" @@ -199,6 +200,34 @@ func createModFile(modInfo modInfo, fileInfo modFileInfo, index *core.Index) err return index.RefreshFileWithHash(path, format, hash, true) } +func matchGameVersion(mcVersion string, modMcVersion string) bool { + if getCurseforgeVersion(mcVersion) == modMcVersion { + return true + } else { + for _, v := range viper.GetStringSlice("acceptable-game-versions") { + if getCurseforgeVersion(v) == modMcVersion { + return true + } + } + return false + } +} + +func matchGameVersions(mcVersion string, modMcVersions []string) bool { + for _, modMcVersion := range modMcVersions { + if getCurseforgeVersion(mcVersion) == modMcVersion { + return true + } else { + for _, v := range viper.GetStringSlice("acceptable-game-versions") { + if getCurseforgeVersion(v) == modMcVersion { + return true + } + } + } + } + return false +} + type cfUpdateData struct { ProjectID int `mapstructure:"project-id"` FileID int `mapstructure:"file-id"` @@ -271,7 +300,7 @@ func (u cfUpdater) CheckUpdate(mods []core.Mod, mcVersion string) ([]core.Update // For snapshots, curseforge doesn't put them in GameVersionLatestFiles for _, v := range modInfos[i].LatestFiles { // Choose "newest" version by largest ID - if sliceContainsString(v.GameVersions, getCurseforgeVersion(mcVersion)) && v.ID > fileID { + if matchGameVersions(mcVersion, v.GameVersions) && v.ID > fileID { updateAvailable = true fileID = v.ID fileInfoData = v @@ -284,7 +313,7 @@ func (u cfUpdater) CheckUpdate(mods []core.Mod, mcVersion string) ([]core.Update // TODO: change to timestamp-based comparison?? // TODO: manage alpha/beta/release correctly, check update channel? // Choose "newest" version by largest ID - if file.GameVersion == getCurseforgeVersion(mcVersion) && file.ID > fileID { + if matchGameVersion(mcVersion, file.GameVersion) && file.ID > fileID { updateAvailable = true fileID = file.ID fileName = file.Name diff --git a/curseforge/install.go b/curseforge/install.go index 65d1fed..ed83e99 100644 --- a/curseforge/install.go +++ b/curseforge/install.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "github.com/sahilm/fuzzy" + "github.com/spf13/viper" "os" "strings" @@ -268,7 +269,13 @@ func (r modResultsList) Len() int { func searchCurseforgeInternal(args []string, mcVersion string) (bool, modInfo) { fmt.Println("Searching CurseForge...") searchTerm := strings.Join(args, " ") - results, err := getSearch(searchTerm, getCurseforgeVersion(mcVersion)) + + // If there are more than one acceptable version, we shouldn't filter by game version at all (as we can't filter by multiple) + filterGameVersion := getCurseforgeVersion(mcVersion) + if len(viper.GetStringSlice("acceptable-game-versions")) > 0 { + filterGameVersion = "" + } + results, err := getSearch(searchTerm, filterGameVersion) if err != nil { fmt.Println(err) os.Exit(1) @@ -343,7 +350,7 @@ func getLatestFile(modInfoData modInfo, mcVersion string, fileID int) (modFileIn for _, v := range modInfoData.LatestFiles { // Choose "newest" version by largest ID - if sliceContainsString(v.GameVersions, getCurseforgeVersion(mcVersion)) && v.ID > fileID { + if matchGameVersions(mcVersion, v.GameVersions) && v.ID > fileID { fileID = v.ID fileInfoData = v fileInfoObtained = true @@ -352,7 +359,7 @@ func getLatestFile(modInfoData modInfo, mcVersion string, fileID int) (modFileIn // TODO: change to timestamp-based comparison?? for _, v := range modInfoData.GameVersionLatestFiles { // Choose "newest" version by largest ID - if v.GameVersion == getCurseforgeVersion(mcVersion) && v.ID > fileID { + if matchGameVersion(mcVersion, v.GameVersion) && v.ID > fileID { fileID = v.ID fileInfoObtained = false // Make sure we get the file info } @@ -363,7 +370,7 @@ func getLatestFile(modInfoData modInfo, mcVersion string, fileID int) (modFileIn } if fileID == 0 { - return modFileInfo{}, errors.New("mod not available for this minecraft version") + return modFileInfo{}, errors.New("mod not available for the configured Minecraft version(s) (use the acceptable-remote-versions option to accept more)") } fileInfoData, err := getFileInfo(modInfoData.ID, fileID) diff --git a/modrinth/install.go b/modrinth/install.go index d096fb8..1f23397 100644 --- a/modrinth/install.go +++ b/modrinth/install.go @@ -3,6 +3,7 @@ package modrinth import ( "errors" "fmt" + "github.com/spf13/viper" "os" "regexp" "strings" @@ -97,7 +98,7 @@ func installViaSearch(query string, pack core.Pack) error { return err } - results, err := getModIdsViaSearch(query, mcVersion) + results, err := getModIdsViaSearch(query, append([]string{mcVersion}, viper.GetStringSlice("acceptable-game-versions")...)) if err != nil { return err } @@ -142,7 +143,7 @@ func installMod(mod Mod, pack core.Pack) error { return err } if latestVersion.ID == "" { - return errors.New("mod is not available for this minecraft version or mod loader") + return errors.New("mod is not available for this Minecraft version (use the acceptable-remote-versions option to accept more) or mod loader") } return installVersion(mod, latestVersion, pack) diff --git a/modrinth/modrinth.go b/modrinth/modrinth.go index 3df509b..c16bde1 100644 --- a/modrinth/modrinth.go +++ b/modrinth/modrinth.go @@ -3,6 +3,7 @@ package modrinth import ( "encoding/json" "errors" + "github.com/spf13/viper" "io/ioutil" "net/http" "net/url" @@ -115,14 +116,22 @@ type VersionFile struct { Primary bool // Is the file the primary file? } -func getModIdsViaSearch(query string, version string) ([]ModResult, error) { +func getModIdsViaSearch(query string, versions []string) ([]ModResult, error) { baseUrl := *modrinthApiUrlParsed baseUrl.Path += "mod" params := url.Values{} params.Add("limit", "5") params.Add("index", "relevance") - params.Add("facets", "[[\"versions:"+version+"\"]]") + facets := make([]string, 0) + for _, v := range versions { + facets = append(facets, "\"versions:"+v+"\"") + } + facetsEncoded, err := json.Marshal(facets) + if err != nil { + return []ModResult{}, err + } + params.Add("facets", "["+string(facetsEncoded)+"]") params.Add("query", query) baseUrl.RawQuery = params.Encode() @@ -156,6 +165,11 @@ func getLatestVersion(modID string, pack core.Pack) (Version, error) { if err != nil { return Version{}, err } + gameVersions := append([]string{mcVersion}, viper.GetStringSlice("acceptable-game-versions")...) + gameVersionsEncoded, err := json.Marshal(gameVersions) + if err != nil { + return Version{}, err + } loader := getLoader(pack) @@ -165,7 +179,7 @@ func getLatestVersion(modID string, pack core.Pack) (Version, error) { baseUrl.Path += "/version" params := url.Values{} - params.Add("game_versions", "[\""+mcVersion+"\"]") + params.Add("game_versions", string(gameVersionsEncoded)) if loader != "any" { params.Add("loaders", "[\""+loader+"\"]") }