FCLauncher/fclauncher/InstanceManager.go

415 lines
14 KiB
Go
Raw Normal View History

package main
import (
2024-10-26 18:14:12 -06:00
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
2024-10-26 18:14:12 -06:00
"runtime"
"strconv"
"strings"
2024-10-30 19:11:24 -06:00
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
)
type Instance struct {
InstanceName string
ModpackId string
ModpackVersion string
MinecraftVersion string
ForgeVersion string
NeoForgeVersion string
FabricVersion string
QuiltVersion string
JavaVersion int
2024-10-31 16:23:38 -06:00
Libraries []string
MainClass string
}
type InstanceManager struct {
instances []Instance
app *App
}
2024-10-26 18:14:12 -06:00
type mmcpack struct {
Components []component
}
type component struct {
Uid string
Version string
}
func (i *InstanceManager)SearchInstances() {
i.instances = []Instance{}
dir, _ := os.UserConfigDir()
dir = filepath.Join(dir, "FCLauncher", "instances")
if _, err := os.Stat(dir); err != nil {
return
}
subdirs, _ := os.ReadDir(dir)
for _, d := range subdirs {
if !d.IsDir() {
continue
}
if _, err := os.Stat(filepath.Join(dir, d.Name(), "instance.json")); err != nil {
continue
}
f, _ := os.OpenFile(filepath.Join(dir, d.Name(), "instance.json"), os.O_RDONLY, 0755)
defer f.Close()
buff := new(bytes.Buffer)
io.Copy(buff, f)
instance := Instance{}
json.Unmarshal(buff.Bytes(), &instance)
fmt.Printf("Found Instance: %+v\n", instance)
i.instances = append(i.instances, instance)
}
}
2024-10-26 18:14:12 -06:00
func (i *InstanceManager)checkJavaVersion(instance Instance){
infoPath := filepath.Join(i.app.PrismLauncher.GetInstanceDir(), instance.InstanceName, "mmc-pack.json")
f, _ := os.OpenFile(infoPath, os.O_RDONLY, 0755)
defer f.Close()
dataStr,_ := io.ReadAll(f)
var data mmcpack
json.Unmarshal(dataStr, &data)
mc_version := "0.0"
for _, comp := range data.Components {
if comp.Uid == "net.minecraft" {
mc_version = comp.Version
break;
}
}
fmt.Printf("MC Version: %s",mc_version)
tokensStr := strings.Split(mc_version, ".")
tokens := []int{0, 0, 0}
tokens[0], _ = strconv.Atoi(tokensStr[0])
tokens[1], _ = strconv.Atoi(tokensStr[1])
2024-10-26 19:27:39 -06:00
if len(tokensStr) > 2 {
tokens[2], _ = strconv.Atoi(tokensStr[2])
}
2024-10-26 18:14:12 -06:00
javaVer := 8
if tokens[1] == 17 {
javaVer = 17
} else if tokens[1] == 18 || tokens[1] == 19 {
javaVer = 17
} else if tokens[1] > 19 {
if tokens[1] == 20 && tokens[2] < 5 {
javaVer = 17
} else {
javaVer = 21
}
}
fmt.Printf("Req Java Version: %d",javaVer)
if !i.app.Java.CheckJavaVer(javaVer) {
i.app.Java.InstallJavaVer(javaVer)
}
confPath := filepath.Join(i.app.PrismLauncher.GetInstanceDir(), instance.InstanceName, "instance.cfg")
f, _ = os.OpenFile(confPath, os.O_RDONLY, 0755)
defer f.Close()
buff := new(bytes.Buffer)
io.Copy(buff, f)
sc := bufio.NewScanner(buff)
f, _ = os.OpenFile(confPath, os.O_CREATE|os.O_RDWR, 0755)
plat := "lin"
exe := "java"
if runtime.GOOS == "windows" {
plat = "win"
exe = "Java.exe"
}
confDir, _ := os.UserConfigDir()
found := false
for sc.Scan() {
line := sc.Text()
if strings.HasPrefix(line, "JavaPath=") {
2024-10-26 22:33:33 -06:00
line = fmt.Sprintf("JavaPath=%s/FCLauncher/java/java-%d-%s/bin/%s", strings.ReplaceAll(confDir, "\\", "/"), javaVer, plat, exe)
2024-10-26 18:14:12 -06:00
found = true
}
f.WriteString(line+"\n")
}
if !found {
2024-10-26 22:33:33 -06:00
line := fmt.Sprintf("JavaPath=%s/FCLauncher/java/java-%d-%s/bin/%s", strings.ReplaceAll(confDir, "\\", "/"), javaVer, plat, exe)
2024-10-26 18:14:12 -06:00
f.WriteString(line+"\n")
f.WriteString("OverrideJavaLocation=true\nOverrideJava=true\n")
}
f.Close()
}
func (i *InstanceManager)InstallModpack(modpack Modpack, instanceName string){
i.app.Status(fmt.Sprintf("Installing %s", modpack.Name))
version := modpack.Versions[len(modpack.Versions)-1]
dname, _ := os.MkdirTemp("", "fclauncher-*")
f, _ := os.OpenFile(filepath.Join(dname, instanceName+".mrpack"), os.O_CREATE|os.O_RDWR, 0755)
defer f.Close()
HttpDownload(modpack.Id + "/" + version.File, f, i.app.Ctx)
i.app.PrismLauncher.ImportModpack(f.Name())
instance := Instance{InstanceName: instanceName, ModpackVersion: version.Version, ModpackId: modpack.Id}
i.instances = append(i.instances, instance)
f, _ = os.OpenFile(filepath.Join(i.app.PrismLauncher.GetInstanceDir(), instanceName, "instance.json"), os.O_CREATE|os.O_RDWR, 0755)
defer f.Close()
data, _ := json.Marshal(instance)
f.Write(data)
2024-10-26 18:14:12 -06:00
i.checkJavaVersion(instance)
}
2024-10-29 21:48:59 -06:00
func (i *InstanceManager)InstallVanilla(version string, instanceName string) {
dir, _ := os.UserConfigDir()
err := DownloadAssets(version, filepath.Join(dir, "FCLauncher", "assets"), *i.app)
if err != nil {
fmt.Printf("Unable to download assets: %s\n", err)
} else {
fmt.Printf("Assets Downloaded")
}
err = DownloadLibraries(version, filepath.Join(dir, "FCLauncher", "lib"), *i.app)
2024-10-29 21:48:59 -06:00
if err != nil {
fmt.Printf("Unable to download libs: %s\n", err)
2024-10-29 21:48:59 -06:00
} else {
fmt.Printf("Libs Downloaded")
}
InstallNatives(version, filepath.Join(dir, "FCLauncher", "instances", instanceName, "minecraft", "natives"))
2024-10-30 15:58:05 -06:00
DownloadLoggingConfig(version, filepath.Join(dir, "FCLauncher", "instances", instanceName, "minecraft"))
err = DownloadExecutable(version, filepath.Join(dir, "FCLauncher", "bin"), *i.app)
if err != nil {
fmt.Printf("Unable to download binaries: %s\n", err)
} else {
fmt.Printf("Binaries Downloaded")
}
metadata, err := GetVersionMetadata(version)
if err != nil {
fmt.Printf("unable to pull metadata: %s\n", err)
}
err = os.MkdirAll(filepath.Join(dir, "FCLauncher", "instances", instanceName, "minecraft"), 0755)
if err != nil {
fmt.Printf("unable to create directory: %s\n", err)
}
2024-10-31 16:23:38 -06:00
instance := Instance{InstanceName: instanceName, MinecraftVersion: version, JavaVersion: metadata.JavaVersion.MajorVersion, MainClass: metadata.MainClass}
for _, lib := range metadata.Libraries {
instance.Libraries = append(instance.Libraries, lib.Downloads.Artifact.Path)
}
data, err := json.Marshal(instance)
if err != nil {
fmt.Printf("unable to marshal json data: %s\n", err)
}
f, err := os.OpenFile(filepath.Join(dir, "FCLauncher", "instances", instanceName, "instance.json"), os.O_CREATE|os.O_RDWR, 0755)
if err != nil {
fmt.Printf("unable to open file: %s\n", err)
}
defer f.Close()
_, err = f.Write(data)
if err != nil {
fmt.Printf("unable to write data: %s\n", err)
}
i.instances = append(i.instances, instance)
if !i.app.Java.CheckJavaVer(instance.JavaVersion) {
i.app.Status(fmt.Sprintf("Installing Java Version %d", instance.JavaVersion))
i.app.Java.InstallJavaVer(instance.JavaVersion)
2024-10-29 21:48:59 -06:00
}
2024-10-29 21:48:59 -06:00
return
}
func (i *InstanceManager)GetInstances() []Instance{
return i.instances
}
2024-10-26 18:14:12 -06:00
func (i *InstanceManager)CheckUpdate(instance Instance){
return
2024-10-26 18:14:12 -06:00
i.app.Status("Checking for Updates")
i.app.Modpacks.QuerryModpacks()
pack := i.app.Modpacks.GetModpack(instance.ModpackId)
if pack.Versions[len(pack.Versions)-1].Version == instance.ModpackVersion {
return
}
i.app.Status(fmt.Sprintf("Updating %s", instance.InstanceName))
version := pack.Versions[len(pack.Versions)-1]
dname, _ := os.MkdirTemp("", "fclauncher-*")
f, _ := os.OpenFile(filepath.Join(dname, instance.InstanceName+".mrpack"), os.O_CREATE|os.O_RDWR, 0755)
defer f.Close()
HttpDownload(pack.Id + "/" + version.File, f, i.app.Ctx)
i.app.PrismLauncher.ImportModpack(f.Name())
instance.ModpackVersion = version.Version
f, _ = os.OpenFile(filepath.Join(i.app.PrismLauncher.GetInstanceDir(), instance.InstanceName, "instance.json"), os.O_CREATE|os.O_RDWR, 0755)
defer f.Close()
data, _ := json.Marshal(instance)
f.Write(data)
i.checkJavaVersion(instance)
i.SearchInstances()
}
2024-10-31 16:23:38 -06:00
func (i *InstanceManager)GetInstance(instance string) (Instance, error) {
instanceObject := Instance{}
found := false
for _, inst := range i.instances {
if inst.InstanceName == instance {
instanceObject = inst
found = true
break
}
}
if !found {
2024-10-31 16:23:38 -06:00
return Instance{}, fmt.Errorf("unable to find instance %s\n", instance)
}
return instanceObject, nil
}
func (i *InstanceManager)LaunchInstance(instance string) {
dir, err := os.UserConfigDir()
if err != nil {
fmt.Printf("unable to get config directory\n")
}
instanceObject, err := i.GetInstance(instance)
if err != nil {
fmt.Printf("Unable to find instance\n")
}
execName := "java"
suffix := "lin"
if runtime.GOOS == "windows" {
execName = "Java.exe"
suffix = "win"
}
dir = filepath.Join(dir, "FCLauncher")
2024-10-30 17:16:10 -06:00
auth, err := MicrosoftAuth(i.app.Auth)
if err != nil {
fmt.Printf("unable to authenticate: %s\n", err)
return
}
2024-10-31 16:23:38 -06:00
args, err := GetOnlineLaunchArgs(instanceObject.MinecraftVersion, instanceObject, filepath.Join(dir, "lib"), filepath.Join(dir, "bin"), filepath.Join(dir, "assets"), filepath.Join(dir, "instances", instance, "minecraft"), auth)
if err != nil {
fmt.Printf("unable to get launch args: %s\n", err)
}
fmt.Printf("Args: %+v", args)
child := exec.Command(filepath.Join(dir, "java", fmt.Sprintf("java-%d-%s", instanceObject.JavaVersion, suffix), "bin", execName), args...)
2024-10-31 17:50:45 -06:00
child.Dir = filepath.Join(dir, "instances", instance, "minecraft")
2024-10-30 19:11:24 -06:00
wruntime.WindowHide(i.app.Ctx)
data, err := child.CombinedOutput()
2024-10-30 19:11:24 -06:00
wruntime.WindowShow(i.app.Ctx)
fmt.Printf("Command Output: %s\n", data)
}
2024-10-31 16:23:38 -06:00
func (i *InstanceManager)InstallFabric(instance string, fabricVersion string) {
i.app.Status("Installing Fabric")
instanceObject, err := i.GetInstance(instance)
if err != nil {
fmt.Printf("Instance does not exist\n")
}
metadata, err := GetFabricMetadata(instanceObject.MinecraftVersion, fabricVersion)
if err != nil {
fmt.Printf("unable to get version metadata\n")
}
2024-10-31 17:47:50 -06:00
client:
2024-10-31 16:23:38 -06:00
for _, lib := range metadata.LauncherMeta.Libraries.Client {
2024-10-31 17:47:50 -06:00
tokens := strings.Split(ProcessMavenPath(lib.Name), string(os.PathSeparator))
pkg := tokens[len(tokens)-2]
2024-10-31 16:46:12 -06:00
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(lib.Name), ProcessMavenFilename(lib.Name)))
2024-10-31 17:47:50 -06:00
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 client
}
}
2024-10-31 16:23:38 -06:00
}
2024-10-31 17:47:50 -06:00
common:
2024-10-31 16:23:38 -06:00
for _, lib := range metadata.LauncherMeta.Libraries.Common {
2024-10-31 17:47:50 -06:00
tokens := strings.Split(ProcessMavenPath(lib.Name), string(os.PathSeparator))
pkg := tokens[len(tokens)-2]
2024-10-31 16:46:12 -06:00
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(lib.Name), ProcessMavenFilename(lib.Name)))
2024-10-31 17:47:50 -06:00
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 common
}
}
2024-10-31 16:23:38 -06:00
}
2024-10-31 16:46:12 -06:00
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(metadata.Loader.Maven), ProcessMavenFilename(metadata.Loader.Maven)))
2024-10-31 16:23:38 -06:00
2024-10-31 16:46:12 -06:00
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(metadata.Intermediary.Maven), ProcessMavenFilename(metadata.Intermediary.Maven)))
2024-10-31 16:23:38 -06:00
instanceObject.MainClass = metadata.LauncherMeta.MainClass["client"]
instanceObject.FabricVersion = fabricVersion
dir, _ := os.UserConfigDir()
InstallFabricLibs(instanceObject.MinecraftVersion, fabricVersion, filepath.Join(dir, "FCLauncher", "lib"))
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
}
}
}
2024-10-31 18:21:09 -06:00
func (i *InstanceManager)InstallQuilt(instance string, quiltVersion string) {
i.app.Status("Installing Quilt")
instanceObject, err := i.GetInstance(instance)
if err != nil {
fmt.Printf("Instance does not exist\n")
}
metadata, err := GetQuiltMetadata(instanceObject.MinecraftVersion, quiltVersion)
if err != nil {
fmt.Printf("unable to get version metadata\n")
}
client:
for _, lib := range metadata.LauncherMeta.Libraries.Client {
tokens := strings.Split(ProcessMavenPath(lib.Name), string(os.PathSeparator))
pkg := tokens[len(tokens)-2]
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(lib.Name), ProcessMavenFilename(lib.Name)))
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 client
}
}
}
common:
for _, lib := range metadata.LauncherMeta.Libraries.Common {
tokens := strings.Split(ProcessMavenPath(lib.Name), string(os.PathSeparator))
pkg := tokens[len(tokens)-2]
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(lib.Name), ProcessMavenFilename(lib.Name)))
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 common
}
}
}
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(metadata.Loader.Maven), ProcessMavenFilename(metadata.Loader.Maven)))
instanceObject.Libraries = append(instanceObject.Libraries, filepath.Join(ProcessMavenPath(metadata.Intermediary.Maven), ProcessMavenFilename(metadata.Intermediary.Maven)))
instanceObject.MainClass = metadata.LauncherMeta.MainClass["client"]
instanceObject.QuiltVersion = quiltVersion
dir, _ := os.UserConfigDir()
InstallQuiltLibs(instanceObject.MinecraftVersion, quiltVersion, filepath.Join(dir, "FCLauncher", "lib"))
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
}
}
}