package main import ( "bufio" "encoding/json" "fmt" "io" "os" "os/exec" "runtime" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) type Project struct { EnginePath string `json:"enginePath"` ProjectPath string `json:"projectPath"` ProjectName string `json:"projectName"` Version string `json:"engineVersion"` } const projectsFilePath = "projects.json" var projectList *fyne.Container var logText *widget.Entry var scrollContainer *container.Scroll func loadProjects() ([]Project, error) { file, err := os.ReadFile(projectsFilePath) if err != nil { return nil, err } var projects []Project if err := json.Unmarshal(file, &projects); err != nil { return nil, err } return projects, nil } func generateUnrealSolution(project Project) { var buildCmd string switch runtime.GOOS { case "linux": buildCmd = project.EnginePath + "/Engine/Build/BatchFiles/Linux/GenerateProjectFiles.sh"; case "darwin": buildCmd = project.EnginePath + "/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" default: fmt.Println("Generate Project is not yet supported on Windows") return } projectCmd := project.ProjectPath + "/" + project.ProjectName + ".uproject" cmd := exec.Command(buildCmd, projectCmd, "-game") logToOutput(cmd) } func runUnrealProject(project Project) { var buildCmd string switch runtime.GOOS { case "linux": buildCmd = project.EnginePath + "/Engine/Binaries/Linux/UnrealEditor" case "darwin": buildCmd = project.EnginePath + "/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor" default: buildCmd = project.EnginePath + "/Engine/Binaries/Win64/UnrealEditor.exe" } projectCmd := project.ProjectPath + "/" + project.ProjectName + ".uproject" cmd := exec.Command(buildCmd, projectCmd) logToOutput(cmd) } func logToOutput(cmd *exec.Cmd) { stdout, err := cmd.StdoutPipe() if err != nil { fmt.Println("Error during pipe stdout creation") } stderr, err := cmd.StderrPipe() if err != nil { fmt.Println("Error during pipe stderr creation") } if err := cmd.Start(); err != nil { fmt.Println("Error while loading command") } readPipe := func(reader io.ReadCloser) { scanner := bufio.NewScanner(reader) for scanner.Scan() { logText.SetText(logText.Text + scanner.Text() + "\n") scrollContainer.ScrollToTop() } } go readPipe(stdout) go readPipe(stderr) if err := cmd.Wait(); err != nil { fmt.Println("Error") } } func main() { myApp := app.New() myWindow := myApp.NewWindow("Unreal Project Launcher") myWindow.Resize(fyne.NewSize(640, 400)) projects, err := loadProjects() if err != nil { fmt.Println("Error while loading projects") } logText = widget.NewMultiLineEntry() logText.SetMinRowsVisible(5) reloadUI := func() { projectList.RemoveAll() for _, project := range projects { projectName := project.ProjectName iconPath := project.ProjectPath + "/" + projectName + ".png" var projectIcon fyne.Resource if _, err := os.Stat(iconPath); err == nil { icon, err := fyne.LoadResourceFromPath(iconPath) if err == nil { projectIcon = icon } } if projectIcon == nil { projectIcon = theme.FileIcon() } icon := canvas.NewImageFromResource(projectIcon) icon.SetMinSize(fyne.NewSize(48, 48)) nameLabel := widget.NewLabel(projectName + " / Unreal Engine " + project.Version) nameLabel.Alignment = fyne.TextAlignLeading // Buttons generateBtn := widget.NewButton("Generate", func() { generateUnrealSolution(project) }) generateBtn.Resize(fyne.NewSize(150, 40)) generateBtn.Size().Min(fyne.NewSize(150, 40)) launchBtn := widget.NewButton("Start", func() { runUnrealProject(project) }) launchBtn.Size().Min(fyne.NewSize(150, 40)) deleteBtn := widget.NewButton("X", func() { }) // Row row := container.NewHBox( icon, nameLabel, layout.NewSpacer(), generateBtn, launchBtn, deleteBtn, ) projectList.Add(row) } } projectList = container.NewVBox() reloadUI() scrollContainer = container.NewVScroll(projectList) mainContainer := container.NewBorder(nil, logText, nil, nil, scrollContainer) myWindow.SetContent(mainContainer) myWindow.ShowAndRun() }