Started work on downloading minecraft

This commit is contained in:
Samuel Walker 2024-10-29 21:48:59 -06:00
parent 98e03a3e60
commit ab0bfebe87
8 changed files with 267 additions and 15 deletions

View File

@ -11,6 +11,7 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
) )
type Instance struct { type Instance struct {
@ -146,6 +147,17 @@ func (i *InstanceManager)InstallModpack(modpack Modpack, instanceName string){
} }
func (i *InstanceManager)InstallVanilla(version string, instanceName string) {
metadata, err := GetVersionMetadata(version)
if err != nil {
fmt.Printf("Unable to obtain metadata: %s\n", err)
} else {
fmt.Printf("Version Metadata: %+v", metadata)
}
time.Sleep(time.Second * 1)
return
}
func (i *InstanceManager)GetInstances() []Instance{ func (i *InstanceManager)GetInstances() []Instance{
return i.instances return i.instances
} }

View File

@ -61,6 +61,21 @@ func (a *App) CheckPrerequisites() {
a.Java.InstallJavaVer(21) a.Java.InstallJavaVer(21)
a.Status("Java 21 Installed") a.Status("Java 21 Installed")
} }
}
func (App) GetVersions() ([]string, error) {
manifest, err := GetVersionManifest()
if err != nil {
fmt.Printf("Manifest Error: %s\n", err)
return []string{}, err
}
versions := []string{}
for _, version := range manifest.Versions {
versions = append(versions, version.Id)
}
return versions, nil
} }
func (a *App) Status(status string) { func (a *App) Status(status string) {

View File

@ -1,12 +1,13 @@
<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 {InstallModpack, GetInstances, CheckUpdate} from '../wailsjs/go/main/InstanceManager.js' import {InstallVanilla, GetInstances, CheckUpdate} from '../wailsjs/go/main/InstanceManager.js'
import {LaunchInstance} from '../wailsjs/go/main/Prism.js' import {LaunchInstance} from '../wailsjs/go/main/Prism.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'
import {slide} from 'svelte/transition' import {slide} from 'svelte/transition'
let modpacks: Modpack[] = [] let modpacks: string[] = []
let pack: string let pack: string
let instances: Instance[] = [] let instances: Instance[] = []
let instance: Instance let instance: Instance
@ -14,10 +15,10 @@
let name: string = "New Modpack" let name: string = "New Modpack"
function updateLists(){ function updateLists(){
GetModpacks().then((result) => { GetVersions().then((result) => {
modpacks = result modpacks = result
pack = modpacks[0].Id pack = modpacks[0]
name = modpacks[0].Name name = modpacks[0]
}) })
GetInstances().then((result) => { GetInstances().then((result) => {
instances = result instances = result
@ -41,19 +42,15 @@
function install(){ function install(){
$loading = true $loading = true
GetModpack(pack).then((result) => { InstallVanilla(pack, name).then(() => {
InstallModpack(result, name).then(() => {
updateLists()
addingInstance = false addingInstance = false
$loading = false $loading = false
}) updateLists()
}) })
} }
function onchange(event){ function onchange(event){
GetModpack(event.target.value).then((result) => { name = event.target.value
name = result.Name
})
} }
@ -71,7 +68,7 @@
<div transition:slide="{{duration:300}}"> <div transition:slide="{{duration:300}}">
<select id="pack" on:change={onchange} bind:value={pack} name="pack">Select a Modpack: <select id="pack" on:change={onchange} bind:value={pack} name="pack">Select a Modpack:
{#each modpacks as pack} {#each modpacks as pack}
<option value={pack.Id}>{pack.Name}</option> <option value={pack}>{pack}</option>
{/each} {/each}
</select> </select>
<br/> <br/>

View File

@ -3,4 +3,6 @@
export function CheckPrerequisites():Promise<void>; export function CheckPrerequisites():Promise<void>;
export function GetVersions():Promise<Array<string>>;
export function Status(arg1:string):Promise<void>; export function Status(arg1:string):Promise<void>;

View File

@ -6,6 +6,10 @@ export function CheckPrerequisites() {
return window['go']['main']['App']['CheckPrerequisites'](); return window['go']['main']['App']['CheckPrerequisites']();
} }
export function GetVersions() {
return window['go']['main']['App']['GetVersions']();
}
export function Status(arg1) { export function Status(arg1) {
return window['go']['main']['App']['Status'](arg1); return window['go']['main']['App']['Status'](arg1);
} }

View File

@ -8,4 +8,6 @@ export function GetInstances():Promise<Array<main.Instance>>;
export function InstallModpack(arg1:main.Modpack,arg2:string):Promise<void>; export function InstallModpack(arg1:main.Modpack,arg2:string):Promise<void>;
export function InstallVanilla(arg1:string,arg2:string):Promise<void>;
export function SearchInstances():Promise<void>; export function SearchInstances():Promise<void>;

View File

@ -14,6 +14,10 @@ export function InstallModpack(arg1, arg2) {
return window['go']['main']['InstanceManager']['InstallModpack'](arg1, arg2); return window['go']['main']['InstanceManager']['InstallModpack'](arg1, arg2);
} }
export function InstallVanilla(arg1, arg2) {
return window['go']['main']['InstanceManager']['InstallVanilla'](arg1, arg2);
}
export function SearchInstances() { export function SearchInstances() {
return window['go']['main']['InstanceManager']['SearchInstances'](); return window['go']['main']['InstanceManager']['SearchInstances']();
} }

216
fclauncher/minecraft.go Normal file
View File

@ -0,0 +1,216 @@
package main
import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"time"
)
type McVersionManifestEntry struct {
Id string
Type string
Url string
Time time.Time
ReleaseTime time.Time
Sha1 string
ComplianceLevel int
}
type McLatestEntry struct {
Release string
Snapshot string
}
type McVersionManifest struct {
Latest McLatestEntry
Versions []McVersionManifestEntry
}
type McArguments struct {
Game []string
Jvm []string
}
type McAssetIndex struct {
Id string
Sha1 string
Size int
TotalSize int
Url string
}
type McJavaVersion struct {
Component string
MajorVersion int
}
type McLibraryArtifact struct {
Path string
Sha1 string
Size int
Url string
}
type McLibraryDownload struct {
Artifact McLibraryArtifact
}
type McRuleOs struct {
Name string
Version string
ARch string
}
type McRule struct {
Action string
Features map[string]bool
Os McRuleOs
}
type McLibrary struct {
Downloads McLibraryDownload
Name string
Rules []McRule
}
type McDownload struct {
Sha1 string
Size int
Url string
}
type McMetadata struct {
Arguments McArguments
AssetIndex McAssetIndex
Assets string
ComplianceLevel int
Downloads map[string]McDownload
Id string
JavaVersion McJavaVersion
Libraries []McLibrary
Logging interface{}
MainClass string
MinimumLauncherVersion int
ReleaseTime time.Time
Time time.Time
Type string
}
func GetVersionManifest() (McVersionManifest, error) {
resp, err := http.Get("https://piston-meta.mojang.com/mc/game/version_manifest_v2.json")
var returnError error = nil
if err == nil {
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err == nil {
versionManifest := McVersionManifest{}
err = json.Unmarshal(data, &versionManifest)
if err == nil {
dir, err := os.UserConfigDir()
if err != nil {
return versionManifest, nil
}
err = os.MkdirAll(filepath.Join(dir, "FCLauncher", "cache"), 0755)
f, err := os.OpenFile(filepath.Join(dir, "FCLauncher", "cache", "versionManifest.json"), os.O_CREATE|os.O_RDWR, 0755)
defer f.Close()
f.Write(data)
return versionManifest, nil
} else {
returnError = fmt.Errorf("Unable to parse Json: %e\n", err)
}
} else {
returnError = fmt.Errorf("Unable to read version manifest: %e\n", err)
}
} else {
returnError = fmt.Errorf("Unable to download version manifest: %e\n", err)
}
dir, err := os.UserConfigDir()
if err != nil {
return McVersionManifest{}, returnError
}
path := filepath.Join(dir, "FCLauncher", "cache", "versionManifest.json")
if _, err = os.Stat(path); err != nil {
return McVersionManifest{}, returnError
}
f, err := os.OpenFile(path, os.O_RDONLY, 0755)
if err != nil {
return McVersionManifest{}, returnError
}
data, _ := io.ReadAll(f)
if err != nil {
return McVersionManifest{}, returnError
}
versionManifest := McVersionManifest{}
err = json.Unmarshal(data, &versionManifest)
if err != nil {
return McVersionManifest{}, returnError
}
return versionManifest, nil
}
func GetVersionMetadata(wantedVersion string) (McMetadata, error) {
manifest, err := GetVersionManifest()
if err != nil {
return McMetadata{}, fmt.Errorf("GetVersionMetadata: %e\n", err)
}
for _, version := range manifest.Versions {
if wantedVersion == version.Id {
//found it
dir, err := os.UserConfigDir()
if err == nil {
path := filepath.Join(dir, "FCLauncher", "cache", "versionMetadata", wantedVersion+".json")
if _, err := os.Stat(path); err == nil {
if f, err := os.OpenFile(path, 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]) == version.Sha1{
metadata := McMetadata{}
json.Unmarshal(data, &metadata)
fmt.Printf("Found cache!\n")
return metadata, nil
}
}
}
}
}
resp, err := http.Get(version.Url)
if err != nil {
return McMetadata{}, fmt.Errorf("Unable to download metadata: %e\n", err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return McMetadata{}, fmt.Errorf("Unable to download metadata: %e\n", err)
}
sha := sha1.Sum(data)
if hex.EncodeToString(sha[:20]) != version.Sha1 {
return McMetadata{}, fmt.Errorf("GetMetadata: Sha1 hash does not match\n")
}
metadata := McMetadata{}
err = json.Unmarshal(data, &metadata)
dir, err = os.UserConfigDir()
if err == nil {
path := filepath.Join(dir, "FCLauncher", "cache", "versionMetadata")
if os.MkdirAll(path, 0755) == nil {
if f, err := os.OpenFile(filepath.Join(path, wantedVersion+".json"), os.O_CREATE|os.O_RDWR, 0755); err == nil {
defer f.Close()
f.Write(data)
}
}
}
return metadata, nil
}
}
return McMetadata{}, fmt.Errorf("Unable to find version %s\n", wantedVersion)
}