121 lines
3.5 KiB
Go
121 lines
3.5 KiB
Go
// Package layout resolves the supported Windows and macOS Brown Dust II
|
|
// installation layouts without relying on the host running bd2client.
|
|
package layout
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
type Kind string
|
|
|
|
const (
|
|
Windows Kind = "windows"
|
|
MacOS Kind = "macos"
|
|
)
|
|
|
|
type Installation struct {
|
|
Kind Kind
|
|
Selected string
|
|
Root string
|
|
Executable string
|
|
Data string
|
|
Resources string
|
|
Managers string
|
|
BepInEx string
|
|
Config string
|
|
Plugins string
|
|
Disabled string
|
|
}
|
|
|
|
func Resolve(selected string) (Installation, error) {
|
|
if strings.TrimSpace(selected) == "" {
|
|
return Installation{}, errors.New("select the Brown Dust II installation directory")
|
|
}
|
|
abs, err := filepath.Abs(strings.TrimSpace(selected))
|
|
if err != nil {
|
|
return Installation{}, fmt.Errorf("resolve game directory: %w", err)
|
|
}
|
|
abs = filepath.Clean(abs)
|
|
if installation, ok := windowsLayout(abs); ok {
|
|
return installation, nil
|
|
}
|
|
if installation, ok := macLayout(abs); ok {
|
|
return installation, nil
|
|
}
|
|
return Installation{}, errors.New("the selected directory is not a complete Brown Dust II Windows or macOS client")
|
|
}
|
|
|
|
func windowsLayout(root string) (Installation, bool) {
|
|
executable := filepath.Join(root, "BrownDust II.exe")
|
|
data := filepath.Join(root, "BrownDust II_Data")
|
|
if !regularFile(executable) || !regularFile(filepath.Join(data, "resources.assets")) {
|
|
return Installation{}, false
|
|
}
|
|
return newInstallation(Windows, root, root, executable, data, filepath.Join(root, "BepInEx")), true
|
|
}
|
|
|
|
func macLayout(selected string) (Installation, bool) {
|
|
candidates := []string{selected}
|
|
if !strings.EqualFold(filepath.Ext(selected), ".app") {
|
|
candidates = append(candidates, filepath.Join(selected, "BrownDust II.app"))
|
|
}
|
|
for _, app := range candidates {
|
|
contents := filepath.Join(app, "Contents")
|
|
executable := filepath.Join(contents, "MacOS", "BrownDust II")
|
|
data := filepath.Join(contents, "Resources", "Data")
|
|
if regularFile(executable) && regularFile(filepath.Join(data, "resources.assets")) {
|
|
// BepInEx Unix distributions are normally extracted beside the
|
|
// .app bundle. Also accept an installation placed inside Contents.
|
|
bepInEx := filepath.Join(filepath.Dir(app), "BepInEx")
|
|
insideBundle := filepath.Join(contents, "BepInEx")
|
|
if directoryExists(insideBundle) && !directoryExists(bepInEx) {
|
|
bepInEx = insideBundle
|
|
}
|
|
return newInstallation(MacOS, selected, app, executable, data, bepInEx), true
|
|
}
|
|
}
|
|
return Installation{}, false
|
|
}
|
|
|
|
func newInstallation(kind Kind, selected, root, executable, data, bepInEx string) Installation {
|
|
return Installation{
|
|
Kind: kind,
|
|
Selected: selected,
|
|
Root: root,
|
|
Executable: executable,
|
|
Data: data,
|
|
Resources: filepath.Join(data, "resources.assets"),
|
|
Managers: filepath.Join(data, "globalgamemanagers"),
|
|
BepInEx: bepInEx,
|
|
Config: filepath.Join(bepInEx, "config"),
|
|
Plugins: filepath.Join(bepInEx, "plugins"),
|
|
Disabled: filepath.Join(bepInEx, "disabled"),
|
|
}
|
|
}
|
|
|
|
func (i Installation) LaunchTarget() string {
|
|
if i.Kind == MacOS {
|
|
return i.Root
|
|
}
|
|
return i.Executable
|
|
}
|
|
|
|
func (i Installation) SupportedOnHost() bool {
|
|
return (i.Kind == Windows && runtime.GOOS == "windows") || (i.Kind == MacOS && runtime.GOOS == "darwin")
|
|
}
|
|
|
|
func regularFile(path string) bool {
|
|
info, err := os.Stat(path)
|
|
return err == nil && info.Mode().IsRegular()
|
|
}
|
|
|
|
func directoryExists(path string) bool {
|
|
info, err := os.Stat(path)
|
|
return err == nil && info.IsDir()
|
|
}
|