mirror of
https://github.com/packwiz/packwiz.git
synced 2025-04-19 13:06:30 +02:00
Add Jumploader to Fabric packs for CurseForge automatically (fixes #5)
This commit is contained in:
parent
a87f7b50f0
commit
877c7d1b02
120
cmd/init.go
120
cmd/init.go
@ -3,8 +3,6 @@ package cmd
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -89,13 +87,13 @@ var initCmd = &cobra.Command{
|
||||
if len(modLoaderName) == 0 {
|
||||
modLoaderName = initReadValue("Mod loader [fabric]: ", "fabric")
|
||||
}
|
||||
_, ok := modLoaders[modLoaderName]
|
||||
_, ok := core.ModLoaders[modLoaderName]
|
||||
if modLoaderName != "none" && !ok {
|
||||
fmt.Println("Given mod loader is not supported! Use \"none\" to specify no modloader, or to configure one manually.")
|
||||
fmt.Print("The following mod loaders are supported: ")
|
||||
keys := make([]string, len(modLoaders))
|
||||
keys := make([]string, len(core.ModLoaders))
|
||||
i := 0
|
||||
for k := range modLoaders {
|
||||
for k := range core.ModLoaders {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
@ -105,7 +103,7 @@ var initCmd = &cobra.Command{
|
||||
|
||||
modLoaderVersions := make(map[string]string)
|
||||
if modLoaderName != "none" {
|
||||
components := modLoaders[modLoaderName]
|
||||
components := core.ModLoaders[modLoaderName]
|
||||
|
||||
for _, component := range components {
|
||||
versions, latestVersion, err := component.VersionListGetter(mcVersion)
|
||||
@ -223,7 +221,7 @@ func init() {
|
||||
_ = viper.BindPFlag("init.modloader", initCmd.Flags().Lookup("modloader"))
|
||||
|
||||
// ok this is epic
|
||||
for _, loader := range modLoaders {
|
||||
for _, loader := range core.ModLoaders {
|
||||
for _, component := range loader {
|
||||
initCmd.Flags().String(component.Name+"-version", "", "The "+component.FriendlyName+" version to use (omit to define interactively)")
|
||||
_ = viper.BindPFlag("init."+component.Name+"-version", initCmd.Flags().Lookup(component.Name+"-version"))
|
||||
@ -289,111 +287,3 @@ func getValidMCVersions() (mcVersionManifest, error) {
|
||||
})
|
||||
return out, nil
|
||||
}
|
||||
|
||||
type mavenMetadata struct {
|
||||
XMLName xml.Name `xml:"metadata"`
|
||||
GroupID string `xml:"groupId"`
|
||||
ArtifactID string `xml:"artifactId"`
|
||||
Versioning struct {
|
||||
Release string `xml:"release"`
|
||||
Versions struct {
|
||||
Version []string `xml:"version"`
|
||||
} `xml:"versions"`
|
||||
LastUpdated string `xml:"lastUpdated"`
|
||||
} `xml:"versioning"`
|
||||
}
|
||||
|
||||
type modLoaderComponent struct {
|
||||
Name string
|
||||
FriendlyName string
|
||||
VersionListGetter func(mcVersion string) ([]string, string, error)
|
||||
}
|
||||
|
||||
var modLoaders = map[string][]modLoaderComponent{
|
||||
"fabric": {
|
||||
{
|
||||
Name: "fabric",
|
||||
FriendlyName: "Fabric loader",
|
||||
VersionListGetter: fetchMavenVersionList("https://maven.fabricmc.net/net/fabricmc/fabric-loader/maven-metadata.xml"),
|
||||
},
|
||||
// There's no need to specify yarn version - yarn isn't used outside a dev environment, and intermediary corresponds to game version anyway
|
||||
//{
|
||||
// Name: "yarn",
|
||||
// FriendlyName: "Yarn (mappings)",
|
||||
// VersionListGetter: fetchMavenVersionPrefixedList("https://maven.fabricmc.net/net/fabricmc/yarn/maven-metadata.xml", "Yarn"),
|
||||
//},
|
||||
},
|
||||
"forge": {
|
||||
{
|
||||
Name: "forge",
|
||||
FriendlyName: "Forge",
|
||||
VersionListGetter: fetchMavenVersionPrefixedListStrip("https://files.minecraftforge.net/maven/net/minecraftforge/forge/maven-metadata.xml", "Forge"),
|
||||
},
|
||||
},
|
||||
"liteloader": {
|
||||
{
|
||||
Name: "liteloader",
|
||||
FriendlyName: "LiteLoader",
|
||||
VersionListGetter: fetchMavenVersionPrefixedList("http://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/maven-metadata.xml", "LiteLoader"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func fetchMavenVersionList(url string) func(mcVersion string) ([]string, string, error) {
|
||||
return func(mcVersion string) ([]string, string, error) {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
dec := xml.NewDecoder(res.Body)
|
||||
out := mavenMetadata{}
|
||||
err = dec.Decode(&out)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
return out.Versioning.Versions.Version, out.Versioning.Release, nil
|
||||
}
|
||||
}
|
||||
|
||||
func fetchMavenVersionPrefixedListStrip(url string, friendlyName string) func(mcVersion string) ([]string, string, error) {
|
||||
noStrip := fetchMavenVersionPrefixedList(url, friendlyName)
|
||||
return func(mcVersion string) ([]string, string, error) {
|
||||
versions, latestVersion, err := noStrip(mcVersion)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
for k, v := range versions {
|
||||
versions[k] = strings.TrimPrefix(v, mcVersion+"-")
|
||||
}
|
||||
latestVersion = strings.TrimPrefix(latestVersion, mcVersion+"-")
|
||||
return versions, latestVersion, nil
|
||||
}
|
||||
}
|
||||
|
||||
func fetchMavenVersionPrefixedList(url string, friendlyName string) func(mcVersion string) ([]string, string, error) {
|
||||
return func(mcVersion string) ([]string, string, error) {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
dec := xml.NewDecoder(res.Body)
|
||||
out := mavenMetadata{}
|
||||
err = dec.Decode(&out)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
allowedVersions := make([]string, 0, len(out.Versioning.Versions.Version))
|
||||
for _, v := range out.Versioning.Versions.Version {
|
||||
if strings.HasPrefix(v, mcVersion) {
|
||||
allowedVersions = append(allowedVersions, v)
|
||||
}
|
||||
}
|
||||
if len(allowedVersions) == 0 {
|
||||
return []string{}, "", errors.New("no " + friendlyName + " versions available for this Minecraft version")
|
||||
}
|
||||
if strings.HasPrefix(out.Versioning.Release, mcVersion) {
|
||||
return allowedVersions, out.Versioning.Release, nil
|
||||
}
|
||||
return allowedVersions, allowedVersions[len(allowedVersions)-1], nil
|
||||
}
|
||||
}
|
||||
|
116
core/versionutil.go
Normal file
116
core/versionutil.go
Normal file
@ -0,0 +1,116 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MavenMetadata struct {
|
||||
XMLName xml.Name `xml:"metadata"`
|
||||
GroupID string `xml:"groupId"`
|
||||
ArtifactID string `xml:"artifactId"`
|
||||
Versioning struct {
|
||||
Release string `xml:"release"`
|
||||
Versions struct {
|
||||
Version []string `xml:"version"`
|
||||
} `xml:"versions"`
|
||||
LastUpdated string `xml:"lastUpdated"`
|
||||
} `xml:"versioning"`
|
||||
}
|
||||
|
||||
type ModLoaderComponent struct {
|
||||
Name string
|
||||
FriendlyName string
|
||||
VersionListGetter func(mcVersion string) ([]string, string, error)
|
||||
}
|
||||
|
||||
var ModLoaders = map[string][]ModLoaderComponent{
|
||||
"fabric": {
|
||||
{
|
||||
Name: "fabric",
|
||||
FriendlyName: "Fabric loader",
|
||||
VersionListGetter: FetchMavenVersionList("https://maven.fabricmc.net/net/fabricmc/fabric-loader/maven-metadata.xml"),
|
||||
},
|
||||
// There's no need to specify yarn version - yarn isn't used outside a dev environment, and intermediary corresponds to game version anyway
|
||||
//{
|
||||
// Name: "yarn",
|
||||
// FriendlyName: "Yarn (mappings)",
|
||||
// VersionListGetter: fetchMavenVersionPrefixedList("https://maven.fabricmc.net/net/fabricmc/yarn/maven-metadata.xml", "Yarn"),
|
||||
//},
|
||||
},
|
||||
"forge": {
|
||||
{
|
||||
Name: "forge",
|
||||
FriendlyName: "Forge",
|
||||
VersionListGetter: FetchMavenVersionPrefixedListStrip("https://files.minecraftforge.net/maven/net/minecraftforge/forge/maven-metadata.xml", "Forge"),
|
||||
},
|
||||
},
|
||||
"liteloader": {
|
||||
{
|
||||
Name: "liteloader",
|
||||
FriendlyName: "LiteLoader",
|
||||
VersionListGetter: FetchMavenVersionPrefixedList("http://repo.mumfrey.com/content/repositories/snapshots/com/mumfrey/liteloader/maven-metadata.xml", "LiteLoader"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func FetchMavenVersionList(url string) func(mcVersion string) ([]string, string, error) {
|
||||
return func(mcVersion string) ([]string, string, error) {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
dec := xml.NewDecoder(res.Body)
|
||||
out := MavenMetadata{}
|
||||
err = dec.Decode(&out)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
return out.Versioning.Versions.Version, out.Versioning.Release, nil
|
||||
}
|
||||
}
|
||||
|
||||
func FetchMavenVersionPrefixedListStrip(url string, friendlyName string) func(mcVersion string) ([]string, string, error) {
|
||||
noStrip := FetchMavenVersionPrefixedList(url, friendlyName)
|
||||
return func(mcVersion string) ([]string, string, error) {
|
||||
versions, latestVersion, err := noStrip(mcVersion)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
for k, v := range versions {
|
||||
versions[k] = strings.TrimPrefix(v, mcVersion+"-")
|
||||
}
|
||||
latestVersion = strings.TrimPrefix(latestVersion, mcVersion+"-")
|
||||
return versions, latestVersion, nil
|
||||
}
|
||||
}
|
||||
|
||||
func FetchMavenVersionPrefixedList(url string, friendlyName string) func(mcVersion string) ([]string, string, error) {
|
||||
return func(mcVersion string) ([]string, string, error) {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
dec := xml.NewDecoder(res.Body)
|
||||
out := MavenMetadata{}
|
||||
err = dec.Decode(&out)
|
||||
if err != nil {
|
||||
return []string{}, "", err
|
||||
}
|
||||
allowedVersions := make([]string, 0, len(out.Versioning.Versions.Version))
|
||||
for _, v := range out.Versioning.Versions.Version {
|
||||
if strings.HasPrefix(v, mcVersion) {
|
||||
allowedVersions = append(allowedVersions, v)
|
||||
}
|
||||
}
|
||||
if len(allowedVersions) == 0 {
|
||||
return []string{}, "", errors.New("no " + friendlyName + " versions available for this Minecraft version")
|
||||
}
|
||||
if strings.HasPrefix(out.Versioning.Release, mcVersion) {
|
||||
return allowedVersions, out.Versioning.Release, nil
|
||||
}
|
||||
return allowedVersions, allowedVersions[len(allowedVersions)-1], nil
|
||||
}
|
||||
}
|
@ -349,6 +349,9 @@ func (u cfUpdater) DoUpdate(mods []*core.Mod, cachedState []interface{}) error {
|
||||
|
||||
type cfExportData struct {
|
||||
ProjectID int `mapstructure:"project-id"`
|
||||
DisableJumploader bool `mapstructure:"disable-jumploader"`
|
||||
JumploaderForgeVersion string `mapstructure:"jumploader-forge-version"`
|
||||
JumploaderFileID int `mapstructure:"jumploader-version-id"`
|
||||
}
|
||||
|
||||
func (e cfExportData) ToMap() (map[string]interface{}, error) {
|
||||
|
@ -3,6 +3,7 @@ package curseforge
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/viper"
|
||||
"os"
|
||||
@ -104,6 +105,8 @@ var exportCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
cfFileRefs := make([]packinterop.AddonFileReference, 0, len(mods))
|
||||
jumploaderIncluded := false
|
||||
jumploaderProjectID := 361988
|
||||
for _, mod := range mods {
|
||||
projectRaw, ok := mod.GetParsedUpdateData("curseforge")
|
||||
// If the mod has curseforge metadata, add it to cfFileRefs
|
||||
@ -115,6 +118,9 @@ var exportCmd = &cobra.Command{
|
||||
FileID: p.FileID,
|
||||
OptionalDisabled: mod.Option != nil && mod.Option.Optional && !mod.Option.Default,
|
||||
})
|
||||
if p.ProjectID == jumploaderProjectID {
|
||||
jumploaderIncluded = true
|
||||
}
|
||||
} else {
|
||||
// If the mod doesn't have the metadata, save it into the zip
|
||||
path, err := filepath.Rel(filepath.Dir(indexPath), mod.GetDestFilePath())
|
||||
@ -138,6 +144,82 @@ var exportCmd = &cobra.Command{
|
||||
}
|
||||
}
|
||||
|
||||
fabricVersion, usingFabric := pack.Versions["fabric"]
|
||||
dataUpdated := false
|
||||
|
||||
if usingFabric {
|
||||
if len(fabricVersion) == 0 {
|
||||
fmt.Println("Invalid version of Fabric found!")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(exportData.JumploaderForgeVersion) == 0 {
|
||||
dataUpdated = true
|
||||
|
||||
// TODO: this code is horrible, I hate it
|
||||
_, latest, err := core.ModLoaders["forge"][0].VersionListGetter(pack.Versions["minecraft"])
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to get the latest Forge version: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
exportData.JumploaderForgeVersion = latest
|
||||
}
|
||||
}
|
||||
|
||||
if !jumploaderIncluded && usingFabric && !exportData.DisableJumploader {
|
||||
fmt.Println("Fabric isn't natively supported by CurseForge, adding Jumploader...")
|
||||
|
||||
if exportData.JumploaderFileID == 0 {
|
||||
dataUpdated = true
|
||||
modInfoData, err := getModInfo(jumploaderProjectID)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to fetch Jumploader latest file: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
var fileID int
|
||||
for _, v := range modInfoData.LatestFiles {
|
||||
// Choose "newest" version by largest ID
|
||||
if v.ID > fileID {
|
||||
fileID = v.ID
|
||||
}
|
||||
}
|
||||
if fileID == 0 {
|
||||
fmt.Printf("Failed to fetch Jumploader latest file: no file found")
|
||||
os.Exit(1)
|
||||
}
|
||||
exportData.JumploaderFileID = fileID
|
||||
}
|
||||
|
||||
cfFileRefs = append(cfFileRefs, packinterop.AddonFileReference{
|
||||
ProjectID: jumploaderProjectID,
|
||||
FileID: exportData.JumploaderFileID,
|
||||
OptionalDisabled: false,
|
||||
})
|
||||
|
||||
err = createJumploaderConfig(exp, fabricVersion)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating Jumploader config file: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
if dataUpdated {
|
||||
newMap, err := exportData.ToMap()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to update metadata: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if pack.Export == nil {
|
||||
pack.Export = make(map[string]map[string]interface{})
|
||||
}
|
||||
pack.Export["curseforge"] = newMap
|
||||
err = pack.Write()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
manifestFile, err := exp.Create("manifest.json")
|
||||
if err != nil {
|
||||
_ = exp.Close()
|
||||
@ -146,7 +228,7 @@ var exportCmd = &cobra.Command{
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = packinterop.WriteManifestFromPack(pack, cfFileRefs, exportData.ProjectID, manifestFile)
|
||||
err = packinterop.WriteManifestFromPack(pack, cfFileRefs, exportData.ProjectID, exportData.JumploaderForgeVersion, manifestFile)
|
||||
if err != nil {
|
||||
_ = exp.Close()
|
||||
_ = expFile.Close()
|
||||
@ -241,6 +323,39 @@ func createModlist(zw *zip.Writer, mods []core.Mod) error {
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
type jumploaderConfig struct {
|
||||
ConfigVersion int `json:"configVersion"`
|
||||
Sources []string `json:"sources"`
|
||||
GameVersion string `json:"gameVersion"`
|
||||
GameSide string `json:"gameSide"`
|
||||
DisableUI bool `json:"disableUI"`
|
||||
LoadJarsFromFolder interface{} `json:"loadJarsFromFolder"`
|
||||
OverrideMainClass interface{} `json:"overrideMainClass"`
|
||||
PinFabricLoaderVersion string `json:"pinFabricLoaderVersion"`
|
||||
}
|
||||
|
||||
func createJumploaderConfig(zw *zip.Writer, loaderVersion string) error {
|
||||
jumploaderConfigFile, err := zw.Create("overrides/config/jumploader.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
j := jumploaderConfig{
|
||||
ConfigVersion: 2,
|
||||
Sources: []string{"minecraft", "fabric"},
|
||||
GameVersion: "current",
|
||||
GameSide: "current",
|
||||
DisableUI: false,
|
||||
LoadJarsFromFolder: nil,
|
||||
OverrideMainClass: nil,
|
||||
PinFabricLoaderVersion: loaderVersion,
|
||||
}
|
||||
|
||||
w := json.NewEncoder(jumploaderConfigFile)
|
||||
w.SetIndent("", " ") // Match CF export
|
||||
return w.Encode(j)
|
||||
}
|
||||
|
||||
func loadMods(index core.Index) []core.Mod {
|
||||
modPaths := index.GetAllMods()
|
||||
mods := make([]core.Mod, len(modPaths))
|
||||
|
@ -69,7 +69,7 @@ type AddonFileReference struct {
|
||||
OptionalDisabled bool
|
||||
}
|
||||
|
||||
func WriteManifestFromPack(pack core.Pack, fileRefs []AddonFileReference, projectID int, out io.Writer) error {
|
||||
func WriteManifestFromPack(pack core.Pack, fileRefs []AddonFileReference, projectID int, jumploaderForgeVersion string, out io.Writer) error {
|
||||
files := make([]struct {
|
||||
ProjectID int `json:"projectID"`
|
||||
FileID int `json:"fileID"`
|
||||
@ -90,6 +90,11 @@ func WriteManifestFromPack(pack core.Pack, fileRefs []AddonFileReference, projec
|
||||
ID: "forge-" + forgeVersion,
|
||||
Primary: true,
|
||||
})
|
||||
} else if len(jumploaderForgeVersion) > 0 {
|
||||
modLoaders = append(modLoaders, modLoaderDef{
|
||||
ID: "forge-" + jumploaderForgeVersion,
|
||||
Primary: true,
|
||||
})
|
||||
}
|
||||
|
||||
manifest := cursePackMeta{
|
||||
|
Loading…
x
Reference in New Issue
Block a user