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 }