feat: initial commit for G-Launcher based on Firefly with Horoyoi enhancements
This commit is contained in:
commit
a99470a69f
155 files changed
+19061
No files matched your search
@@ -0,0 +1,185 @@
|
||||
package fsService
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"g-launcher/pkg/sevenzip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type FSService struct{}
|
||||
|
||||
func (f *FSService) PickFolder() (string, error) {
|
||||
dialog := application.Get().Dialog.OpenFile().
|
||||
CanChooseDirectories(true).
|
||||
CanChooseFiles(false).
|
||||
ResolvesAliases(true)
|
||||
if runtime.GOOS == "darwin" {
|
||||
dialog.SetMessage("Select a folder")
|
||||
} else {
|
||||
dialog.SetTitle("Select a folder")
|
||||
}
|
||||
return dialog.PromptForSingleSelection()
|
||||
}
|
||||
|
||||
func (f *FSService) PickFile(filter string) (string, error) {
|
||||
dialog := application.Get().Dialog.OpenFile().
|
||||
CanChooseFiles(true).
|
||||
ResolvesAliases(true)
|
||||
if runtime.GOOS == "darwin" {
|
||||
dialog.SetMessage("Select a file")
|
||||
} else {
|
||||
dialog.SetTitle("Select a file")
|
||||
}
|
||||
if filter == "exe" {
|
||||
dialog.AddFilter("Executable Files (*.exe)", "*.exe")
|
||||
} else if filter == "zip" {
|
||||
dialog.AddFilter("ZIP archives (*.zip)", "*.zip")
|
||||
} else if filter == "patch" {
|
||||
dialog.AddFilter("Patch files (*.zip;*.7z;*.ziff)", "*.zip;*.7z;*.ziff")
|
||||
}
|
||||
if path, err := dialog.PromptForSingleSelection(); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (f *FSService) DirExists(path string) bool {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return info.IsDir()
|
||||
}
|
||||
|
||||
func (f *FSService) FileExists(path string) bool {
|
||||
if info, err := os.Stat(path); err == nil {
|
||||
return info.Mode().IsRegular()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *FSService) GetDir(path string) string {
|
||||
return filepath.Dir(path)
|
||||
}
|
||||
|
||||
func (f *FSService) Join(paths ...string) string {
|
||||
return filepath.Join(paths...)
|
||||
}
|
||||
|
||||
func (f *FSService) RemoveFile(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
func (f *FSService) StartApp(path string) (bool, string) {
|
||||
dir := filepath.Dir(path)
|
||||
cmd := exec.Command(path)
|
||||
cmd.Dir = dir
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, "StarRail.exe") || strings.HasSuffix(path, "ZenlessZoneZeroBeta.exe") {
|
||||
go func() {
|
||||
_ = cmd.Wait()
|
||||
application.Get().Event.Emit("game:exit")
|
||||
}()
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (f *FSService) StartWithConsole(path string) (bool, string) {
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
if _, err := os.Stat(absPath); os.IsNotExist(err) {
|
||||
return false, "file not found: " + absPath
|
||||
}
|
||||
cmd := exec.Command(absPath)
|
||||
cmd.Dir = filepath.Dir(absPath)
|
||||
cmd.Stdin = nil
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
|
||||
cmd.SysProcAttr = &windows.SysProcAttr{
|
||||
CreationFlags: windows.CREATE_NEW_CONSOLE |
|
||||
windows.CREATE_BREAKAWAY_FROM_JOB,
|
||||
NoInheritHandles: true,
|
||||
}
|
||||
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
go func() {
|
||||
_ = cmd.Wait()
|
||||
base := strings.ToLower(filepath.Base(path))
|
||||
if base == "launcher.exe" || base == "starrail.exe" {
|
||||
application.Get().Event.Emit("game:exit")
|
||||
} else if base == "firefly-go_win.exe" || base == "gameserver.exe" {
|
||||
application.Get().Event.Emit("server:exit")
|
||||
} else if base == "firefly-go-proxy.exe" || base == "proxy.exe" {
|
||||
application.Get().Event.Emit("proxy:exit")
|
||||
}
|
||||
}()
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (f *FSService) OpenFolder(path string) (bool, string) {
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return false, "failed to resolve absolute path: " + err.Error()
|
||||
}
|
||||
|
||||
if !f.DirExists(absPath) {
|
||||
return false, "directory not found: " + absPath
|
||||
}
|
||||
|
||||
url := "file:///" + filepath.ToSlash(absPath)
|
||||
application.Get().Browser.OpenURL(url)
|
||||
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func (f *FSService) FileExistsInZip(archivePath, fileInside string) (bool, string) {
|
||||
exists, err := sevenzip.IsFileIn7z(archivePath, fileInside)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
return exists, ""
|
||||
}
|
||||
|
||||
func (f *FSService) ReadConfigFile(gameDir, fileName string) (string, error) {
|
||||
if strings.TrimSpace(gameDir) == "" {
|
||||
return "", fmt.Errorf("select the game folder first")
|
||||
}
|
||||
target := filepath.Join(gameDir, fileName)
|
||||
content, err := os.ReadFile(target)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", nil
|
||||
}
|
||||
return "", fmt.Errorf("read file %s: %w", target, err)
|
||||
}
|
||||
return string(content), nil
|
||||
}
|
||||
|
||||
func (f *FSService) WriteConfigFile(gameDir, fileName, content string) error {
|
||||
if strings.TrimSpace(gameDir) == "" {
|
||||
return fmt.Errorf("select the game folder first")
|
||||
}
|
||||
target := filepath.Join(gameDir, fileName)
|
||||
return os.WriteFile(target, []byte(content), 0644)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package fsService
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type gameSelection struct {
|
||||
GamePath string `json:"gamePath"`
|
||||
GameDir string `json:"gameDir"`
|
||||
}
|
||||
|
||||
func gameSelectionPath() (string, error) {
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("resolve user config directory: %w", err)
|
||||
}
|
||||
|
||||
return filepath.Join(configDir, "g-launcher", "game-selection.json"), nil
|
||||
}
|
||||
|
||||
func (f *FSService) GetSavedGameSelection() (string, string, error) {
|
||||
path, err := gameSelectionPath()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return "", "", nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("read saved game selection: %w", err)
|
||||
}
|
||||
|
||||
var selection gameSelection
|
||||
if err := json.Unmarshal(data, &selection); err != nil {
|
||||
return "", "", fmt.Errorf("parse saved game selection: %w", err)
|
||||
}
|
||||
|
||||
return selection.GamePath, selection.GameDir, nil
|
||||
}
|
||||
|
||||
func (f *FSService) SaveGameSelection(gamePath, gameDir string) error {
|
||||
path, err := gameSelectionPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(gameSelection{GamePath: gamePath, GameDir: gameDir})
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode game selection: %w", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
|
||||
return fmt.Errorf("create game selection directory: %w", err)
|
||||
}
|
||||
|
||||
tempPath := path + ".tmp"
|
||||
if err := os.WriteFile(tempPath, data, 0600); err != nil {
|
||||
return fmt.Errorf("write game selection: %w", err)
|
||||
}
|
||||
|
||||
tempPathPtr, err := windows.UTF16PtrFromString(tempPath)
|
||||
if err != nil {
|
||||
_ = os.Remove(tempPath)
|
||||
return fmt.Errorf("encode temporary game selection path: %w", err)
|
||||
}
|
||||
pathPtr, err := windows.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
_ = os.Remove(tempPath)
|
||||
return fmt.Errorf("encode game selection path: %w", err)
|
||||
}
|
||||
if err := windows.MoveFileEx(tempPathPtr, pathPtr, windows.MOVEFILE_REPLACE_EXISTING|windows.MOVEFILE_WRITE_THROUGH); err != nil {
|
||||
_ = os.Remove(tempPath)
|
||||
return fmt.Errorf("replace saved game selection: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user