package provision import ( "fmt" "log" "strings" "zlh-agent/internal/provision/addons" "zlh-agent/internal/provision/devcontainer" "zlh-agent/internal/provision/minecraft" "zlh-agent/internal/provision/steam" "zlh-agent/internal/state" ) /* ProvisionAll — unified entrypoint for provisioning. IMPORTANT: - This function ONLY performs installation. - Validation/verification happens in ensureProvisioned(). - state.Config is treated as immutable desired state. */ func ProvisionAll(cfg state.Config) error { normalizeMinecraftConfig(&cfg) /* --------------------------------------------------------- BASE ROLE PROVISIONING --------------------------------------------------------- */ if cfg.ContainerType == "dev" { if err := devcontainer.Provision(cfg); err != nil { return err } } else { // Legacy / default behavior assumes game containers game := strings.ToLower(cfg.Game) variant := strings.ToLower(cfg.Variant) runtime := strings.ToLower(cfg.Runtime) /* --------------------------------------------------------- MINECRAFT --------------------------------------------------------- */ if game == "minecraft" { // 1. Install Java (runtime) if err := InstallJava(cfg); err != nil { return fmt.Errorf("java install failed: %w", err) } // 2. Game variant install switch variant { case "vanilla": if runtime != "fabric" { return fmt.Errorf("unsupported runtime: %s", cfg.Runtime) } if err := minecraft.InstallFabric(cfg); err != nil { return err } if err := minecraft.InjectFabricProxyLite(cfg); err != nil { return fmt.Errorf("fabricproxy-lite injection failed: %w", err) } case "fabric": if err := minecraft.InstallFabric(cfg); err != nil { return err } case "paper", "purpur", "quilt": if err := minecraft.InstallMinecraftJar(cfg); err != nil { return fmt.Errorf("minecraft jar install failed: %w", err) } case "forge": if err := minecraft.InstallMinecraftForge(cfg); err != nil { return fmt.Errorf("forge install failed: %w", err) } case "neoforge": if err := minecraft.InstallMinecraftNeoForge(cfg); err != nil { return fmt.Errorf("neoforge install failed: %w", err) } default: return fmt.Errorf("unsupported minecraft variant: %s", variant) } // 3. Config files generated AFTER variant installer if err := WriteEula(cfg); err != nil { return err } if err := WriteServerProperties(cfg); err != nil { return err } if err := WriteStartScript(cfg); err != nil { return err } } else if IsSteamGame(game) { /* --------------------------------------------------------- STEAM GAMES --------------------------------------------------------- */ // 1. SteamCMD install if err := steam.EnsureSteamCMD(); err != nil { return fmt.Errorf("steamcmd install failed: %w", err) } // 2. Install game-specific content switch game { case "valheim": if err := steam.InstallValheim(cfg); err != nil { return err } case "rust": if err := steam.InstallRust(cfg); err != nil { return err } case "terraria": if err := steam.InstallTerraria(cfg); err != nil { return err } case "projectzomboid": if err := steam.InstallProjectZomboid(cfg); err != nil { return err } default: return fmt.Errorf("unsupported steam game: %s", game) } // 3. Start script if err := WriteStartScript(cfg); err != nil { return err } } else { return fmt.Errorf( "unsupported container identity (containerType=%q game=%q)", cfg.ContainerType, cfg.Game, ) } } /* --------------------------------------------------------- ADDONS (OPTIONAL, ROLE-AGNOSTIC) --------------------------------------------------------- */ if cfg.ContainerType == "dev" && cfg.EnableCodeServer { seen := false for _, addon := range cfg.Addons { if addon == "codeserver" { seen = true break } } if !seen { cfg.Addons = append(cfg.Addons, "codeserver") } } if len(cfg.Addons) > 0 { if err := addons.Provision(cfg); err != nil { return err } } return nil } func normalizeMinecraftConfig(cfg *state.Config) { if cfg == nil { return } if !strings.EqualFold(cfg.ContainerType, "game") { return } if !strings.EqualFold(cfg.Game, "minecraft") { return } if !strings.EqualFold(cfg.Variant, "vanilla") { return } cfg.Runtime = "fabric" cfg.InternalProfile = "vanilla-fabric" cfg.ArtifactPath = fmt.Sprintf("minecraft/fabric/%s/server.jar", strings.TrimSpace(cfg.Version)) log.Printf("[provision] vmid=%d action=normalize original_variant=vanilla runtime=fabric profile=vanilla-fabric", cfg.VMID) log.Printf("[provision] vmid=%d variant=vanilla normalized_runtime=fabric", cfg.VMID) log.Printf("[provision] vmid=%d artifact_override=true source=fabric path=%s", cfg.VMID, cfg.ArtifactPath) }