feat: add launch module (manifest, interpolation, process exec)
- manifest: Manifest struct (files, launch config, server info), LoadManifest, LibraryFiles/ModFiles filters - launch: Game struct (Prepare/BuildCommand/Start lifecycle) - Prepare: download manifest, resolve Java, sync files with SHA-1, soft-delete unknown mods - BuildCommand: classpath assembly, variable interpolation (, , etc.), authlib-injector injection - Start: execute the assembled command - interpolate: template replacement - cleanupUnknownMods: moves untracked mods to mods_backup/ Co-Authored-By: OWL <noreply@anthropic.com>
This commit is contained in:
75
internal/launch/manifest.go
Normal file
75
internal/launch/manifest.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// package launch handles Minecraft process launching.
|
||||
package launch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Manifest describes the contents of a modpack as provided by the backend.
|
||||
type Manifest struct {
|
||||
MinecraftVersion string `json:"minecraft_version"`
|
||||
JavaVersion int `json:"java_version"`
|
||||
ServerInfo ServerInfo `json:"server_info"`
|
||||
Files []ManifestFile `json:"files"`
|
||||
Launch LaunchConfig `json:"launch"`
|
||||
}
|
||||
|
||||
// ServerInfo is the game server address injected into servers.dat.
|
||||
type ServerInfo struct {
|
||||
Name string `json:"name"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
|
||||
// ManifestFile is a single file entry with SHA-1 verification.
|
||||
type ManifestFile struct {
|
||||
Path string `json:"path"`
|
||||
Hash string `json:"hash"`
|
||||
Size int64 `json:"size"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// LaunchConfig contains the JVM and game arguments template.
|
||||
type LaunchConfig struct {
|
||||
MainClass string `json:"mainClass"`
|
||||
JVMArgs []string `json:"jvmArgs"`
|
||||
GameArgs []string `json:"gameArgs"`
|
||||
NativeLibs []string `json:"nativeLibs"`
|
||||
AuthLibInjector string `json:"authLibInjector"` // URL to authlib-injector.jar
|
||||
}
|
||||
|
||||
// LoadManifest reads and parses a manifest.json from disk.
|
||||
func LoadManifest(path string) (*Manifest, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reading manifest %s: %w", path, err)
|
||||
}
|
||||
var m Manifest
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return nil, fmt.Errorf("parsing manifest %s: %w", path, err)
|
||||
}
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// LibraryFiles returns the subset of Files that are .jar libraries (classpath).
|
||||
func (m *Manifest) LibraryFiles() []ManifestFile {
|
||||
var libs []ManifestFile
|
||||
for _, f := range m.Files {
|
||||
if len(f.Path) > 4 && f.Path[len(f.Path)-4:] == ".jar" {
|
||||
libs = append(libs, f)
|
||||
}
|
||||
}
|
||||
return libs
|
||||
}
|
||||
|
||||
// ModFiles returns the subset of Files that go into the mods/ directory.
|
||||
func (m *Manifest) ModFiles() []ManifestFile {
|
||||
var mods []ManifestFile
|
||||
for _, f := range m.Files {
|
||||
if len(f.Path) > 5 && f.Path[:5] == "mods/" {
|
||||
mods = append(mods, f)
|
||||
}
|
||||
}
|
||||
return mods
|
||||
}
|
||||
Reference in New Issue
Block a user