installation and launching of vanilla minecraft working
This commit is contained in:
parent
ab0bfebe87
commit
2bbb4b8cf0
@ -7,17 +7,23 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
InstanceName string
|
InstanceName string
|
||||||
ModpackId string
|
ModpackId string
|
||||||
ModpackVersion string
|
ModpackVersion string
|
||||||
|
MinecraftVersion string
|
||||||
|
ForgeVersion string
|
||||||
|
NeoForgeVersion string
|
||||||
|
FabricVersion string
|
||||||
|
QuiltVersion string
|
||||||
|
JavaVersion int
|
||||||
}
|
}
|
||||||
|
|
||||||
type InstanceManager struct {
|
type InstanceManager struct {
|
||||||
@ -36,7 +42,8 @@ type component struct {
|
|||||||
|
|
||||||
func (i *InstanceManager)SearchInstances() {
|
func (i *InstanceManager)SearchInstances() {
|
||||||
i.instances = []Instance{}
|
i.instances = []Instance{}
|
||||||
dir := i.app.PrismLauncher.GetInstanceDir()
|
dir, _ := os.UserConfigDir()
|
||||||
|
dir = filepath.Join(dir, "FCLauncher", "instances")
|
||||||
if _, err := os.Stat(dir); err != nil {
|
if _, err := os.Stat(dir); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -148,13 +155,59 @@ func (i *InstanceManager)InstallModpack(modpack Modpack, instanceName string){
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *InstanceManager)InstallVanilla(version string, instanceName string) {
|
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)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Unable to download libs: %s\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Libs Downloaded")
|
||||||
|
}
|
||||||
|
InstallNatives(version, filepath.Join(dir, "FCLauncher", "instances", instanceName, "minecraft", "natives"))
|
||||||
|
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)
|
metadata, err := GetVersionMetadata(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Unable to obtain metadata: %s\n", err)
|
fmt.Printf("unable to pull metadata: %s\n", err)
|
||||||
} else {
|
|
||||||
fmt.Printf("Version Metadata: %+v", metadata)
|
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second * 1)
|
|
||||||
|
err = os.MkdirAll(filepath.Join(dir, "FCLauncher", "instances", instanceName, "minecraft"), 0755)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("unable to create directory: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
instance := Instance{InstanceName: instanceName, MinecraftVersion: version, JavaVersion: metadata.JavaVersion.MajorVersion}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +216,7 @@ func (i *InstanceManager)GetInstances() []Instance{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *InstanceManager)CheckUpdate(instance Instance){
|
func (i *InstanceManager)CheckUpdate(instance Instance){
|
||||||
|
return
|
||||||
i.app.Status("Checking for Updates")
|
i.app.Status("Checking for Updates")
|
||||||
i.app.Modpacks.QuerryModpacks()
|
i.app.Modpacks.QuerryModpacks()
|
||||||
pack := i.app.Modpacks.GetModpack(instance.ModpackId)
|
pack := i.app.Modpacks.GetModpack(instance.ModpackId)
|
||||||
@ -185,3 +239,37 @@ func (i *InstanceManager)CheckUpdate(instance Instance){
|
|||||||
i.SearchInstances()
|
i.SearchInstances()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *InstanceManager)LaunchInstance(instance string) {
|
||||||
|
dir, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("unable to get config directory\n")
|
||||||
|
}
|
||||||
|
instanceObject := Instance{}
|
||||||
|
found := false
|
||||||
|
for _, inst := range i.instances {
|
||||||
|
if inst.InstanceName == instance {
|
||||||
|
instanceObject = inst
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
fmt.Printf("unable to find instance %s\n", instance)
|
||||||
|
}
|
||||||
|
execName := "java"
|
||||||
|
suffix := "lin"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
execName = "Java.exe"
|
||||||
|
suffix = "win"
|
||||||
|
}
|
||||||
|
dir = filepath.Join(dir, "FCLauncher")
|
||||||
|
args, err := GetOfflineLaunchArgs(instanceObject.MinecraftVersion, filepath.Join(dir, "lib"), filepath.Join(dir, "bin"), filepath.Join(dir, "assets"), filepath.Join(dir, "instances", instance, "minecraft"), "Player")
|
||||||
|
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...)
|
||||||
|
data, err := child.CombinedOutput()
|
||||||
|
fmt.Printf("Command Output: %s\n", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ import (
|
|||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
const client_id string = "9305aeb8-5ecb-4e7a-b28f-c33aefcfbd8d"
|
||||||
|
|
||||||
// App struct
|
// App struct
|
||||||
type App struct {
|
type App struct {
|
||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {GetModpacks, GetModpack} from '../wailsjs/go/main/ModpackManager.js'
|
import {GetModpacks, GetModpack} from '../wailsjs/go/main/ModpackManager.js'
|
||||||
import {InstallVanilla, GetInstances, CheckUpdate} from '../wailsjs/go/main/InstanceManager.js'
|
import {InstallVanilla, LaunchInstance, GetInstances, CheckUpdate} from '../wailsjs/go/main/InstanceManager.js'
|
||||||
import {LaunchInstance} from '../wailsjs/go/main/Prism.js'
|
|
||||||
import {GetVersions} from '../wailsjs/go/main/App.js'
|
import {GetVersions} from '../wailsjs/go/main/App.js'
|
||||||
import {onMount} from 'svelte'
|
import {onMount} from 'svelte'
|
||||||
import {loading} from './global.ts'
|
import {loading} from './global.ts'
|
||||||
@ -10,7 +9,7 @@
|
|||||||
let modpacks: string[] = []
|
let modpacks: string[] = []
|
||||||
let pack: string
|
let pack: string
|
||||||
let instances: Instance[] = []
|
let instances: Instance[] = []
|
||||||
let instance: Instance
|
let instance: string
|
||||||
let addingInstance: boolean = false
|
let addingInstance: boolean = false
|
||||||
let name: string = "New Modpack"
|
let name: string = "New Modpack"
|
||||||
|
|
||||||
@ -22,7 +21,7 @@
|
|||||||
})
|
})
|
||||||
GetInstances().then((result) => {
|
GetInstances().then((result) => {
|
||||||
instances = result
|
instances = result
|
||||||
instance = instances[0]
|
instance = instances[0].InstanceName
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,12 +31,10 @@
|
|||||||
|
|
||||||
function onclick(event) {
|
function onclick(event) {
|
||||||
$loading = true
|
$loading = true
|
||||||
CheckUpdate(instance).then(() => {
|
|
||||||
LaunchInstance(instance).then(() => {
|
LaunchInstance(instance).then(() => {
|
||||||
$loading = false
|
$loading = false
|
||||||
window.runtime.Quit()
|
window.runtime.Quit()
|
||||||
})
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function install(){
|
function install(){
|
||||||
@ -59,7 +56,7 @@
|
|||||||
<main>
|
<main>
|
||||||
<select bind:value={instance} name="pack">Select a Modpack:
|
<select bind:value={instance} name="pack">Select a Modpack:
|
||||||
{#each instances as instance}
|
{#each instances as instance}
|
||||||
<option value={instance}>{instance.InstanceName}</option>
|
<option value={instance.InstanceName}>{instance.InstanceName}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
<button on:click={onclick}>Launch</button>
|
<button on:click={onclick}>Launch</button>
|
||||||
|
@ -10,4 +10,6 @@ export function InstallModpack(arg1:main.Modpack,arg2:string):Promise<void>;
|
|||||||
|
|
||||||
export function InstallVanilla(arg1:string,arg2:string):Promise<void>;
|
export function InstallVanilla(arg1:string,arg2:string):Promise<void>;
|
||||||
|
|
||||||
|
export function LaunchInstance(arg1:string):Promise<void>;
|
||||||
|
|
||||||
export function SearchInstances():Promise<void>;
|
export function SearchInstances():Promise<void>;
|
||||||
|
@ -18,6 +18,10 @@ export function InstallVanilla(arg1, arg2) {
|
|||||||
return window['go']['main']['InstanceManager']['InstallVanilla'](arg1, arg2);
|
return window['go']['main']['InstanceManager']['InstallVanilla'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function LaunchInstance(arg1) {
|
||||||
|
return window['go']['main']['InstanceManager']['LaunchInstance'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function SearchInstances() {
|
export function SearchInstances() {
|
||||||
return window['go']['main']['InstanceManager']['SearchInstances']();
|
return window['go']['main']['InstanceManager']['SearchInstances']();
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,12 @@ export namespace main {
|
|||||||
InstanceName: string;
|
InstanceName: string;
|
||||||
ModpackId: string;
|
ModpackId: string;
|
||||||
ModpackVersion: string;
|
ModpackVersion: string;
|
||||||
|
MinecraftVersion: string;
|
||||||
|
ForgeVersion: string;
|
||||||
|
NeoForgeVersion: string;
|
||||||
|
FabricVersion: string;
|
||||||
|
QuiltVersion: string;
|
||||||
|
JavaVersion: number;
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new Instance(source);
|
return new Instance(source);
|
||||||
@ -14,6 +20,12 @@ export namespace main {
|
|||||||
this.InstanceName = source["InstanceName"];
|
this.InstanceName = source["InstanceName"];
|
||||||
this.ModpackId = source["ModpackId"];
|
this.ModpackId = source["ModpackId"];
|
||||||
this.ModpackVersion = source["ModpackVersion"];
|
this.ModpackVersion = source["ModpackVersion"];
|
||||||
|
this.MinecraftVersion = source["MinecraftVersion"];
|
||||||
|
this.ForgeVersion = source["ForgeVersion"];
|
||||||
|
this.NeoForgeVersion = source["NeoForgeVersion"];
|
||||||
|
this.FabricVersion = source["FabricVersion"];
|
||||||
|
this.QuiltVersion = source["QuiltVersion"];
|
||||||
|
this.JavaVersion = source["JavaVersion"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class Version {
|
export class Version {
|
||||||
|
BIN
fclauncher/logs/2024-10-30-1.log.gz
Normal file
BIN
fclauncher/logs/2024-10-30-1.log.gz
Normal file
Binary file not shown.
BIN
fclauncher/logs/2024-10-30-2.log.gz
Normal file
BIN
fclauncher/logs/2024-10-30-2.log.gz
Normal file
Binary file not shown.
BIN
fclauncher/logs/2024-10-30-3.log.gz
Normal file
BIN
fclauncher/logs/2024-10-30-3.log.gz
Normal file
Binary file not shown.
BIN
fclauncher/logs/2024-10-30-4.log.gz
Normal file
BIN
fclauncher/logs/2024-10-30-4.log.gz
Normal file
Binary file not shown.
BIN
fclauncher/logs/2024-10-30-5.log.gz
Normal file
BIN
fclauncher/logs/2024-10-30-5.log.gz
Normal file
Binary file not shown.
77
fclauncher/logs/latest.log
Normal file
77
fclauncher/logs/latest.log
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -9,7 +10,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
|
"github.com/zhyee/zipstream"
|
||||||
)
|
)
|
||||||
|
|
||||||
type McVersionManifestEntry struct {
|
type McVersionManifestEntry struct {
|
||||||
@ -59,6 +65,7 @@ type McLibraryArtifact struct {
|
|||||||
|
|
||||||
type McLibraryDownload struct {
|
type McLibraryDownload struct {
|
||||||
Artifact McLibraryArtifact
|
Artifact McLibraryArtifact
|
||||||
|
Classifiers map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type McRuleOs struct {
|
type McRuleOs struct {
|
||||||
@ -77,6 +84,7 @@ type McLibrary struct {
|
|||||||
Downloads McLibraryDownload
|
Downloads McLibraryDownload
|
||||||
Name string
|
Name string
|
||||||
Rules []McRule
|
Rules []McRule
|
||||||
|
Natives map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type McDownload struct {
|
type McDownload struct {
|
||||||
@ -100,6 +108,7 @@ type McMetadata struct {
|
|||||||
ReleaseTime time.Time
|
ReleaseTime time.Time
|
||||||
Time time.Time
|
Time time.Time
|
||||||
Type string
|
Type string
|
||||||
|
MinecraftArguments string
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetVersionManifest() (McVersionManifest, error) {
|
func GetVersionManifest() (McVersionManifest, error) {
|
||||||
@ -176,7 +185,6 @@ func GetVersionMetadata(wantedVersion string) (McMetadata, error) {
|
|||||||
if hex.EncodeToString(sha[:20]) == version.Sha1{
|
if hex.EncodeToString(sha[:20]) == version.Sha1{
|
||||||
metadata := McMetadata{}
|
metadata := McMetadata{}
|
||||||
json.Unmarshal(data, &metadata)
|
json.Unmarshal(data, &metadata)
|
||||||
fmt.Printf("Found cache!\n")
|
|
||||||
return metadata, nil
|
return metadata, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,3 +222,379 @@ func GetVersionMetadata(wantedVersion string) (McMetadata, error) {
|
|||||||
}
|
}
|
||||||
return McMetadata{}, fmt.Errorf("Unable to find version %s\n", wantedVersion)
|
return McMetadata{}, fmt.Errorf("Unable to find version %s\n", wantedVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAssetIndex(mcVersion string) ([]string, error) {
|
||||||
|
found := false
|
||||||
|
var data []byte
|
||||||
|
metadata, err := GetVersionMetadata(mcVersion)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, fmt.Errorf("Unable to pull manifest: %e\n", err)
|
||||||
|
}
|
||||||
|
dir, _ := os.UserConfigDir()
|
||||||
|
path := filepath.Join(dir, "FCLauncher", "assets", "indexes")
|
||||||
|
if _, err := os.Stat(filepath.Join(path, metadata.Assets+".json")); err == nil {
|
||||||
|
//cache file exists
|
||||||
|
if f, err := os.OpenFile(filepath.Join(path, metadata.Assets+".json"), os.O_RDONLY, 0755); err == nil {
|
||||||
|
defer f.Close()
|
||||||
|
if data, err = io.ReadAll(f); err == nil {
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) == metadata.AssetIndex.Sha1 {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
//no cache file
|
||||||
|
data = []byte{}
|
||||||
|
resp, err := http.Get(metadata.AssetIndex.Url)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, fmt.Errorf("Unable to pull asset index: %e\n", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
data, err = io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, fmt.Errorf("Unable to pull asset index: %e\n", err)
|
||||||
|
}
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) != metadata.AssetIndex.Sha1 {
|
||||||
|
return []string{}, fmt.Errorf("Sha mismatch!\n")
|
||||||
|
}
|
||||||
|
os.MkdirAll(path, 0755)
|
||||||
|
f, _ := os.OpenFile(filepath.Join(path, metadata.Assets+".json"), os.O_CREATE|os.O_RDWR, 0755)
|
||||||
|
defer f.Close()
|
||||||
|
f.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
//at this point data is populated
|
||||||
|
var index map[string]interface{}
|
||||||
|
json.Unmarshal(data, &index)
|
||||||
|
index = index["objects"].(map[string]interface{})
|
||||||
|
hashes := []string{}
|
||||||
|
for _, val := range index {
|
||||||
|
index_map := val.(map[string]interface{})
|
||||||
|
hashes = append(hashes, index_map["hash"].(string))
|
||||||
|
}
|
||||||
|
return hashes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadAssets(mcVersion string, assetPath string, a App) error {
|
||||||
|
a.Status("Downloading Minecraft Assets")
|
||||||
|
assets, err := GetAssetIndex(mcVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to get asset index: %e\n", err)
|
||||||
|
}
|
||||||
|
metadata, err := GetVersionMetadata(mcVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to get version metadata: %e\n", err)
|
||||||
|
}
|
||||||
|
total := metadata.AssetIndex.TotalSize
|
||||||
|
downloaded := 0
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download", downloaded, total)
|
||||||
|
for _, hash := range assets {
|
||||||
|
if _, err := os.Stat(filepath.Join(assetPath, "objects", hash[:2], hash)); err == nil {
|
||||||
|
f, _ := os.OpenFile(filepath.Join(assetPath, "objects", hash[:2], hash), os.O_RDONLY, 0755)
|
||||||
|
defer f.Close()
|
||||||
|
data, _ := io.ReadAll(f)
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) == hash {
|
||||||
|
downloaded += len(data)
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download", downloaded, total)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp, err := http.Get(fmt.Sprintf("https://resources.download.minecraft.net/%s/%s", hash[:2], hash))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download assets: %e\n", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
for {
|
||||||
|
count, err := io.CopyN(buff, resp.Body, BlockSize)
|
||||||
|
if err == io.EOF {
|
||||||
|
downloaded += int(count)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Downloading assets: %e\n", err)
|
||||||
|
}
|
||||||
|
downloaded += int(count)
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download", downloaded, total)
|
||||||
|
}
|
||||||
|
data := buff.Bytes()
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) != hash {
|
||||||
|
return fmt.Errorf("unable to download assets: Sha1 Mismatch\n")
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(filepath.Join(assetPath, "objects", hash[:2]), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download assets: Unable to create directory\n")
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(filepath.Join(assetPath, "objects", hash[:2], hash), os.O_CREATE|os.O_RDWR, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download assets: Unable to open file\n")
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
f.Write(data)
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download", downloaded, total)
|
||||||
|
}
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download_complete")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadLibraries(mcVersion string, libPath string, a App) error {
|
||||||
|
metadata, err := GetVersionMetadata(mcVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to pull version metadata: %e\n", err)
|
||||||
|
}
|
||||||
|
for _, lib := range metadata.Libraries {
|
||||||
|
a.Status(fmt.Sprintf("Checking %s\n", lib.Name))
|
||||||
|
if _, err := os.Stat(filepath.Join(libPath, lib.Downloads.Artifact.Path)); err == nil {
|
||||||
|
f, _ := os.OpenFile(filepath.Join(libPath, lib.Downloads.Artifact.Path), os.O_CREATE|os.O_RDWR, 0755)
|
||||||
|
defer f.Close()
|
||||||
|
data, _ := io.ReadAll(f)
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) == lib.Downloads.Artifact.Sha1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Status(fmt.Sprintf("Downloading %s\n", lib.Name))
|
||||||
|
resp, err := http.Get(lib.Downloads.Artifact.Url)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download libs: %e\n", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
downloaded := 0
|
||||||
|
for {
|
||||||
|
count, err := io.CopyN(buff, resp.Body, BlockSize)
|
||||||
|
if err == io.EOF {
|
||||||
|
downloaded += int(count)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Downloading libs: %e\n", err)
|
||||||
|
}
|
||||||
|
downloaded += int(count)
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download", downloaded, resp.ContentLength)
|
||||||
|
}
|
||||||
|
data := buff.Bytes()
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) != lib.Downloads.Artifact.Sha1 {
|
||||||
|
return fmt.Errorf("unable to download libs: Sha1 Mismatch\n")
|
||||||
|
}
|
||||||
|
path := ""
|
||||||
|
tokens := strings.Split(lib.Downloads.Artifact.Path, "/")
|
||||||
|
for ind, token := range tokens {
|
||||||
|
if ind != len(tokens)-1 {
|
||||||
|
path = filepath.Join(path, token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(filepath.Join(libPath, path), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download libs: Unable to create directory\n")
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(filepath.Join(libPath, lib.Downloads.Artifact.Path), os.O_CREATE|os.O_RDWR, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download libs: Unable to open file\n")
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
f.Write(data)
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download_complete")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstallNatives(mcVersion string, nativesDir string){
|
||||||
|
metadata, _ := GetVersionMetadata(mcVersion)
|
||||||
|
for _, lib := range metadata.Libraries {
|
||||||
|
if lib.Natives != nil {
|
||||||
|
glob := lib.Natives[runtime.GOOS]
|
||||||
|
fmt.Printf("glob is: %s\n", glob)
|
||||||
|
if lib.Downloads.Classifiers[glob] != nil {
|
||||||
|
artifact := lib.Downloads.Classifiers[glob].(map[string]interface{})
|
||||||
|
resp, _ := http.Get(artifact["url"].(string))
|
||||||
|
defer resp.Body.Close()
|
||||||
|
zr := zipstream.NewReader(resp.Body)
|
||||||
|
for {
|
||||||
|
e, err := zr.GetNextEntry()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if e.IsDir() {
|
||||||
|
os.MkdirAll(filepath.Join(nativesDir, e.Name), 0755)
|
||||||
|
} else {
|
||||||
|
zc, _ := e.Open()
|
||||||
|
f, _ := os.OpenFile(filepath.Join(nativesDir, e.Name), os.O_CREATE|os.O_RDWR, 0755)
|
||||||
|
defer zc.Close()
|
||||||
|
defer f.Close()
|
||||||
|
io.Copy(f, zc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadExecutable(mcVersion string, binDir string, a App) error {
|
||||||
|
metadata, err := GetVersionMetadata(mcVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to pull version metadata: %e\n", err)
|
||||||
|
}
|
||||||
|
a.Status(fmt.Sprintf("Checking Minecraft %s Executable\n", mcVersion))
|
||||||
|
if _, err := os.Stat(filepath.Join(binDir, mcVersion, "client.jar")); err == nil {
|
||||||
|
f, _ := os.OpenFile(filepath.Join(binDir, mcVersion, "client.jar"), os.O_CREATE|os.O_RDWR, 0755)
|
||||||
|
defer f.Close()
|
||||||
|
data, _ := io.ReadAll(f)
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) == metadata.Downloads["client"].Sha1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Status(fmt.Sprintf("Downloading Minecraft %s Executable\n", mcVersion))
|
||||||
|
resp, err := http.Get(metadata.Downloads["client"].Url)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download executable: %e\n", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
downloaded := 0
|
||||||
|
for {
|
||||||
|
count, err := io.CopyN(buff, resp.Body, BlockSize)
|
||||||
|
if err == io.EOF {
|
||||||
|
downloaded += int(count)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Downloading executable: %e\n", err)
|
||||||
|
}
|
||||||
|
downloaded += int(count)
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download", downloaded, resp.ContentLength)
|
||||||
|
}
|
||||||
|
data := buff.Bytes()
|
||||||
|
sha := sha1.Sum(data)
|
||||||
|
if hex.EncodeToString(sha[:20]) != metadata.Downloads["client"].Sha1 {
|
||||||
|
return fmt.Errorf("unable to download executable: Sha1 Mismatch\n")
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(filepath.Join(binDir, mcVersion), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download executable: Unable to create directory\n")
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(filepath.Join(binDir, mcVersion, "client.jar"), os.O_CREATE|os.O_RDWR, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to download executable: Unable to open file\n")
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
f.Write(data)
|
||||||
|
wruntime.EventsEmit(a.Ctx, "download_complete")
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBaseLaunchArgs(mcVersion string, libDir string, binDir string, assetDir string, gameDir string) ([]string, error) {
|
||||||
|
args := []string{}
|
||||||
|
metadata, err := GetVersionMetadata(mcVersion)
|
||||||
|
if err != nil {
|
||||||
|
return args, fmt.Errorf("GetLaunchArgs: %e\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
searchArgs := []string{}
|
||||||
|
|
||||||
|
if metadata.MinecraftArguments != "" {
|
||||||
|
searchArgs = strings.Split(metadata.MinecraftArguments, " ")
|
||||||
|
} else {
|
||||||
|
searchArgs = metadata.Arguments.Game
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, "-Djava.library.path="+filepath.Join(gameDir, "natives"))
|
||||||
|
args = append(args, "-Djna.tmpdir="+filepath.Join(gameDir, "natives"))
|
||||||
|
args = append(args, "-Dorg.lwjgl.system.SharedLibraryExtractpath="+filepath.Join(gameDir, "natives"))
|
||||||
|
args = append(args, "-Dio.netty.native.workdir="+filepath.Join(gameDir, "natives"))
|
||||||
|
args = append(args, "-Xms512m")
|
||||||
|
args = append(args, "-Xmx1024m")
|
||||||
|
args = append(args, "-cp")
|
||||||
|
arg := ""
|
||||||
|
for _, lib := range metadata.Libraries {
|
||||||
|
arg += filepath.Join(libDir, lib.Downloads.Artifact.Path) + ":"
|
||||||
|
}
|
||||||
|
arg += filepath.Join(binDir, mcVersion, "client.jar")
|
||||||
|
args = append(args, arg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
args = append(args, metadata.MainClass)
|
||||||
|
|
||||||
|
for _, val := range searchArgs {
|
||||||
|
switch val {
|
||||||
|
case "${version_name}":
|
||||||
|
args = append(args, mcVersion)
|
||||||
|
case "${game_directory}":
|
||||||
|
args = append(args, gameDir)
|
||||||
|
case "${assets_root}":
|
||||||
|
args = append(args, assetDir)
|
||||||
|
case "${clientid}":
|
||||||
|
args = append(args, client_id)
|
||||||
|
case "${version_type}":
|
||||||
|
args = append(args, metadata.Type)
|
||||||
|
case "${user_type}":
|
||||||
|
args = append(args, "mojang")
|
||||||
|
case "${assets_index_name}":
|
||||||
|
args = append(args, metadata.Assets)
|
||||||
|
case "${user_properties}":
|
||||||
|
args = append(args, "null")
|
||||||
|
default:
|
||||||
|
args = append(args, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func GetOfflineLaunchArgs(mcVersion string, libDir string, binDir string, assetDir string, gameDir string, playerName string) ([]string, error) {
|
||||||
|
args, err := GetBaseLaunchArgs(mcVersion, libDir, binDir, assetDir, gameDir)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, fmt.Errorf("GatOfflineLaunchArgs: %e\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ind, val := range args {
|
||||||
|
switch val{
|
||||||
|
case "${auth_player_name}":
|
||||||
|
args[ind] = playerName
|
||||||
|
case "${auth_uuid}":
|
||||||
|
args[ind] = "null"
|
||||||
|
case "${auth_access_token}":
|
||||||
|
args[ind] = "null"
|
||||||
|
case "${auth_xuid}":
|
||||||
|
args[ind] = "null"
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOnlineLaunchArgs(mcVersion string, libDir string, binDir string, assetDir string, gameDir string, playerName string) ([]string, error) {
|
||||||
|
args, err := GetBaseLaunchArgs(mcVersion, libDir, binDir, assetDir, gameDir)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, fmt.Errorf("GatOfflineLaunchArgs: %e\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ind, val := range args {
|
||||||
|
switch val{
|
||||||
|
case "${auth_player_name}":
|
||||||
|
args[ind] = val
|
||||||
|
case "${auth_uuid}":
|
||||||
|
args[ind] = val
|
||||||
|
case "${auth_access_token}":
|
||||||
|
args[ind] = val
|
||||||
|
case "${auth_xuid}":
|
||||||
|
args[ind] = val
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user