feat(research): one option per way to run a game, SteamCMD recommended
A draft built on a ready-made image whose files all live outside /server
went round three times and ended as WIP, although research had also
verified the game's Steam app, which SteamCMD installs straight into
/server. The build picked among the variant's images on its own.
- research reads each Steam app's OS list. When it ships a Linux server,
the SteamCMD route is the recommended option; for Windows-only servers,
images that bring Proton or Wine come first. The research prompt says
the same.
- A variant that can run on several images becomes one option per image
("... (SteamCMD)", "... (image x/y)"), so the admin picks exactly how the
server runs.
- build uses exactly the chosen option and never switches to another; if it
can't be made to work, the PR says so and another option can be picked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
274ed68cc5
commit
f2ffed5c98
3 files changed
+202
-61
No files matched your search
+26
-23
@@ -93,26 +93,35 @@ type buildOptions struct {
|
||||
agentImage string
|
||||
}
|
||||
|
||||
// build drafts the template for exactly the option the admin chose: one image (research lists each way to
|
||||
// run a game as its own option). It never switches to another image; if the chosen one can't be made to
|
||||
// work, the result says so and the admin can pick a different option.
|
||||
func build(o buildOptions) (*buildResult, error) {
|
||||
if len(o.variant.Images) == 0 {
|
||||
return nil, errors.New("the variant has no image to build from")
|
||||
}
|
||||
res := &buildResult{GameID: o.id, Dir: filepath.Join(o.gamesDir, o.id)}
|
||||
res.Verified = append(res.Verified, o.variant.Verified...)
|
||||
|
||||
// 1. First boot of each candidate image until one runs as a non-root user
|
||||
var report *bootReport
|
||||
for _, image := range o.variant.Images {
|
||||
steam := isSteamCMDImage(image) && o.variant.SteamAppID != ""
|
||||
if isSteamCMDImage(image) && !steam {
|
||||
if isSteamCMDImage(image) && o.variant.SteamAppID == "" {
|
||||
continue // the SteamCMD image alone runs nothing
|
||||
}
|
||||
res.Image = image
|
||||
if steam && o.variant.StartupHint == "" {
|
||||
fmt.Printf("[build] no startup command known for Steam app %s; drafting without a first boot\n", o.variant.SteamAppID)
|
||||
report = nil
|
||||
break
|
||||
res, err := buildWithImage(o, image)
|
||||
if res != nil {
|
||||
res.Summary = buildSummary(o, res)
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
return nil, errors.New("the variant has no image to build from")
|
||||
}
|
||||
|
||||
// buildWithImage drafts the template for one image: first boot, draft, then boots of the draft with
|
||||
// failures going back to the model.
|
||||
func buildWithImage(o buildOptions, image string) (*buildResult, error) {
|
||||
res := &buildResult{GameID: o.id, Dir: filepath.Join(o.gamesDir, o.id), Image: image}
|
||||
res.Verified = append(res.Verified, o.variant.Verified...)
|
||||
steam := isSteamCMDImage(image)
|
||||
|
||||
// 1. First boot of the image untouched: its log, files and settings are the draft's facts
|
||||
var report *bootReport
|
||||
if steam && o.variant.StartupHint == "" {
|
||||
fmt.Printf("[build] no startup command known for Steam app %s; drafting without a first boot\n", o.variant.SteamAppID)
|
||||
} else {
|
||||
fmt.Printf("[build] first boot of %s\n", image)
|
||||
r, err := firstBoot(o.id+"-probe", image, o.variant.SteamAppID, steam, o.variant.StartupHint)
|
||||
if err != nil {
|
||||
@@ -120,18 +129,12 @@ func build(o buildOptions) (*buildResult, error) {
|
||||
}
|
||||
if why := imageUnusable(r); why != "" {
|
||||
fmt.Printf("[build] %s can't be used: %s\n", image, why)
|
||||
res.Problems = append(res.Problems, why)
|
||||
res.Image = ""
|
||||
continue
|
||||
res.Problems = []string{why}
|
||||
return res, nil
|
||||
}
|
||||
report = r
|
||||
res.Verified = append(res.Verified, fmt.Sprintf("first boot of %s: %s", image, r.Outcome))
|
||||
break
|
||||
}
|
||||
if res.Image == "" {
|
||||
return res, errors.New("no image of this variant runs as a non-root user")
|
||||
}
|
||||
res.Problems = nil
|
||||
|
||||
// 2. Draft until validation and the image checks pass
|
||||
steamApp := ""
|
||||
|
||||
Reference in new issue
Block a user