From b9d8b763a74ee9fd2de18256353c4737192a462b Mon Sep 17 00:00:00 2001 From: Samuel Walker Date: Fri, 1 Nov 2024 18:08:29 -0600 Subject: [PATCH] working on forge integration --- fclauncher/InstanceManager.go | 45 +++++++ fclauncher/forge.go | 115 ++++++++++++++++++ fclauncher/frontend/src/Instances.svelte | 10 +- .../wailsjs/go/main/InstanceManager.d.ts | 2 + .../wailsjs/go/main/InstanceManager.js | 4 + 5 files changed, 174 insertions(+), 2 deletions(-) diff --git a/fclauncher/InstanceManager.go b/fclauncher/InstanceManager.go index b7113bb..c094658 100644 --- a/fclauncher/InstanceManager.go +++ b/fclauncher/InstanceManager.go @@ -289,6 +289,10 @@ func (i *InstanceManager) LaunchInstance(instance string) { if err != nil { fmt.Printf("unable to get launch args: %s\n", err) } + if instanceObject.ForgeVersion != "" { + args = append(args, "--launchTarget") + args = append(args, "forge_client") + } fmt.Printf("Args: %+v", args) child := exec.Command(filepath.Join(dir, "java", fmt.Sprintf("java-%d-%s", instanceObject.JavaVersion, suffix), "bin", execName), args...) child.Dir = filepath.Join(dir, "instances", instance, "minecraft") @@ -415,3 +419,44 @@ common: } } } + +func (i *InstanceManager) InstallForge(instance string, forgeVersion string) { + instanceObject, err := i.GetInstance(instance) + if err != nil { + fmt.Printf("Unable to find instance: %s\n", err) + } + installData, err := GetForgeInstallData(instanceObject.MinecraftVersion, forgeVersion) + if err != nil { + fmt.Printf("Unable to get install data: %s\n", err) + } + dir, _ := os.UserConfigDir() + InstallForgeLibs(instanceObject.MinecraftVersion, forgeVersion, filepath.Join(dir, "FCLauncher", "lib")) + instanceObject.ForgeVersion = forgeVersion +outer: + for _, lib := range installData.Libraries { + tokens := strings.Split(lib.Downloads.Artifact.Path, string(os.PathSeparator)) + pkg := tokens[len(tokens)-2] + instanceObject.Libraries = append(instanceObject.Libraries, lib.Downloads.Artifact.Path) + for ind, path := range instanceObject.Libraries { + tokens := strings.Split(path, string(os.PathSeparator)) + if pkg == tokens[len(tokens)-3] { + instanceObject.Libraries[ind] = filepath.Join(ProcessMavenPath(lib.Name), ProcessMavenFilename(lib.Name)) + fmt.Printf("duplicate library %s\n", pkg) + continue outer + } + } + } + instanceObject.MainClass = installData.MainClass + + f, _ := os.OpenFile(filepath.Join(dir, "FCLauncher", "instances", instance, "instance.json"), os.O_CREATE|os.O_RDWR, 0755) + data, _ := json.Marshal(instanceObject) + defer f.Close() + f.Write(data) + for ind, inst := range i.instances { + if inst.InstanceName == instance { + i.instances[ind] = instanceObject + break + } + } + +} diff --git a/fclauncher/forge.go b/fclauncher/forge.go index 7e6cfc6..68fdfa5 100644 --- a/fclauncher/forge.go +++ b/fclauncher/forge.go @@ -1,10 +1,18 @@ package main import ( + "crypto/sha1" + "encoding/hex" + "encoding/json" "fmt" "io" "net/http" + "os" + "path/filepath" "strings" + "time" + + "github.com/zhyee/zipstream" ) type Forge struct{} @@ -15,6 +23,31 @@ type ForgeVersion struct { Url string } +type ForgeLibraryArtifact struct { + Path string + Url string + Sha1 string +} + +type ForgeLibraryDownload struct { + Artifact ForgeLibraryArtifact +} + +type ForgeLibrary struct { + Name string + Downloads ForgeLibraryDownload +} + +type ForgeInstallData struct { + Id string + Time time.Time + ReleaseTime time.Time + InheritsFrom string + Type string + MainClass string + Libraries []ForgeLibrary +} + func parseForgeVersions(html string) []ForgeVersion { lines := strings.Split(html, "\n") parsing := false @@ -68,3 +101,85 @@ func (Forge) GetForgeVersions(mcVersion string) ([]ForgeVersion, error) { data, _ := io.ReadAll(resp.Body) return parseForgeVersions(string(data)), nil } + +func GetForgeInstallDataFromVersion(version ForgeVersion) (ForgeInstallData, error) { + resp, err := http.Get(version.Url) + if err != nil { + return ForgeInstallData{}, fmt.Errorf("unable to pull jar file: %e", err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return ForgeInstallData{}, fmt.Errorf("unable to pull jar file: %s", resp.Status) + } + zs := zipstream.NewReader(resp.Body) + for { + entry, err := zs.GetNextEntry() + if err == io.EOF { + break + } + if entry.Name != "version.json" { + continue + } + f, _ := entry.Open() + defer f.Close() + data, _ := io.ReadAll(f) + installData := ForgeInstallData{} + json.Unmarshal(data, &installData) + return installData, nil + } + return ForgeInstallData{}, fmt.Errorf("unable to find version.json") +} + +func GetForgeInstallData(mcVersion string, forgeVersion string) (ForgeInstallData, error) { + versions, err := Forge{}.GetForgeVersions(mcVersion) + if err != nil { + return ForgeInstallData{}, fmt.Errorf("failed to pull forge versions: %e", err) + } + for _, version := range versions { + if version.Version == forgeVersion { + return GetForgeInstallDataFromVersion(version) + } + } + return ForgeInstallData{}, fmt.Errorf("unable to find the requested version") +} + +func InstallForgeLibs(mcVersion string, forgeVersion string, libDir string) { + installData, err := GetForgeInstallData(mcVersion, forgeVersion) + if err != nil { + fmt.Printf("Unable to get install data: %s\n", err) + } + for _, lib := range installData.Libraries { + if _, err := os.Stat(filepath.Join(libDir, lib.Downloads.Artifact.Path)); err == nil { + if f, err := os.OpenFile(filepath.Join(libDir, lib.Downloads.Artifact.Path), os.O_RDONLY, 0755); err == nil { + defer f.Close() + data, _ := io.ReadAll(f) + sha := sha1.Sum(data) + if hex.EncodeToString(sha[:20]) == lib.Downloads.Artifact.Sha1 { + continue + } + } + } + resp, err := http.Get(lib.Downloads.Artifact.Url) + if err != nil { + fmt.Printf("Unable to download library %s: %s\n", lib.Name, err) + continue + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + fmt.Printf("Unable to download library %s: %s\n", lib.Name, resp.Status) + continue + } + tokens := strings.Split(lib.Downloads.Artifact.Path, "/") + path := "" + for ind, token := range tokens { + if ind == len(tokens)-1 { + break + } + path = filepath.Join(path, token) + } + os.MkdirAll(filepath.Join(libDir, path), 0755) + f, _ := os.OpenFile(filepath.Join(libDir, lib.Downloads.Artifact.Path), os.O_CREATE|os.O_RDWR, 0755) + defer f.Close() + io.Copy(f, resp.Body) + } +} diff --git a/fclauncher/frontend/src/Instances.svelte b/fclauncher/frontend/src/Instances.svelte index 63e1549..9e71d7d 100644 --- a/fclauncher/frontend/src/Instances.svelte +++ b/fclauncher/frontend/src/Instances.svelte @@ -1,5 +1,5 @@