mccl/internal/manifest/manifest.go

213 lines
5.8 KiB
Go
Raw Normal View History

package manifest
import (
"encoding/json"
"fmt"
"mccl/pkg/util"
"path"
"strings"
)
type Manifest struct {
InheritsFrom string `json:"inheritsFrom"`
Arguments struct {
Game []Argument `json:"game"`
Jvm []Argument `json:"jvm"`
} `json:"arguments"`
AssetIndex struct {
util.File
TotalSize int `json:"totalSize"`
} `json:"assetIndex"`
Assets string `json:"assets"`
ComplianceLevel int `json:"complianceLevel"`
Downloads map[string]util.File `json:"downloads"`
Id string `json:"id"`
JavaVersion struct {
Component string `json:"component"`
MajorVersion int `json:"majorVersion"`
} `json:"javaVersion"`
Libraries []Library `json:"libraries"`
Logging struct {
Client struct {
Argument string `json:"argument"`
File util.File `json:"file"`
Type string `json:"type"`
} `json:"client"`
} `json:"logging"`
MainClass string `json:"mainClass"`
MinecraftArguments string `json:"minecraftArguments"`
MinimumLauncherVersion int `json:"minimumLauncherVersion"`
ReleaseTime string `json:"releaseTime"`
Time string `json:"time"`
Type string `json:"type"`
}
// New returns a new Manifest for a specific Minecraft version.
func New(data []byte) (*Manifest, error) {
m := &Manifest{}
if err := json.Unmarshal(data, m); err != nil {
return nil, err
}
return m, nil
}
func (m *Manifest) BuildCommandLine(properties map[string]string) (arguments []string) {
if m.MinecraftArguments != "" {
arguments = append(arguments, fmt.Sprintf("-Djava.library.path=%s", properties["natives_directory"]))
arguments = append(arguments, "-cp")
arguments = append(arguments, properties["classpath"])
arguments = append(arguments, m.MainClass)
args := strings.Split(m.MinecraftArguments, " ")
for _, arg := range args {
if strings.HasPrefix(arg, "${") {
propName := arg[2 : len(arg)-1]
arg = properties[propName]
}
arguments = append(arguments, arg)
}
return arguments
}
var allArgs []Argument
allArgs = append(allArgs, m.Arguments.Jvm...)
if m.Logging.Client.Argument != "" {
logConf := strings.Split(m.Logging.Client.Argument, "${")[0]
logConf += properties["logging_path"]
allArgs = append(allArgs, Argument{Value: []string{logConf}})
}
allArgs = append(allArgs, Argument{Value: []string{m.MainClass}})
allArgs = append(allArgs, m.Arguments.Game...)
for _, arg := range allArgs {
ok, feature := arg.CheckRules()
if !ok {
continue
} else if feature != FeatureUnknown {
if _, ok := properties[feature.String()]; !ok {
continue
}
}
for _, v := range arg.Value {
if strings.Contains(v, "${library_directory}") {
v = strings.ReplaceAll(v, "${library_directory}", properties["library_directory"])
v = strings.ReplaceAll(v, "${classpath_separator}", properties["classpath_separator"])
} else if i := strings.Index(v, "${"); i != -1 {
j := strings.Index(v, "}")
propName := v[i+2 : j]
switch propName {
case "version_name":
if strings.Contains(m.Id, "forge") {
v = strings.ReplaceAll(v, "${version_name}", m.InheritsFrom)
} else {
v = strings.ReplaceAll(v, "${version_name}", m.Id)
}
case "assets_index_name":
v = m.Assets
case "version_type":
v = m.Type
default:
v = strings.Replace(v, v[i:j+1], properties[propName], 1)
}
}
arguments = append(arguments, v)
}
}
return arguments
}
func (m *Manifest) BuildClasspath(baseDir, clientPath string) string {
var sb []string = make([]string, 0, len(m.Libraries))
for _, lib := range m.Libraries {
if lib.CheckRules() {
sb = append(sb, path.Join(baseDir, "libraries", lib.Path()))
if natives := lib.Natives(); natives != nil {
sb = append(sb, path.Join(baseDir, "libraries", natives.Path))
}
}
}
if m.InheritsFrom != "" {
sb = append(sb, path.Join(clientPath, m.InheritsFrom, m.InheritsFrom+".jar"))
} else {
sb = append(sb, path.Join(clientPath, m.Id, m.Id+".jar"))
}
return strings.Join(sb, util.PathSeparator())
}
func (m *Manifest) InheritFrom(parent *Manifest) error {
if parent == nil {
return nil
}
m.Arguments.Game = append(parent.Arguments.Game, m.Arguments.Game...)
m.Arguments.Jvm = append(parent.Arguments.Jvm, m.Arguments.Jvm...)
if m.AssetIndex.TotalSize == 0 {
m.AssetIndex.File = parent.AssetIndex.File
m.AssetIndex.TotalSize = parent.AssetIndex.TotalSize
}
if m.Assets == "" {
m.Assets = parent.Assets
}
if m.ComplianceLevel == 0 {
m.ComplianceLevel = parent.ComplianceLevel
}
if m.Downloads == nil {
m.Downloads = make(map[string]util.File)
}
for k, v := range parent.Downloads {
m.Downloads[k] = v
}
if m.Id == "" {
m.Id = parent.Id
}
if m.JavaVersion.Component != "" {
m.JavaVersion.Component = parent.JavaVersion.Component
m.JavaVersion.MajorVersion = parent.JavaVersion.MajorVersion
}
merge_libs:
for _, plib := range parent.Libraries {
plname := strings.Split(plib.Name, ":")
for _, lib := range m.Libraries {
lname := strings.Split(lib.Name, ":")
if len(plname) == len(lname) {
if lname[0]+":"+lname[1] == plname[0]+":"+plname[1] {
continue merge_libs
}
}
}
m.Libraries = append(m.Libraries, plib)
}
if m.Logging.Client.Argument == "" {
m.Logging.Client.Argument = parent.Logging.Client.Argument
m.Logging.Client.Type = parent.Logging.Client.Type
m.Logging.Client.File = parent.Logging.Client.File
}
if m.MainClass == "" {
m.MainClass = parent.MainClass
}
if m.MinecraftArguments == "" {
m.MinecraftArguments = parent.MinecraftArguments
}
return nil
}