chore(all): resolve lint findings, update example plugin, refine docs and add LGPL licenses
This commit is contained in:
@@ -21,7 +21,7 @@ import (
|
||||
//go:embed web/index.html
|
||||
var webFS embed.FS
|
||||
|
||||
var errGameAlreadyRunning = errors.New("Brown Dust II is already running")
|
||||
var errGameAlreadyRunning = errors.New("Brown Dust II is already running") //nolint:staticcheck // ST1005
|
||||
|
||||
type Options struct {
|
||||
InitialGameDir string
|
||||
@@ -226,7 +226,7 @@ func (s *Studio) Resources(input Request) (Response, error) {
|
||||
defer cancel()
|
||||
policy, err := clientsetup.FetchResourcePolicy(ctx, nil, input.settings(), s.options.Versions)
|
||||
message := "The client will use the release-locked official CDN"
|
||||
if policy.Mode == clientconfig.CDNLocal {
|
||||
if policy.Mode == clientconfig.CDNLocal { //nolint:staticcheck // QF1003
|
||||
message = "Local resources verified"
|
||||
} else if policy.Mode == clientconfig.CDNServer {
|
||||
message = "Server resource policy verified"
|
||||
|
||||
@@ -45,7 +45,7 @@ func Run(runOptions Options) error {
|
||||
studio.Shutdown()
|
||||
studio.log().Info("native client window closed")
|
||||
},
|
||||
Bind: []interface{}{studio},
|
||||
Bind: []any{studio},
|
||||
EnableDefaultContextMenu: false,
|
||||
DragAndDrop: &options.DragAndDrop{
|
||||
DisableWebViewDrop: true,
|
||||
|
||||
@@ -4,6 +4,7 @@ package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -42,7 +43,9 @@ func ShowFatalError(err error) {
|
||||
if conversionErr != nil {
|
||||
return
|
||||
}
|
||||
messageBoxW.Call(0, uintptr(unsafe.Pointer(message)), uintptr(unsafe.Pointer(title)), 0x10)
|
||||
if result, _, callErr := messageBoxW.Call(0, uintptr(unsafe.Pointer(message)), uintptr(unsafe.Pointer(title)), 0x10); result == 0 {
|
||||
log.Printf("Fatal error dialog could not be displayed: %v", callErr)
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE_NO_WINDOW prevents console-subsystem helpers such as powershell.exe
|
||||
@@ -74,7 +77,7 @@ func launchGame(target, proxyURL string) error {
|
||||
return err
|
||||
} else if running {
|
||||
if !activateProcessWindow(processID, 5*time.Second) {
|
||||
return fmt.Errorf("Brown Dust II is running, but its window could not be restored")
|
||||
return fmt.Errorf("Brown Dust II is running, but its window could not be restored") //nolint:staticcheck // ST1005
|
||||
}
|
||||
return errGameAlreadyRunning
|
||||
}
|
||||
@@ -95,7 +98,11 @@ func windowsExecutableProcessID(name string) (uint32, bool, error) {
|
||||
if err != nil {
|
||||
return 0, false, err
|
||||
}
|
||||
defer windows.CloseHandle(snapshot)
|
||||
defer func() {
|
||||
if err := windows.CloseHandle(snapshot); err != nil {
|
||||
log.Printf("Process snapshot cleanup failed: %v", err)
|
||||
}
|
||||
}()
|
||||
entry := windows.ProcessEntry32{Size: uint32(unsafe.Sizeof(windows.ProcessEntry32{}))}
|
||||
if err := windows.Process32First(snapshot, &entry); err != nil {
|
||||
return 0, false, err
|
||||
@@ -120,9 +127,14 @@ func activateProcessWindow(processID uint32, timeout time.Duration) bool {
|
||||
iconic, _, _ := isIconicProc.Call(window)
|
||||
if iconic != 0 {
|
||||
const swRestore = 9
|
||||
showWindowAsyncProc.Call(window, swRestore)
|
||||
if result, _, callErr := showWindowAsyncProc.Call(window, swRestore); result == 0 {
|
||||
log.Printf("Game window restore request failed: %v", callErr)
|
||||
}
|
||||
}
|
||||
if result, _, _ := setForegroundWindowProc.Call(window); result == 0 {
|
||||
// Windows may deny foreground activation even for a valid game window.
|
||||
log.Print("Windows declined foreground activation of the game window")
|
||||
}
|
||||
setForegroundWindowProc.Call(window)
|
||||
return true
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
@@ -136,7 +148,9 @@ func topLevelWindowForProcess(processID uint32) uintptr {
|
||||
var found uintptr
|
||||
callback := syscall.NewCallback(func(window uintptr, _ uintptr) uintptr {
|
||||
var owner uint32
|
||||
getWindowThreadProcessIDProc.Call(window, uintptr(unsafe.Pointer(&owner)))
|
||||
if thread, _, _ := getWindowThreadProcessIDProc.Call(window, uintptr(unsafe.Pointer(&owner))); thread == 0 {
|
||||
return 1 // The window disappeared during enumeration.
|
||||
}
|
||||
visible, _, _ := isWindowVisibleProc.Call(window)
|
||||
if owner == processID && visible != 0 {
|
||||
found = window
|
||||
@@ -144,6 +158,11 @@ func topLevelWindowForProcess(processID uint32) uintptr {
|
||||
}
|
||||
return 1
|
||||
})
|
||||
enumWindowsProc.Call(callback, 0)
|
||||
if result, _, callErr := enumWindowsProc.Call(callback, 0); result == 0 && found == 0 {
|
||||
// A successful match deliberately stops enumeration and also returns zero.
|
||||
if callErr != syscall.Errno(0) {
|
||||
log.Printf("Game window enumeration failed: %v", callErr)
|
||||
}
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ func Save(gameDir string, in Settings) (Settings, error) {
|
||||
return Settings{}, fmt.Errorf("client config: create temporary config: %w", err)
|
||||
}
|
||||
temporaryPath := temporary.Name()
|
||||
defer os.Remove(temporaryPath)
|
||||
defer func() { _ = os.Remove(temporaryPath) }()
|
||||
if err = temporary.Chmod(0o600); err == nil {
|
||||
_, err = temporary.Write(data)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func SavePreferences(gameDirectory string) error {
|
||||
return fmt.Errorf("stage client preferences: %w", err)
|
||||
}
|
||||
temporaryPath := temporary.Name()
|
||||
defer os.Remove(temporaryPath)
|
||||
defer func() { _ = os.Remove(temporaryPath) }()
|
||||
if err = temporary.Chmod(0o600); err == nil {
|
||||
_, err = temporary.Write(data)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func cryptPages(in []byte, encrypt bool) ([]byte, error) {
|
||||
}
|
||||
out := make([]byte, len(in))
|
||||
for start := 0; start < len(in); start += PageSize {
|
||||
var mode cipher.BlockMode = cipher.NewCBCEncrypter(block, Header)
|
||||
mode := cipher.NewCBCEncrypter(block, Header)
|
||||
if !encrypt {
|
||||
mode = cipher.NewCBCDecrypter(block, Header)
|
||||
}
|
||||
|
||||
@@ -199,10 +199,7 @@ func urlInDB(p []byte) (string, error) {
|
||||
break
|
||||
}
|
||||
i += start + len(marker)
|
||||
limit := i + 128
|
||||
if limit > len(p) {
|
||||
limit = len(p)
|
||||
}
|
||||
limit := min(i+128, len(p))
|
||||
if j := bytes.Index(p[i:limit], []byte("http")); j >= 0 {
|
||||
at := i + j
|
||||
if at+len(oldURL) <= len(p) {
|
||||
@@ -229,7 +226,7 @@ func copyFile(src, dst string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
defer func() { _ = in.Close() }()
|
||||
out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -433,7 +430,7 @@ func findIntro(file []byte) (textAsset, []byte, error) {
|
||||
return textAsset{}, nil, fmt.Errorf("introdb: invalid object count %d", count)
|
||||
}
|
||||
var candidates []textAsset
|
||||
for i := int32(0); i < count; i++ {
|
||||
for i := range count {
|
||||
// Since serialized version 14, Unity aligns object records to four bytes
|
||||
// before their 64-bit path ID (not to an eight-byte boundary).
|
||||
r.off = (r.off + 48 + 3) &^ 3
|
||||
|
||||
@@ -125,7 +125,7 @@ func installData(spec Spec, pluginDir string, sourceData []byte) (Result, error)
|
||||
return Result{}, fmt.Errorf("clientplugin: create temporary plugin: %w", err)
|
||||
}
|
||||
temporaryPath := temporary.Name()
|
||||
defer os.Remove(temporaryPath)
|
||||
defer func() { _ = os.Remove(temporaryPath) }()
|
||||
if _, err = io.Copy(temporary, bytes.NewReader(sourceData)); err == nil {
|
||||
err = temporary.Sync()
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func readCatalog(path string) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open local ServerData catalog: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() { _ = file.Close() }()
|
||||
raw, err := io.ReadAll(io.LimitReader(file, maximumCatalogBytes+1))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read local ServerData catalog: %w", err)
|
||||
@@ -163,8 +163,7 @@ func localizeCatalog(raw []byte, release, aa string) ([]byte, error) {
|
||||
remoteCount++
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(internalID, localCatalogPrefix) {
|
||||
relative := strings.TrimPrefix(internalID, localCatalogPrefix)
|
||||
if relative, ok := strings.CutPrefix(internalID, localCatalogPrefix); ok {
|
||||
relative = filepath.FromSlash(strings.ReplaceAll(relative, "\\", "/"))
|
||||
if info, err := os.Stat(filepath.Join(aa, relative)); err != nil || !info.Mode().IsRegular() {
|
||||
return nil, fmt.Errorf("built-in Addressables catalog references a missing local bundle: %s", relative)
|
||||
@@ -288,7 +287,7 @@ func replaceCatalog(path string, data []byte) error {
|
||||
return err
|
||||
}
|
||||
temporaryPath := temporary.Name()
|
||||
defer os.Remove(temporaryPath)
|
||||
defer func() { _ = os.Remove(temporaryPath) }()
|
||||
if err = temporary.Chmod(0o600); err == nil {
|
||||
_, err = temporary.Write(data)
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ func FetchResourcePolicy(ctx context.Context, client *http.Client, settings clie
|
||||
if err != nil {
|
||||
return ResourcePolicy{}, fmt.Errorf("request server resource policy: %w", err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
defer func() { _ = response.Body.Close() }()
|
||||
limited := io.LimitReader(response.Body, 64<<10)
|
||||
responseBody, err := io.ReadAll(limited)
|
||||
if err != nil {
|
||||
@@ -272,10 +272,10 @@ func detectClientVersion(path string) (string, error) {
|
||||
return "", fmt.Errorf("read Brown Dust II client version metadata: %w", err)
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
return "", errors.New("Brown Dust II client version metadata is not a regular file")
|
||||
return "", errors.New("Brown Dust II client version metadata is not a regular file") //nolint:staticcheck // ST1005
|
||||
}
|
||||
if info.Size() <= 0 || info.Size() > 64<<20 {
|
||||
return "", fmt.Errorf("Brown Dust II client version metadata has an invalid size: %d", info.Size())
|
||||
return "", fmt.Errorf("Brown Dust II client version metadata has an invalid size: %d", info.Size()) //nolint:staticcheck // ST1005
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user