mirror of
				https://github.com/packwiz/packwiz.git
				synced 2025-11-03 19:54:32 +01:00 
			
		
		
		
	Eradicate variable-size integer types where not used by interface or as index (fixes #107)
This commit is contained in:
		@@ -117,7 +117,7 @@ var urlRegexes = [...]*regexp.Regexp{
 | 
			
		||||
	regexp.MustCompile("^(?P<slug>[a-z][\\da-z\\-_]{0,127})$"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseSlugOrUrl(url string) (game string, category string, slug string, fileID int, err error) {
 | 
			
		||||
func parseSlugOrUrl(url string) (game string, category string, slug string, fileID uint32, err error) {
 | 
			
		||||
	for _, r := range urlRegexes {
 | 
			
		||||
		matches := r.FindStringSubmatch(url)
 | 
			
		||||
		if matches != nil {
 | 
			
		||||
@@ -132,7 +132,9 @@ func parseSlugOrUrl(url string) (game string, category string, slug string, file
 | 
			
		||||
			}
 | 
			
		||||
			if i := r.SubexpIndex("fileID"); i >= 0 {
 | 
			
		||||
				if matches[i] != "" {
 | 
			
		||||
					fileID, err = strconv.Atoi(matches[i])
 | 
			
		||||
					var f uint64
 | 
			
		||||
					f, err = strconv.ParseUint(matches[i], 10, 32)
 | 
			
		||||
					fileID = uint32(f)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
@@ -214,7 +216,7 @@ func createModFile(modInfo modInfo, fileInfo modFileInfo, index *core.Index, opt
 | 
			
		||||
	return index.RefreshFileWithHash(path, format, hash, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getSearchLoaderType(pack core.Pack) int {
 | 
			
		||||
func getSearchLoaderType(pack core.Pack) modloaderType {
 | 
			
		||||
	dependencies := pack.Versions
 | 
			
		||||
 | 
			
		||||
	_, hasFabric := dependencies["fabric"]
 | 
			
		||||
@@ -235,7 +237,7 @@ func getSearchLoaderType(pack core.Pack) int {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func matchLoaderType(packLoaders []string, modLoaderType int) bool {
 | 
			
		||||
func matchLoaderType(packLoaders []string, modLoaderType modloaderType) bool {
 | 
			
		||||
	if len(packLoaders) == 0 || modLoaderType == modloaderTypeAny {
 | 
			
		||||
		return true
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -290,8 +292,8 @@ func matchGameVersions(mcVersion string, modMcVersions []string) bool {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type cfUpdateData struct {
 | 
			
		||||
	ProjectID int `mapstructure:"project-id"`
 | 
			
		||||
	FileID    int `mapstructure:"file-id"`
 | 
			
		||||
	ProjectID uint32 `mapstructure:"project-id"`
 | 
			
		||||
	FileID    uint32 `mapstructure:"file-id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u cfUpdateData) ToMap() (map[string]interface{}, error) {
 | 
			
		||||
@@ -311,13 +313,13 @@ func (u cfUpdater) ParseUpdate(updateUnparsed map[string]interface{}) (interface
 | 
			
		||||
type cachedStateStore struct {
 | 
			
		||||
	modInfo
 | 
			
		||||
	hasFileInfo bool
 | 
			
		||||
	fileID      int
 | 
			
		||||
	fileID      uint32
 | 
			
		||||
	fileInfo    modFileInfo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u cfUpdater) CheckUpdate(mods []core.Mod, mcVersion string, pack core.Pack) ([]core.UpdateCheck, error) {
 | 
			
		||||
	results := make([]core.UpdateCheck, len(mods))
 | 
			
		||||
	modIDs := make([]int, len(mods))
 | 
			
		||||
	modIDs := make([]uint32, len(mods))
 | 
			
		||||
	modInfos := make([]modInfo, len(mods))
 | 
			
		||||
 | 
			
		||||
	for i, v := range mods {
 | 
			
		||||
@@ -438,7 +440,7 @@ func (u cfUpdater) DoUpdate(mods []*core.Mod, cachedState []interface{}) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type cfExportData struct {
 | 
			
		||||
	ProjectID int `mapstructure:"project-id"`
 | 
			
		||||
	ProjectID uint32 `mapstructure:"project-id"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e cfExportData) ToMap() (map[string]interface{}, error) {
 | 
			
		||||
@@ -461,9 +463,9 @@ func (c cfDownloader) GetFilesMetadata(mods []*core.Mod) ([]core.MetaDownloaderD
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	downloaderData := make([]core.MetaDownloaderData, len(mods))
 | 
			
		||||
	indexMap := make(map[int]int)
 | 
			
		||||
	indexMap := make(map[uint32]int)
 | 
			
		||||
	projectMetadata := make([]cfUpdateData, len(mods))
 | 
			
		||||
	fileIDs := make([]int, len(mods))
 | 
			
		||||
	fileIDs := make([]uint32, len(mods))
 | 
			
		||||
	for i, v := range mods {
 | 
			
		||||
		updateData, ok := v.GetParsedUpdateData("curseforge")
 | 
			
		||||
		if !ok {
 | 
			
		||||
@@ -480,7 +482,7 @@ func (c cfDownloader) GetFilesMetadata(mods []*core.Mod) ([]core.MetaDownloaderD
 | 
			
		||||
		return nil, fmt.Errorf("failed to get CurseForge file metadata: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	modIDsToLookup := make([]int, 0)
 | 
			
		||||
	modIDsToLookup := make([]uint32, 0)
 | 
			
		||||
	fileNames := make([]string, len(mods))
 | 
			
		||||
	for _, file := range fileData {
 | 
			
		||||
		if _, ok := indexMap[file.ModID]; !ok {
 | 
			
		||||
@@ -509,7 +511,7 @@ func (c cfDownloader) GetFilesMetadata(mods []*core.Mod) ([]core.MetaDownloaderD
 | 
			
		||||
			downloaderData[indexMap[mod.ID]] = &cfDownloadMetadata{
 | 
			
		||||
				noDistribution: true, // Inverted so the default value is not this (probably doesn't matter)
 | 
			
		||||
				name:           mod.Name,
 | 
			
		||||
				websiteUrl:     mod.Links.WebsiteURL + "/files/" + strconv.Itoa(fileIDs[indexMap[mod.ID]]),
 | 
			
		||||
				websiteUrl:     mod.Links.WebsiteURL + "/files/" + strconv.FormatUint(uint64(fileIDs[indexMap[mod.ID]]), 10),
 | 
			
		||||
				fileName:       fileNames[indexMap[mod.ID]],
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,8 +32,8 @@ var detectCmd = &cobra.Command{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Walk files in the mods folder
 | 
			
		||||
		var hashes []int
 | 
			
		||||
		modPaths := make(map[int]string)
 | 
			
		||||
		var hashes []uint32
 | 
			
		||||
		modPaths := make(map[uint32]string)
 | 
			
		||||
		err = filepath.Walk("mods", func(path string, info os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
@@ -51,8 +51,8 @@ var detectCmd = &cobra.Command{
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			hash := getByteArrayHash(bytes)
 | 
			
		||||
			hashes = append(hashes, int(hash))
 | 
			
		||||
			modPaths[int(hash)] = path
 | 
			
		||||
			hashes = append(hashes, hash)
 | 
			
		||||
			modPaths[hash] = path
 | 
			
		||||
			return nil
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -132,8 +132,8 @@ func init() {
 | 
			
		||||
	curseforgeCmd.AddCommand(detectCmd)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getByteArrayHash(bytes []byte) uint64 {
 | 
			
		||||
	return uint64(murmur.MurmurHash2(computeNormalizedArray(bytes), 1))
 | 
			
		||||
func getByteArrayHash(bytes []byte) uint32 {
 | 
			
		||||
	return murmur.MurmurHash2(computeNormalizedArray(bytes), 1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func computeNormalizedArray(bytes []byte) []byte {
 | 
			
		||||
 
 | 
			
		||||
@@ -238,7 +238,7 @@ func createModlist(zw *zip.Writer, mods []*core.Mod) error {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		project := projectRaw.(cfUpdateData)
 | 
			
		||||
		_, err = w.WriteString("<li><a href=\"https://www.curseforge.com/projects/" + strconv.Itoa(project.ProjectID) + "\">" + mod.Name + "</a></li>\r\n")
 | 
			
		||||
		_, err = w.WriteString("<li><a href=\"https://www.curseforge.com/projects/" + strconv.FormatUint(uint64(project.ProjectID), 10) + "\">" + mod.Name + "</a></li>\r\n")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -185,7 +185,7 @@ var importCmd = &cobra.Command{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		modsList := packImport.Mods()
 | 
			
		||||
		modIDs := make([]int, len(modsList))
 | 
			
		||||
		modIDs := make([]uint32, len(modsList))
 | 
			
		||||
		for i, v := range modsList {
 | 
			
		||||
			modIDs[i] = v.ProjectID
 | 
			
		||||
		}
 | 
			
		||||
@@ -198,17 +198,17 @@ var importCmd = &cobra.Command{
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		modInfosMap := make(map[int]modInfo)
 | 
			
		||||
		modInfosMap := make(map[uint32]modInfo)
 | 
			
		||||
		for _, v := range modInfos {
 | 
			
		||||
			modInfosMap[v.ID] = v
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: multithreading????
 | 
			
		||||
 | 
			
		||||
		modFileInfosMap := make(map[int]modFileInfo)
 | 
			
		||||
		modFileInfosMap := make(map[uint32]modFileInfo)
 | 
			
		||||
		referencedModPaths := make([]string, 0, len(modsList))
 | 
			
		||||
		successes := 0
 | 
			
		||||
		remainingFileIDs := make([]int, 0, len(modsList))
 | 
			
		||||
		remainingFileIDs := make([]uint32, 0, len(modsList))
 | 
			
		||||
 | 
			
		||||
		// 1st pass: query mod metadata for every CurseForge file
 | 
			
		||||
		for _, v := range modsList {
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ var installCmd = &cobra.Command{
 | 
			
		||||
 | 
			
		||||
		game := gameFlag
 | 
			
		||||
		category := categoryFlag
 | 
			
		||||
		var modID, fileID int
 | 
			
		||||
		var modID, fileID uint32
 | 
			
		||||
		var slug string
 | 
			
		||||
 | 
			
		||||
		// If mod/file IDs are provided in command line, use those
 | 
			
		||||
@@ -122,7 +122,7 @@ var installCmd = &cobra.Command{
 | 
			
		||||
 | 
			
		||||
		if len(fileInfoData.Dependencies) > 0 {
 | 
			
		||||
			var depsInstallable []installableDep
 | 
			
		||||
			var depIDPendingQueue []int
 | 
			
		||||
			var depIDPendingQueue []uint32
 | 
			
		||||
			for _, dep := range fileInfoData.Dependencies {
 | 
			
		||||
				if dep.Type == dependencyTypeRequired {
 | 
			
		||||
					depIDPendingQueue = append(depIDPendingQueue, dep.ModID)
 | 
			
		||||
@@ -133,7 +133,7 @@ var installCmd = &cobra.Command{
 | 
			
		||||
				fmt.Println("Finding dependencies...")
 | 
			
		||||
 | 
			
		||||
				cycles := 0
 | 
			
		||||
				var installedIDList []int
 | 
			
		||||
				var installedIDList []uint32
 | 
			
		||||
				for len(depIDPendingQueue) > 0 && cycles < maxCycles {
 | 
			
		||||
					if installedIDList == nil {
 | 
			
		||||
						// Get modids of all mods
 | 
			
		||||
@@ -278,14 +278,14 @@ func (r modResultsList) Len() int {
 | 
			
		||||
	return len(r)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func searchCurseforgeInternal(searchTerm string, isSlug bool, game string, category string, mcVersion string, searchLoaderType int) (bool, modInfo) {
 | 
			
		||||
func searchCurseforgeInternal(searchTerm string, isSlug bool, game string, category string, mcVersion string, searchLoaderType modloaderType) (bool, modInfo) {
 | 
			
		||||
	if isSlug {
 | 
			
		||||
		fmt.Println("Looking up CurseForge slug...")
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Println("Searching CurseForge...")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var gameID, categoryID, classID int
 | 
			
		||||
	var gameID, categoryID, classID uint32
 | 
			
		||||
	if game == "minecraft" {
 | 
			
		||||
		gameID = 432
 | 
			
		||||
	}
 | 
			
		||||
@@ -308,7 +308,7 @@ func searchCurseforgeInternal(searchTerm string, isSlug bool, game string, categ
 | 
			
		||||
					fmt.Printf("Failed to lookup game %s: selected game does not have a public API!\n", game)
 | 
			
		||||
					os.Exit(1)
 | 
			
		||||
				}
 | 
			
		||||
				gameID = int(v.ID)
 | 
			
		||||
				gameID = v.ID
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -409,7 +409,7 @@ func searchCurseforgeInternal(searchTerm string, isSlug bool, game string, categ
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getLatestFile(modInfoData modInfo, mcVersion string, fileID int, packLoaders []string) (modFileInfo, error) {
 | 
			
		||||
func getLatestFile(modInfoData modInfo, mcVersion string, fileID uint32, packLoaders []string) (modFileInfo, error) {
 | 
			
		||||
	if fileID == 0 {
 | 
			
		||||
		var fileInfoData modFileInfo
 | 
			
		||||
		fileInfoObtained := false
 | 
			
		||||
@@ -455,8 +455,8 @@ func getLatestFile(modInfoData modInfo, mcVersion string, fileID int, packLoader
 | 
			
		||||
	return fileInfoData, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var addonIDFlag int
 | 
			
		||||
var fileIDFlag int
 | 
			
		||||
var addonIDFlag uint32
 | 
			
		||||
var fileIDFlag uint32
 | 
			
		||||
 | 
			
		||||
var gameFlag string
 | 
			
		||||
var categoryFlag string
 | 
			
		||||
@@ -464,8 +464,8 @@ var categoryFlag string
 | 
			
		||||
func init() {
 | 
			
		||||
	curseforgeCmd.AddCommand(installCmd)
 | 
			
		||||
 | 
			
		||||
	installCmd.Flags().IntVar(&addonIDFlag, "addon-id", 0, "The CurseForge project ID to use")
 | 
			
		||||
	installCmd.Flags().IntVar(&fileIDFlag, "file-id", 0, "The CurseForge file ID to use")
 | 
			
		||||
	installCmd.Flags().Uint32Var(&addonIDFlag, "addon-id", 0, "The CurseForge project ID to use")
 | 
			
		||||
	installCmd.Flags().Uint32Var(&fileIDFlag, "file-id", 0, "The CurseForge file ID to use")
 | 
			
		||||
	installCmd.Flags().StringVar(&gameFlag, "game", "minecraft", "The game to add files from (slug, as stored in URLs); the game in the URL takes precedence")
 | 
			
		||||
	installCmd.Flags().StringVar(&categoryFlag, "category", "", "The category to add files from (slug, as stored in URLs); the category in the URL takes precedence")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ var openCmd = &cobra.Command{
 | 
			
		||||
		}
 | 
			
		||||
		cfUpdateData := updateData.(cfUpdateData)
 | 
			
		||||
		fmt.Println("Opening browser...")
 | 
			
		||||
		url := "https://www.curseforge.com/projects/" + strconv.Itoa(cfUpdateData.ProjectID)
 | 
			
		||||
		url := "https://www.curseforge.com/projects/" + strconv.FormatUint(uint64(cfUpdateData.ProjectID), 10)
 | 
			
		||||
		err = open.Start(url)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println("Opening page failed, direct link:")
 | 
			
		||||
 
 | 
			
		||||
@@ -8,15 +8,15 @@ type cursePackMeta struct {
 | 
			
		||||
		ModLoaders []modLoaderDef `json:"modLoaders"`
 | 
			
		||||
	} `json:"minecraft"`
 | 
			
		||||
	ManifestType    string `json:"manifestType"`
 | 
			
		||||
	ManifestVersion int    `json:"manifestVersion"`
 | 
			
		||||
	ManifestVersion uint32 `json:"manifestVersion"`
 | 
			
		||||
	NameInternal    string `json:"name"`
 | 
			
		||||
	Version         string `json:"version"`
 | 
			
		||||
	Author          string `json:"author"`
 | 
			
		||||
	ProjectID       int    `json:"projectID"`
 | 
			
		||||
	ProjectID       uint32 `json:"projectID"`
 | 
			
		||||
	Files           []struct {
 | 
			
		||||
		ProjectID int  `json:"projectID"`
 | 
			
		||||
		FileID    int  `json:"fileID"`
 | 
			
		||||
		Required  bool `json:"required"`
 | 
			
		||||
		ProjectID uint32 `json:"projectID"`
 | 
			
		||||
		FileID    uint32 `json:"fileID"`
 | 
			
		||||
		Required  bool   `json:"required"`
 | 
			
		||||
	} `json:"files"`
 | 
			
		||||
	Overrides string `json:"overrides"`
 | 
			
		||||
	importSrc ImportPackSource
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,10 @@ type twitchInstalledPackMeta struct {
 | 
			
		||||
	} `json:"baseModLoader"`
 | 
			
		||||
	ModpackOverrides []string `json:"modpackOverrides"`
 | 
			
		||||
	ModsInternal     []struct {
 | 
			
		||||
		ID   int `json:"addonID"`
 | 
			
		||||
		ID   uint32 `json:"addonID"`
 | 
			
		||||
		File struct {
 | 
			
		||||
			// I've given up on using this cached data, just going to re-request it
 | 
			
		||||
			ID int `json:"id"`
 | 
			
		||||
			ID uint32 `json:"id"`
 | 
			
		||||
			// Used to determine if the mod is optional-disabled
 | 
			
		||||
			FileNameOnDisk string
 | 
			
		||||
		} `json:"installedFile"`
 | 
			
		||||
 
 | 
			
		||||
@@ -63,23 +63,23 @@ func ReadMetadata(s ImportPackSource) ImportPackMetadata {
 | 
			
		||||
 | 
			
		||||
// AddonFileReference is a struct to reference a single file on CurseForge
 | 
			
		||||
type AddonFileReference struct {
 | 
			
		||||
	ProjectID int
 | 
			
		||||
	FileID    int
 | 
			
		||||
	ProjectID uint32
 | 
			
		||||
	FileID    uint32
 | 
			
		||||
	// OptionalDisabled is true if the file is optional and disabled (turned off in Twitch launcher)
 | 
			
		||||
	OptionalDisabled bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func WriteManifestFromPack(pack core.Pack, fileRefs []AddonFileReference, projectID int, out io.Writer) error {
 | 
			
		||||
func WriteManifestFromPack(pack core.Pack, fileRefs []AddonFileReference, projectID uint32, out io.Writer) error {
 | 
			
		||||
	files := make([]struct {
 | 
			
		||||
		ProjectID int  `json:"projectID"`
 | 
			
		||||
		FileID    int  `json:"fileID"`
 | 
			
		||||
		Required  bool `json:"required"`
 | 
			
		||||
		ProjectID uint32 `json:"projectID"`
 | 
			
		||||
		FileID    uint32 `json:"fileID"`
 | 
			
		||||
		Required  bool   `json:"required"`
 | 
			
		||||
	}, len(fileRefs))
 | 
			
		||||
	for i, fr := range fileRefs {
 | 
			
		||||
		files[i] = struct {
 | 
			
		||||
			ProjectID int  `json:"projectID"`
 | 
			
		||||
			FileID    int  `json:"fileID"`
 | 
			
		||||
			Required  bool `json:"required"`
 | 
			
		||||
			ProjectID uint32 `json:"projectID"`
 | 
			
		||||
			FileID    uint32 `json:"fileID"`
 | 
			
		||||
			Required  bool   `json:"required"`
 | 
			
		||||
		}{ProjectID: fr.ProjectID, FileID: fr.FileID, Required: !fr.OptionalDisabled}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -85,16 +85,20 @@ func (c *cfApiClient) makePost(endpoint string, body io.Reader) (*http.Response,
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type fileType uint8
 | 
			
		||||
 | 
			
		||||
//noinspection GoUnusedConst
 | 
			
		||||
const (
 | 
			
		||||
	fileTypeRelease int = iota + 1
 | 
			
		||||
	fileTypeRelease fileType = iota + 1
 | 
			
		||||
	fileTypeBeta
 | 
			
		||||
	fileTypeAlpha
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type dependencyType uint8
 | 
			
		||||
 | 
			
		||||
//noinspection GoUnusedConst
 | 
			
		||||
const (
 | 
			
		||||
	dependencyTypeEmbedded int = iota + 1
 | 
			
		||||
	dependencyTypeEmbedded dependencyType = iota + 1
 | 
			
		||||
	dependencyTypeOptional
 | 
			
		||||
	dependencyTypeRequired
 | 
			
		||||
	dependencyTypeTool
 | 
			
		||||
@@ -102,10 +106,12 @@ const (
 | 
			
		||||
	dependencyTypeInclude
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type modloaderType uint8
 | 
			
		||||
 | 
			
		||||
//noinspection GoUnusedConst
 | 
			
		||||
const (
 | 
			
		||||
	// modloaderTypeAny should not be passed to the API - it does not work
 | 
			
		||||
	modloaderTypeAny int = iota
 | 
			
		||||
	modloaderTypeAny modloaderType = iota
 | 
			
		||||
	modloaderTypeForge
 | 
			
		||||
	modloaderTypeCauldron
 | 
			
		||||
	modloaderTypeLiteloader
 | 
			
		||||
@@ -131,9 +137,11 @@ var modloaderIds = [...]string{
 | 
			
		||||
	"quilt",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type hashAlgo uint8
 | 
			
		||||
 | 
			
		||||
//noinspection GoUnusedConst
 | 
			
		||||
const (
 | 
			
		||||
	hashAlgoSHA1 int = iota + 1
 | 
			
		||||
	hashAlgoSHA1 hashAlgo = iota + 1
 | 
			
		||||
	hashAlgoMD5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -142,7 +150,7 @@ type modInfo struct {
 | 
			
		||||
	Name                   string        `json:"name"`
 | 
			
		||||
	Summary                string        `json:"summary"`
 | 
			
		||||
	Slug                   string        `json:"slug"`
 | 
			
		||||
	ID                     int           `json:"id"`
 | 
			
		||||
	ID                     uint32        `json:"id"`
 | 
			
		||||
	GameID                 uint32        `json:"gameId"`
 | 
			
		||||
	PrimaryCategoryID      uint32        `json:"primaryCategoryId"`
 | 
			
		||||
	ClassID                uint32        `json:"classId"`
 | 
			
		||||
@@ -150,11 +158,11 @@ type modInfo struct {
 | 
			
		||||
	GameVersionLatestFiles []struct {
 | 
			
		||||
		// TODO: check how twitch launcher chooses which one to use, when you are on beta/alpha channel?!
 | 
			
		||||
		// or does it not have the concept of release channels?!
 | 
			
		||||
		GameVersion string `json:"gameVersion"`
 | 
			
		||||
		ID          int    `json:"fileId"`
 | 
			
		||||
		Name        string `json:"filename"`
 | 
			
		||||
		FileType    int    `json:"releaseType"`
 | 
			
		||||
		Modloader   int    `json:"modLoader"`
 | 
			
		||||
		GameVersion string        `json:"gameVersion"`
 | 
			
		||||
		ID          uint32        `json:"fileId"`
 | 
			
		||||
		Name        string        `json:"filename"`
 | 
			
		||||
		FileType    fileType      `json:"releaseType"`
 | 
			
		||||
		Modloader   modloaderType `json:"modLoader"`
 | 
			
		||||
	} `json:"latestFilesIndexes"`
 | 
			
		||||
	ModLoaders []string `json:"modLoaders"`
 | 
			
		||||
	Links      struct {
 | 
			
		||||
@@ -162,12 +170,12 @@ type modInfo struct {
 | 
			
		||||
	} `json:"links"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getModInfo(modID int) (modInfo, error) {
 | 
			
		||||
func (c *cfApiClient) getModInfo(modID uint32) (modInfo, error) {
 | 
			
		||||
	var infoRes struct {
 | 
			
		||||
		Data modInfo `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idStr := strconv.Itoa(modID)
 | 
			
		||||
	idStr := strconv.FormatUint(uint64(modID), 10)
 | 
			
		||||
	resp, err := c.makeGet("/v1/mods/" + idStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return modInfo{}, fmt.Errorf("failed to request addon data for ID %d: %w", modID, err)
 | 
			
		||||
@@ -185,13 +193,13 @@ func (c *cfApiClient) getModInfo(modID int) (modInfo, error) {
 | 
			
		||||
	return infoRes.Data, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getModInfoMultiple(modIDs []int) ([]modInfo, error) {
 | 
			
		||||
func (c *cfApiClient) getModInfoMultiple(modIDs []uint32) ([]modInfo, error) {
 | 
			
		||||
	var infoRes struct {
 | 
			
		||||
		Data []modInfo `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	modIDsData, err := json.Marshal(struct {
 | 
			
		||||
		ModIDs []int `json:"modIds"`
 | 
			
		||||
		ModIDs []uint32 `json:"modIds"`
 | 
			
		||||
	}{
 | 
			
		||||
		ModIDs: modIDs,
 | 
			
		||||
	})
 | 
			
		||||
@@ -214,32 +222,31 @@ func (c *cfApiClient) getModInfoMultiple(modIDs []int) ([]modInfo, error) {
 | 
			
		||||
 | 
			
		||||
// modFileInfo is a subset of the deserialised JSON response from the Curse API for mod files
 | 
			
		||||
type modFileInfo struct {
 | 
			
		||||
	ID           int       `json:"id"`
 | 
			
		||||
	ModID        int       `json:"modId"`
 | 
			
		||||
	ID           uint32    `json:"id"`
 | 
			
		||||
	ModID        uint32    `json:"modId"`
 | 
			
		||||
	FileName     string    `json:"fileName"`
 | 
			
		||||
	FriendlyName string    `json:"displayName"`
 | 
			
		||||
	Date         time.Time `json:"fileDate"`
 | 
			
		||||
	Length       int       `json:"fileLength"`
 | 
			
		||||
	FileType     int       `json:"releaseType"`
 | 
			
		||||
	// fileStatus? means latest/preferred?
 | 
			
		||||
	Length       uint64    `json:"fileLength"`
 | 
			
		||||
	FileType     fileType  `json:"releaseType"`
 | 
			
		||||
	// According to the CurseForge API T&Cs, this must not be saved or cached
 | 
			
		||||
	DownloadURL  string   `json:"downloadUrl"`
 | 
			
		||||
	GameVersions []string `json:"gameVersions"`
 | 
			
		||||
	Fingerprint  int      `json:"fileFingerprint"`
 | 
			
		||||
	Fingerprint  uint32   `json:"fileFingerprint"`
 | 
			
		||||
	Dependencies []struct {
 | 
			
		||||
		ModID int `json:"modId"`
 | 
			
		||||
		Type  int `json:"relationType"`
 | 
			
		||||
		ModID uint32         `json:"modId"`
 | 
			
		||||
		Type  dependencyType `json:"relationType"`
 | 
			
		||||
	} `json:"dependencies"`
 | 
			
		||||
 | 
			
		||||
	Hashes []struct {
 | 
			
		||||
		Value     string `json:"value"`
 | 
			
		||||
		Algorithm int    `json:"algo"`
 | 
			
		||||
		Value     string   `json:"value"`
 | 
			
		||||
		Algorithm hashAlgo `json:"algo"`
 | 
			
		||||
	} `json:"hashes"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i modFileInfo) getBestHash() (hash string, hashFormat string) {
 | 
			
		||||
	// TODO: check if the hash is invalid (e.g. 0)
 | 
			
		||||
	hash = strconv.Itoa(i.Fingerprint)
 | 
			
		||||
	hash = strconv.FormatUint(uint64(i.Fingerprint), 10)
 | 
			
		||||
	hashFormat = "murmur2"
 | 
			
		||||
	hashPreferred := 0
 | 
			
		||||
 | 
			
		||||
@@ -263,13 +270,13 @@ func (i modFileInfo) getBestHash() (hash string, hashFormat string) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getFileInfo(modID int, fileID int) (modFileInfo, error) {
 | 
			
		||||
func (c *cfApiClient) getFileInfo(modID uint32, fileID uint32) (modFileInfo, error) {
 | 
			
		||||
	var infoRes struct {
 | 
			
		||||
		Data modFileInfo `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	modIDStr := strconv.Itoa(modID)
 | 
			
		||||
	fileIDStr := strconv.Itoa(fileID)
 | 
			
		||||
	modIDStr := strconv.FormatUint(uint64(modID), 10)
 | 
			
		||||
	fileIDStr := strconv.FormatUint(uint64(fileID), 10)
 | 
			
		||||
 | 
			
		||||
	resp, err := c.makeGet("/v1/mods/" + modIDStr + "/files/" + fileIDStr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -288,13 +295,13 @@ func (c *cfApiClient) getFileInfo(modID int, fileID int) (modFileInfo, error) {
 | 
			
		||||
	return infoRes.Data, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getFileInfoMultiple(fileIDs []int) ([]modFileInfo, error) {
 | 
			
		||||
func (c *cfApiClient) getFileInfoMultiple(fileIDs []uint32) ([]modFileInfo, error) {
 | 
			
		||||
	var infoRes struct {
 | 
			
		||||
		Data []modFileInfo `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fileIDsData, err := json.Marshal(struct {
 | 
			
		||||
		FileIDs []int `json:"fileIds"`
 | 
			
		||||
		FileIDs []uint32 `json:"fileIds"`
 | 
			
		||||
	}{
 | 
			
		||||
		FileIDs: fileIDs,
 | 
			
		||||
	})
 | 
			
		||||
@@ -315,16 +322,16 @@ func (c *cfApiClient) getFileInfoMultiple(fileIDs []int) ([]modFileInfo, error)
 | 
			
		||||
	return infoRes.Data, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getSearch(searchTerm string, slug string, gameID int, classID int, categoryID int, gameVersion string, modloaderType int) ([]modInfo, error) {
 | 
			
		||||
func (c *cfApiClient) getSearch(searchTerm string, slug string, gameID uint32, classID uint32, categoryID uint32, gameVersion string, modloaderType modloaderType) ([]modInfo, error) {
 | 
			
		||||
	var infoRes struct {
 | 
			
		||||
		Data []modInfo `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	q := url.Values{}
 | 
			
		||||
	q.Set("gameId", strconv.Itoa(gameID))
 | 
			
		||||
	q.Set("gameId", strconv.FormatUint(uint64(gameID), 10))
 | 
			
		||||
	q.Set("pageSize", "10")
 | 
			
		||||
	if classID != 0 {
 | 
			
		||||
		q.Set("classId", strconv.Itoa(classID))
 | 
			
		||||
		q.Set("classId", strconv.FormatUint(uint64(classID), 10))
 | 
			
		||||
	}
 | 
			
		||||
	if slug != "" {
 | 
			
		||||
		q.Set("slug", slug)
 | 
			
		||||
@@ -332,7 +339,7 @@ func (c *cfApiClient) getSearch(searchTerm string, slug string, gameID int, clas
 | 
			
		||||
	// If classID and slug are provided, don't bother filtering by anything else (should be unique)
 | 
			
		||||
	if classID == 0 && slug == "" {
 | 
			
		||||
		if categoryID != 0 {
 | 
			
		||||
			q.Set("categoryId", strconv.Itoa(categoryID))
 | 
			
		||||
			q.Set("categoryId", strconv.FormatUint(uint64(categoryID), 10))
 | 
			
		||||
		}
 | 
			
		||||
		if searchTerm != "" {
 | 
			
		||||
			q.Set("searchFilter", searchTerm)
 | 
			
		||||
@@ -341,7 +348,7 @@ func (c *cfApiClient) getSearch(searchTerm string, slug string, gameID int, clas
 | 
			
		||||
			q.Set("gameVersion", gameVersion)
 | 
			
		||||
		}
 | 
			
		||||
		if modloaderType != modloaderTypeAny {
 | 
			
		||||
			q.Set("modLoaderType", strconv.Itoa(modloaderType))
 | 
			
		||||
			q.Set("modLoaderType", strconv.FormatUint(uint64(modloaderType), 10))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -358,9 +365,11 @@ func (c *cfApiClient) getSearch(searchTerm string, slug string, gameID int, clas
 | 
			
		||||
	return infoRes.Data, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type gameStatus uint8
 | 
			
		||||
 | 
			
		||||
//noinspection GoUnusedConst
 | 
			
		||||
const (
 | 
			
		||||
	gameStatusDraft int = iota + 1
 | 
			
		||||
	gameStatusDraft gameStatus = iota + 1
 | 
			
		||||
	gameStatusTest
 | 
			
		||||
	gameStatusPendingReview
 | 
			
		||||
	gameStatusRejected
 | 
			
		||||
@@ -368,18 +377,20 @@ const (
 | 
			
		||||
	gameStatusLive
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type gameApiStatus uint8
 | 
			
		||||
 | 
			
		||||
//noinspection GoUnusedConst
 | 
			
		||||
const (
 | 
			
		||||
	gameApiStatusPrivate int = iota + 1
 | 
			
		||||
	gameApiStatusPrivate gameApiStatus = iota + 1
 | 
			
		||||
	gameApiStatusPublic
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cfGame struct {
 | 
			
		||||
	ID        uint32 `json:"id"`
 | 
			
		||||
	Name      string `json:"name"`
 | 
			
		||||
	Slug      string `json:"slug"`
 | 
			
		||||
	Status    int    `json:"status"`
 | 
			
		||||
	APIStatus int    `json:"apiStatus"`
 | 
			
		||||
	ID        uint32        `json:"id"`
 | 
			
		||||
	Name      string        `json:"name"`
 | 
			
		||||
	Slug      string        `json:"slug"`
 | 
			
		||||
	Status    gameStatus    `json:"status"`
 | 
			
		||||
	APIStatus gameApiStatus `json:"apiStatus"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getGames() ([]cfGame, error) {
 | 
			
		||||
@@ -401,18 +412,18 @@ func (c *cfApiClient) getGames() ([]cfGame, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type cfCategory struct {
 | 
			
		||||
	ID      int    `json:"id"`
 | 
			
		||||
	ID      uint32 `json:"id"`
 | 
			
		||||
	Slug    string `json:"slug"`
 | 
			
		||||
	IsClass bool   `json:"isClass"`
 | 
			
		||||
	ClassID int    `json:"classId"`
 | 
			
		||||
	ClassID uint32 `json:"classId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getCategories(gameID int) ([]cfCategory, error) {
 | 
			
		||||
func (c *cfApiClient) getCategories(gameID uint32) ([]cfCategory, error) {
 | 
			
		||||
	var infoRes struct {
 | 
			
		||||
		Data []cfCategory `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := c.makeGet("/v1/categories?gameId=" + strconv.Itoa(gameID))
 | 
			
		||||
	resp, err := c.makeGet("/v1/categories?gameId=" + strconv.FormatUint(uint64(gameID), 10))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return []cfCategory{}, fmt.Errorf("failed to retrieve category list for game %v: %w", gameID, err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -428,24 +439,24 @@ func (c *cfApiClient) getCategories(gameID int) ([]cfCategory, error) {
 | 
			
		||||
type addonFingerprintResponse struct {
 | 
			
		||||
	IsCacheBuilt bool `json:"isCacheBuilt"`
 | 
			
		||||
	ExactMatches []struct {
 | 
			
		||||
		ID          int           `json:"id"`
 | 
			
		||||
		ID          uint32        `json:"id"`
 | 
			
		||||
		File        modFileInfo   `json:"file"`
 | 
			
		||||
		LatestFiles []modFileInfo `json:"latestFiles"`
 | 
			
		||||
	} `json:"exactMatches"`
 | 
			
		||||
	ExactFingerprints        []int    `json:"exactFingerprints"`
 | 
			
		||||
	PartialMatches           []int    `json:"partialMatches"`
 | 
			
		||||
	ExactFingerprints        []uint32 `json:"exactFingerprints"`
 | 
			
		||||
	PartialMatches           []uint32 `json:"partialMatches"`
 | 
			
		||||
	PartialMatchFingerprints struct{} `json:"partialMatchFingerprints"`
 | 
			
		||||
	InstalledFingerprints    []int    `json:"installedFingerprints"`
 | 
			
		||||
	UnmatchedFingerprints    []int    `json:"unmatchedFingerprints"`
 | 
			
		||||
	InstalledFingerprints    []uint32 `json:"installedFingerprints"`
 | 
			
		||||
	UnmatchedFingerprints    []uint32 `json:"unmatchedFingerprints"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cfApiClient) getFingerprintInfo(hashes []int) (addonFingerprintResponse, error) {
 | 
			
		||||
func (c *cfApiClient) getFingerprintInfo(hashes []uint32) (addonFingerprintResponse, error) {
 | 
			
		||||
	var infoRes struct {
 | 
			
		||||
		Data addonFingerprintResponse `json:"data"`
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hashesData, err := json.Marshal(struct {
 | 
			
		||||
		Fingerprints []int `json:"fingerprints"`
 | 
			
		||||
		Fingerprints []uint32 `json:"fingerprints"`
 | 
			
		||||
	}{
 | 
			
		||||
		Fingerprints: hashes,
 | 
			
		||||
	})
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ type Mod struct {
 | 
			
		||||
	} `json:"license"`
 | 
			
		||||
	ClientSide string   `json:"client_side"` //The support range for the client mod - required, optional, unsupported, or unknown
 | 
			
		||||
	ServerSide string   `json:"server_side"` //The support range for the server mod - required, optional, unsupported, or unknown
 | 
			
		||||
	Downloads  int      `json:"downloads"`   //The total number of downloads the mod has
 | 
			
		||||
	Downloads  uint32   `json:"downloads"`   //The total number of downloads the mod has
 | 
			
		||||
	Categories []string `json:"categories"`  //A list of the categories that the mod is in
 | 
			
		||||
	Versions   []string `json:"versions"`    //A list of ids for versions of the mod
 | 
			
		||||
	IconUrl    string   `json:"icon_url"`    //The URL of the icon of the mod (Optional)
 | 
			
		||||
@@ -74,7 +74,7 @@ type ModResult struct {
 | 
			
		||||
	Description   string   `json:"description"`    //A short description of the mod
 | 
			
		||||
	Categories    []string `json:"categories"`     //A list of the categories the mod is in
 | 
			
		||||
	Versions      []string `json:"versions"`       //A list of the minecraft versions supported by the mod
 | 
			
		||||
	Downloads     int      `json:"downloads"`      //The total number of downloads for the mod
 | 
			
		||||
	Downloads     uint32   `json:"downloads"`      //The total number of downloads for the mod
 | 
			
		||||
	PageUrl       string   `json:"page_url"`       //A link to the mod's main page;
 | 
			
		||||
	IconUrl       string   `json:"icon_url"`       //The url of the mod's icon
 | 
			
		||||
	AuthorUrl     string   `json:"author_url"`     //The url of the mod's author
 | 
			
		||||
@@ -89,9 +89,9 @@ type ModResult struct {
 | 
			
		||||
 | 
			
		||||
type ModSearchResult struct {
 | 
			
		||||
	Hits      []ModResult `json:"hits"`       //The list of results
 | 
			
		||||
	Offset    int         `json:"offset"`     //The number of results that were skipped by the query
 | 
			
		||||
	Limit     int         `json:"limit"`      //The number of mods returned by the query
 | 
			
		||||
	TotalHits int         `json:"total_hits"` //The total number of mods that the query found
 | 
			
		||||
	Offset    uint32      `json:"offset"`     //The number of results that were skipped by the query
 | 
			
		||||
	Limit     uint32      `json:"limit"`      //The number of mods returned by the query
 | 
			
		||||
	TotalHits uint32      `json:"total_hits"` //The total number of mods that the query found
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Version struct {
 | 
			
		||||
@@ -103,7 +103,7 @@ type Version struct {
 | 
			
		||||
	VersionNumber string        `json:"version_number"` //The version number. Ideally will follow semantic versioning
 | 
			
		||||
	Changelog     string        `json:"changelog"`      //The changelog for this version of the mod. (Optional)
 | 
			
		||||
	DatePublished string        `json:"date_published"` //The date that this version was published
 | 
			
		||||
	Downloads     int           `json:"downloads"`      //The number of downloads this specific version has
 | 
			
		||||
	Downloads     uint32        `json:"downloads"`      //The number of downloads this specific version has
 | 
			
		||||
	VersionType   string        `json:"version_type"`   //The type of the release - alpha, beta, or release
 | 
			
		||||
	Files         []VersionFile `json:"files"`          //A list of files available for download for this version
 | 
			
		||||
	//Dependencies  []string      `json:"dependencies"`   //A list of specific versions of mods that this version depends on
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package modrinth
 | 
			
		||||
 | 
			
		||||
type Pack struct {
 | 
			
		||||
	FormatVersion int               `json:"formatVersion"`
 | 
			
		||||
	FormatVersion uint32            `json:"formatVersion"`
 | 
			
		||||
	Game          string            `json:"game"`
 | 
			
		||||
	VersionID     string            `json:"versionId"`
 | 
			
		||||
	Name          string            `json:"name"`
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user