164 lines
4.0 KiB
Go
164 lines
4.0 KiB
Go
package edit
|
|
|
|
import (
|
|
"errors"
|
|
"flag"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"aego/app/bootstrap"
|
|
"aego/app/brand"
|
|
"aego/app/supervise"
|
|
"aego/editor/core/session"
|
|
"aego/editor/shell/launcher"
|
|
"aego/platform"
|
|
"aego/project"
|
|
"aego/sdk"
|
|
)
|
|
|
|
const (
|
|
TabRecent = "recent"
|
|
TabNew = "new"
|
|
NoGoNote = "Go is not installed, so the native code of this project is not built and scenes that use its components may not load. Install Go from go.dev/dl and open the project again."
|
|
)
|
|
|
|
type Entry struct {
|
|
Config
|
|
Arg string
|
|
Launcher string
|
|
Verb string
|
|
Mods []sdk.Module
|
|
}
|
|
|
|
func Main(mods ...sdk.Module) {
|
|
fs := flag.NewFlagSet("aego-editor", flag.ExitOnError)
|
|
debug := fs.Bool("debug", false, "verbose logging and gpu debug output")
|
|
hidden := fs.Bool("hidden", false, "create the window without showing it")
|
|
headless := fs.Bool("headless", false, "run without a window")
|
|
frames := fs.Int("frames", 0, "run a fixed number of frames and exit")
|
|
cpu := fs.String("cpuprofile", "", "write a cpu profile to this file")
|
|
profile := fs.String("profile", "", "player settings profile, default when empty")
|
|
open := fs.String("open", "", "open this scene or prefab, relative to the project root")
|
|
tab := fs.String("launcher", "", "open the launcher on its recent or new tab instead of a project")
|
|
fs.Parse(os.Args[1:])
|
|
err := Start(Entry{
|
|
Config: Config{
|
|
Debug: *debug, Hidden: *hidden, Headless: *headless, Frames: *frames, CPUProfile: *cpu, Profile: *profile,
|
|
OpenPath: *open, Supervised: os.Getenv(session.EnvSupervised) == "1",
|
|
},
|
|
Arg: fs.Arg(0), Launcher: *tab, Mods: mods,
|
|
})
|
|
if errors.Is(err, ErrRestart) {
|
|
os.Exit(session.ExitRestart)
|
|
}
|
|
if err != nil {
|
|
fail(err)
|
|
}
|
|
}
|
|
|
|
func fail(err error) {
|
|
os.Stderr.WriteString("aego-editor: " + err.Error() + "\n")
|
|
platform.Boot("fatal", err.Error())
|
|
if !platform.ShowFatal("Aego", platform.FatalText("Aego", err.Error())) && !interactive() {
|
|
platform.Alert("Aego", err.Error())
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
|
|
func interactive() bool {
|
|
if runtime.GOOS == "windows" {
|
|
return false
|
|
}
|
|
st, err := os.Stderr.Stat()
|
|
return err == nil && st.Mode()&os.ModeCharDevice != 0
|
|
}
|
|
|
|
func goFound() bool {
|
|
_, err := exec.LookPath("go")
|
|
return err == nil
|
|
}
|
|
|
|
func hasProject(dir string) bool {
|
|
_, err := project.Find(dir)
|
|
return err == nil
|
|
}
|
|
|
|
func resolveArg(arg string) (dir, file string) {
|
|
if arg == "" {
|
|
return "", ""
|
|
}
|
|
st, err := os.Stat(arg)
|
|
if err != nil || st.IsDir() {
|
|
return arg, ""
|
|
}
|
|
abs, err := filepath.Abs(arg)
|
|
if err != nil {
|
|
return filepath.Dir(arg), ""
|
|
}
|
|
if filepath.Base(abs) == project.FileName {
|
|
return filepath.Dir(abs), ""
|
|
}
|
|
return filepath.Dir(abs), abs
|
|
}
|
|
|
|
func relInside(root, file string) (string, bool) {
|
|
rel, err := filepath.Rel(root, file)
|
|
if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
|
|
return "", false
|
|
}
|
|
return filepath.ToSlash(rel), true
|
|
}
|
|
|
|
func Start(e Entry) error {
|
|
defer platform.RecoverFatal("Aego")
|
|
startBoot("edit")
|
|
platform.SetAppIcon(brand.Window()...)
|
|
markEntry(e.Verb)
|
|
cfg := e.Config
|
|
if cfg.Recent == "" {
|
|
cfg.Recent, _ = launcher.RecentPath()
|
|
}
|
|
logs := attachLogs(&cfg)
|
|
defer logs.close()
|
|
dir, file := resolveArg(e.Arg)
|
|
if e.Launcher != "" || (dir == "" && !hasProject(".")) {
|
|
cfg.LauncherTab = e.Launcher
|
|
root, err := Launch(cfg)
|
|
if err != nil || root == "" {
|
|
return err
|
|
}
|
|
dir, file = root, ""
|
|
}
|
|
if dir == "" {
|
|
dir = "."
|
|
}
|
|
root, err := project.Find(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p, err := project.Load(root)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if file != "" {
|
|
if rel, ok := relInside(p.Root, file); ok {
|
|
cfg.OpenPath = rel
|
|
}
|
|
}
|
|
platform.Boot("editor", p.Root)
|
|
if bootstrap.NeedsNative(p) && !cfg.Headless && cfg.Frames == 0 && !cfg.Supervised {
|
|
if goFound() {
|
|
return supervise.Run(p, supervise.Options{
|
|
Debug: cfg.Debug, Hidden: cfg.Hidden, CPUProfile: cfg.CPUProfile, Profile: cfg.Profile,
|
|
Open: cfg.OpenPath, Stderr: logs.writer(os.Stderr),
|
|
})
|
|
}
|
|
cfg.NativeNote = NoGoNote
|
|
platform.Boot("native", NoGoNote)
|
|
}
|
|
return Run(p, cfg, e.Mods...)
|
|
}
|