From ba388f8a749eb5f004662628e37471ec69ad1ba3 Mon Sep 17 00:00:00 2001 From: Flechazo <2558755403@qq.com> Date: Thu, 1 Oct 2026 01:19:42 +0800 Subject: [PATCH] fix(all): complete native client and free gacha flows --- go/cmd/bd2client/dev_command.go | 34 ++++++ go/cmd/bd2client/dev_command_release.go | 2 + go/cmd/bd2client/dev_command_test.go | 36 ++++++ go/cmd/bd2client/main.go | 9 ++ go/cmd/bd2client/wails_dev_tag.go | 5 + go/cmd/bd2client/wails_dev_tag_missing.go | 5 + go/internal/client/app/app_test.go | 3 +- go/internal/client/app/web/index.html | 12 +- go/internal/server/gacha/first_gacha_test.go | 4 + go/internal/server/gacha/gacha.go | 98 ++++++++++++---- go/internal/server/gacha/gacha_test.go | 113 ++++++++++++++++++- go/internal/server/gamedata/gacha.go | 45 ++++++-- 12 files changed, 327 insertions(+), 39 deletions(-) create mode 100644 go/cmd/bd2client/wails_dev_tag.go create mode 100644 go/cmd/bd2client/wails_dev_tag_missing.go diff --git a/go/cmd/bd2client/dev_command.go b/go/cmd/bd2client/dev_command.go index 577c9fc..0a739b8 100644 --- a/go/cmd/bd2client/dev_command.go +++ b/go/cmd/bd2client/dev_command.go @@ -20,6 +20,40 @@ type clientDevelopmentConfig struct { GameDirectory string `json:"game_directory"` } +var runDevelopmentChild = func(root string, args []string) error { + command := exec.Command("go", args...) + command.Dir = filepath.Join(root, "go") + command.Stdin = os.Stdin + command.Stdout = os.Stdout + command.Stderr = os.Stderr + return command.Run() +} + +// relaunchDevelopmentIfNeeded preserves the documented plain `go run` +// command. Wails selects its real desktop backend with the `dev` or +// `production` build tag; without either it deliberately links a diagnostic +// placeholder. The outer process therefore rebuilds itself once with +// `production`, retaining the embedded frontend and normal native host while +// the project-level --dev option supplies development paths and plugin builds. +func relaunchDevelopmentIfNeeded(args []string) (bool, error) { + if len(args) == 0 || args[0] != "--dev" || wailsDevelopmentBuild { + return false, nil + } + if len(args) < 2 || args[1] != "run" { + return false, nil + } + root, err := findClientDevelopmentRoot() + if err != nil { + return false, err + } + childArgs := []string{"run", "-tags", "production", "./cmd/bd2client", "--dev", "run"} + childArgs = append(childArgs, args[2:]...) + if err := runDevelopmentChild(root, childArgs); err != nil { + return false, fmt.Errorf("run Wails development client: %w", err) + } + return true, nil +} + func developmentRunOptions(args []string) ([]string, clientRunOptions, error) { if len(args) == 0 || args[0] != "--dev" { return args, clientRunOptions{}, nil diff --git a/go/cmd/bd2client/dev_command_release.go b/go/cmd/bd2client/dev_command_release.go index 5f9e45a..53ced98 100644 --- a/go/cmd/bd2client/dev_command_release.go +++ b/go/cmd/bd2client/dev_command_release.go @@ -2,6 +2,8 @@ package main +func relaunchDevelopmentIfNeeded([]string) (bool, error) { return false, nil } + func developmentRunOptions(args []string) ([]string, clientRunOptions, error) { return args, clientRunOptions{}, nil } diff --git a/go/cmd/bd2client/dev_command_test.go b/go/cmd/bd2client/dev_command_test.go index 86f6511..1f3fdce 100644 --- a/go/cmd/bd2client/dev_command_test.go +++ b/go/cmd/bd2client/dev_command_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "os" "path/filepath" + "reflect" "testing" ) @@ -105,3 +106,38 @@ func TestDevelopmentRunOptionsRequiresRun(t *testing.T) { t.Fatal("development command without run unexpectedly succeeded") } } + +func TestDevelopmentRunRelaunchesWithWailsProductionHost(t *testing.T) { + if wailsDevelopmentBuild { + t.Skip("test exercises the untagged bootstrap process") + } + previous := runDevelopmentChild + t.Cleanup(func() { runDevelopmentChild = previous }) + var gotRoot string + var gotArgs []string + runDevelopmentChild = func(root string, args []string) error { + gotRoot = root + gotArgs = append([]string(nil), args...) + return nil + } + relaunched, err := relaunchDevelopmentIfNeeded([]string{"--dev", "run", "--game-dir", "example"}) + if err != nil || !relaunched { + t.Fatalf("relaunched=%v err=%v", relaunched, err) + } + if !filepath.IsAbs(gotRoot) { + t.Fatalf("root is not absolute: %q", gotRoot) + } + want := []string{"run", "-tags", "production", "./cmd/bd2client", "--dev", "run", "--game-dir", "example"} + if !reflect.DeepEqual(gotArgs, want) { + t.Fatalf("child args=%v want=%v", gotArgs, want) + } +} + +func TestDevelopmentRunDoesNotRelaunchOtherCommands(t *testing.T) { + for _, args := range [][]string{nil, {"--game-dir", "example"}, {"--dev"}, {"--dev", "other"}} { + relaunched, err := relaunchDevelopmentIfNeeded(args) + if err != nil || relaunched { + t.Fatalf("args=%v relaunched=%v err=%v", args, relaunched, err) + } + } +} diff --git a/go/cmd/bd2client/main.go b/go/cmd/bd2client/main.go index 6c1dcb3..5c5d104 100644 --- a/go/cmd/bd2client/main.go +++ b/go/cmd/bd2client/main.go @@ -17,6 +17,15 @@ type clientRunOptions struct { } func main() { + relaunched, err := relaunchDevelopmentIfNeeded(os.Args[1:]) + if err != nil { + clientapp.ShowFatalError(err) + fmt.Fprintln(os.Stderr, "bd2client:", err) + os.Exit(1) + } + if relaunched { + return + } args, options, err := developmentRunOptions(os.Args[1:]) if err == nil { err = runClient(args, options) diff --git a/go/cmd/bd2client/wails_dev_tag.go b/go/cmd/bd2client/wails_dev_tag.go new file mode 100644 index 0000000..f7294b0 --- /dev/null +++ b/go/cmd/bd2client/wails_dev_tag.go @@ -0,0 +1,5 @@ +//go:build !release && (dev || production) + +package main + +const wailsDevelopmentBuild = true diff --git a/go/cmd/bd2client/wails_dev_tag_missing.go b/go/cmd/bd2client/wails_dev_tag_missing.go new file mode 100644 index 0000000..ef3bb52 --- /dev/null +++ b/go/cmd/bd2client/wails_dev_tag_missing.go @@ -0,0 +1,5 @@ +//go:build !release && !dev && !production + +package main + +const wailsDevelopmentBuild = false diff --git a/go/internal/client/app/app_test.go b/go/internal/client/app/app_test.go index c8f3494..2448df5 100644 --- a/go/internal/client/app/app_test.go +++ b/go/internal/client/app/app_test.go @@ -21,6 +21,7 @@ func TestEmbeddedStudioUsesNativeBindings(t *testing.T) { text := string(page) for _, marker := range []string{ "BD2 Client Studio", "window.go.app.Studio", "bridge().Initialize()", + "(()=>{", "async function navigateScene(next)", `id="directoryScene"`, `id="serverScene"`, `id="deskScene"`, `id="patch"`, `id="install"`, `id="launch"`, `value="official"`, `value="local"`, `value="server"`, @@ -32,7 +33,7 @@ func TestEmbeddedStudioUsesNativeBindings(t *testing.T) { t.Errorf("embedded desktop interface lacks %q", marker) } } - for _, obsolete := range []string{"fetch(", "/api/", "bd2-session", "X-BD2-Session", "{{.", "window_darwin.js"} { + for _, obsolete := range []string{"fetch(", "/api/", "bd2-session", "X-BD2-Session", "{{.", "window_darwin.js", "function go("} { if strings.Contains(text, obsolete) { t.Errorf("embedded desktop interface retains obsolete browser bridge %q", obsolete) } diff --git a/go/internal/client/app/web/index.html b/go/internal/client/app/web/index.html index 11347e8..3bf9926 100644 --- a/go/internal/client/app/web/index.html +++ b/go/internal/client/app/web/index.html @@ -56,6 +56,7 @@ main{max-width:1324px;margin:auto;padding:0 58px}.scene{position:relative}.intro