feat: game templates, schemas and validator
Validate game templates / validate (push) Successful in 10m6s

Public game templates for GBR Hosting, one games/<id>/game.yaml per game,
imported from the panel. A Go tool validates them against JSON Schemas and
checks for credentials, private addresses and consents that default to
accepted; CI runs it on every push.

Admin/RCON passwords are no longer shared defaults: they are blank with
x-generate so the panel creates one per server, and Palworld/ARK no longer
publish their RCON/REST ports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
gregandClaude Opus 5.5 committed 2026-10-24 16:54:21 -04:00
commit 822b44e2e5
20 files changed
+2283

No files matched your search

+23
View File
@@ -0,0 +1,23 @@
name: Validate game templates
# Push-only on purpose: this repo is public, and a pull_request trigger would run a fork's
# version of this workflow on our self-hosted runner. PRs from branches in this repo are
# still checked through their push.
on:
push:
workflow_dispatch:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Validate
run: go run ./cmd/gbrgames validate
+6
View File
@@ -0,0 +1,6 @@
# Raw panel exports contain disabled games and panel-only settings; only game folders are published.
*.export.json
export.json
/gbrgames
/gbrgames.exe
+72
View File
@@ -0,0 +1,72 @@
# GBR Hosting game templates
Every game you can host on [GBR Hosting](https://gbrhosting.com) is defined by a template in this repo.
They're public so you can see exactly what your server runs: the Docker image, the startup command,
the install script, and every default setting.
## Layout
```
games/<id>/game.yaml the template
games/<id>/test.yaml values CI uses to boot-test it
schema/ JSON Schemas for both files
cmd/gbrgames/ validator and importer
```
## Reading a template
| Field | What it means |
| --- | --- |
| `defaultDockerImage` | The container image your server runs in. |
| `defaultStartupCommand` | The command started inside that container. |
| `installMethod` / `installConfig` | How game files are installed: `STEAMCMD` (anonymous SteamCMD download of `appId`), `BASH_SCRIPT` (the `script` shown in full), or `NONE` (the image already contains the game). |
| `defaultPorts` | Ports opened for players. |
| `defaultConfig` | Starting value for every setting. |
| `configSchema` | Which settings you can edit in the panel, with their types and limits. |
| `configFilePath` / `configFileFormat` | Where settings are written in your server's files, and in what format (`INI`, `JSON` or `ENV`). |
| `backupPaths` | What's included in backups. |
### Your settings vs. the defaults
When you create a server, it starts with `defaultConfig`. Anything you change in the panel overrides
that one setting for your server only; everything else keeps following the template. A few settings
are fixed by your plan. For example, the key named in `maxPlayersConfigKey` always matches your plan's
player count.
### Values filled in for you
Some defaults are placeholders the panel replaces when your server starts:
| Placeholder | Becomes |
| --- | --- |
| `{SERVER_NAME}` | Your server's name. |
| `{PUBLIC_IP}`, `{PUBLIC_HOST}`, `{PUBLIC_PORT_n}` | The address players connect to. |
| `{saved:KEY}` | A value you stored under Saved Values (e.g. a password or token). |
### Generated passwords
Admin and RCON passwords are never shared between servers. A setting marked `x-generate` is left blank
in the template, and if you leave it blank when you deploy, your server gets its own easy password like
`otter-maple-42`. You can see it and change it any time in your server's settings. Values under
`replace` are old shared defaults: a server still using one gets a fresh password the next time it starts.
### Agreements
A setting marked `x-consent` in `configSchema` (a game's EULA, for example) is never accepted for you.
You tick it yourself when you deploy.
## Changes
Templates are maintained by GBR Hosting. Every change is a commit here, so the history shows what
changed for each game and when. Want a game added or something fixed? Open an issue.
## Tooling
```bash
go run ./cmd/gbrgames validate # what CI runs on every push
go run ./cmd/gbrgames import admin-games.export.json # pull templates from GET /api/v1/admin/games
```
Besides the schemas, `validate` checks that each folder name matches its `id`, that referenced config
keys exist, that consents don't default to accepted, and that no credentials or private network
addresses end up in a template.
+162
View File
@@ -0,0 +1,162 @@
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
"math"
"os"
"path/filepath"
"strings"
"gopkg.in/yaml.v3"
)
// Game fields in the order they are written to game.yaml. Panel-owned business settings
// (enabled, allowPaidHosting, allowPrivateHosting, imageUrl) are deliberately left out.
var gameFields = []string{
"id", "name",
"defaultDockerImage", "defaultStartupCommand", "requiredMemoryMb", "requiredDiskMb", "defaultPorts",
"installMethod", "installConfig",
"defaultConfig", "configSchema", "configFilePath", "configFileFormat", "configFormatOptions",
"agnosticCommandConfig", "clusterConfig",
"logFilePath", "backupPaths", "maxBackupSizeMb",
"publicIpConfigKey", "maxPlayersConfigKey", "mapConfigKey",
"aiCoverPrompt",
}
const gameHeader = "# yaml-language-server: $schema=../../schema/game.schema.json\n"
const testHeader = "# yaml-language-server: $schema=../../schema/test.schema.json\n" +
"# Values CI uses to boot-test this game. Never put real credentials here: map them under 'secrets'.\n"
func runImport(args []string) error {
fs := flag.NewFlagSet("import", flag.ExitOnError)
gamesDir := fs.String("games", "games", "directory to write one folder per game into")
all := fs.Bool("all", false, "also import games that are disabled in the panel")
fs.Parse(args)
if fs.NArg() != 1 {
return errors.New("import needs the path to a GET /api/v1/admin/games export")
}
raw, err := os.ReadFile(fs.Arg(0))
if err != nil {
return err
}
var games []map[string]any
if err := json.Unmarshal(raw, &games); err != nil {
return fmt.Errorf("export is not a JSON array of games: %w", err)
}
for _, g := range games {
id, _ := g["id"].(string)
if id == "" {
return errors.New("export contains a game without an id")
}
if g["enabled"] == false && !*all {
fmt.Printf("skip %s (disabled in panel; use -all to include)\n", id)
continue
}
dir := filepath.Join(*gamesDir, id)
if err := os.MkdirAll(dir, 0o755); err != nil {
return err
}
if err := writeGame(filepath.Join(dir, "game.yaml"), g); err != nil {
return fmt.Errorf("%s: %w", id, err)
}
testPath := filepath.Join(dir, "test.yaml")
if _, err := os.Stat(testPath); errors.Is(err, os.ErrNotExist) {
if err := writeTest(testPath, g); err != nil {
return fmt.Errorf("%s: %w", id, err)
}
}
fmt.Printf("wrote %s\n", dir)
}
return nil
}
func writeGame(path string, g map[string]any) error {
doc := &yaml.Node{Kind: yaml.MappingNode}
for _, f := range gameFields {
v, ok := g[f]
if !ok || isEmpty(v) {
continue
}
var val yaml.Node
if err := val.Encode(normalize(v)); err != nil {
return err
}
doc.Content = append(doc.Content, &yaml.Node{Kind: yaml.ScalarNode, Value: f}, &val)
}
return writeYAML(path, gameHeader, doc)
}
// writeTest seeds a boot-test fixture: consents (EULAs) accepted, a timeout sized to the install method.
func writeTest(path string, g map[string]any) error {
cfg := map[string]any{}
for key, p := range schemaProperties(g) {
if prop, ok := p.(map[string]any); ok {
if c, ok := prop["x-consent"]; ok && c != false {
cfg[key] = true
}
}
}
timeout := 900
if g["installMethod"] == "STEAMCMD" {
timeout = 2400
}
test := map[string]any{"timeoutSec": timeout}
if len(cfg) > 0 {
test["config"] = cfg
}
var doc yaml.Node
if err := doc.Encode(test); err != nil {
return err
}
return writeYAML(path, testHeader, &doc)
}
func writeYAML(path, header string, doc *yaml.Node) error {
var b strings.Builder
b.WriteString(header)
enc := yaml.NewEncoder(&b)
enc.SetIndent(2)
if err := enc.Encode(doc); err != nil {
return err
}
enc.Close()
return os.WriteFile(path, []byte(b.String()), 0o644)
}
// normalize turns whole-number floats from encoding/json back into ints so YAML shows 25565, not 25565.0.
func normalize(v any) any {
switch x := v.(type) {
case float64:
if x == math.Trunc(x) && math.Abs(x) < 1<<53 {
return int64(x)
}
case map[string]any:
for k, e := range x {
x[k] = normalize(e)
}
case []any:
for i, e := range x {
x[i] = normalize(e)
}
}
return v
}
func isEmpty(v any) bool {
switch x := v.(type) {
case nil:
return true
case string:
return x == ""
case map[string]any:
return len(x) == 0
case []any:
return len(x) == 0
}
return false
}
+34
View File
@@ -0,0 +1,34 @@
// Command gbrgames validates the game templates in this repo and imports them from a panel export.
//
// go run ./cmd/gbrgames validate # check every games/<id>/game.yaml (+ test.yaml)
// go run ./cmd/gbrgames import export.json # write games/<id>/ from GET /api/v1/admin/games
package main
import (
"fmt"
"os"
)
func main() {
if len(os.Args) < 2 {
usage()
}
var err error
switch os.Args[1] {
case "validate":
err = runValidate(os.Args[2:])
case "import":
err = runImport(os.Args[2:])
default:
usage()
}
if err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
}
func usage() {
fmt.Fprintln(os.Stderr, "usage: gbrgames validate [-games DIR] | import [-games DIR] [-all] EXPORT.json")
os.Exit(2)
}
+255
View File
@@ -0,0 +1,255 @@
package main
import (
"bytes"
"encoding/json"
"errors"
"flag"
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"github.com/santhosh-tekuri/jsonschema/v6"
"gopkg.in/yaml.v3"
)
var (
// Config keys whose default value must never be a real credential.
sensitiveKey = regexp.MustCompile(`(?i)(pass(word)?|secret|token|api[_-]?key|rcon)`)
// A value made only of panel placeholders, e.g. "{saved:RCON_PASSWORD}".
placeholderOnly = regexp.MustCompile(`^(\{[A-Za-z0-9_:.-]+\})+$`)
// RFC 1918 addresses: home-lab and VPC details have no place in a public repo.
privateIP = regexp.MustCompile(`\b(10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3})\b`)
)
func runValidate(args []string) error {
fs := flag.NewFlagSet("validate", flag.ExitOnError)
gamesDir := fs.String("games", "games", "directory holding one folder per game")
schemaDir := fs.String("schemas", "schema", "directory holding game.schema.json and test.schema.json")
fs.Parse(args)
gameSchema, err := compileSchema(filepath.Join(*schemaDir, "game.schema.json"))
if err != nil {
return err
}
testSchema, err := compileSchema(filepath.Join(*schemaDir, "test.schema.json"))
if err != nil {
return err
}
entries, err := os.ReadDir(*gamesDir)
if err != nil {
return err
}
failed, checked := 0, 0
for _, e := range entries {
if !e.IsDir() {
continue
}
checked++
problems := validateGame(filepath.Join(*gamesDir, e.Name()), e.Name(), gameSchema, testSchema)
if len(problems) == 0 {
fmt.Printf("ok %s\n", e.Name())
continue
}
failed++
fmt.Printf("FAIL %s\n", e.Name())
for _, p := range problems {
fmt.Printf(" - %s\n", p)
}
}
if checked == 0 {
return fmt.Errorf("no games found in %s", *gamesDir)
}
if failed > 0 {
return fmt.Errorf("%d of %d games failed validation", failed, checked)
}
fmt.Printf("\nall %d games valid\n", checked)
return nil
}
func validateGame(dir, folder string, gameSchema, testSchema *jsonschema.Schema) []string {
var problems []string
add := func(format string, a ...any) { problems = append(problems, fmt.Sprintf(format, a...)) }
raw, err := os.ReadFile(filepath.Join(dir, "game.yaml"))
if err != nil {
return []string{"missing game.yaml"}
}
game, err := loadYAML(raw)
if err != nil {
return []string{"game.yaml: " + err.Error()}
}
if err := gameSchema.Validate(game); err != nil {
add("game.yaml does not match schema:\n%s", indent(schemaErrors(err)))
return problems // later checks assume the basic shape is right
}
g := game.(map[string]any)
if g["id"] != folder {
add("id %q must match folder name %q", g["id"], folder)
}
scanPrivateIPs(raw, "game.yaml", add)
defaults, _ := g["defaultConfig"].(map[string]any)
props := schemaProperties(g)
known := map[string]bool{}
for k := range defaults {
known[k] = true
}
for k := range props {
known[k] = true
}
// publicIpConfigKey and maxPlayersConfigKey are injected by the panel, so only the map key must already exist.
if key, ok := g["mapConfigKey"].(string); ok && key != "" && !known[key] {
add("mapConfigKey %q is not in defaultConfig or configSchema", key)
}
for _, key := range sortedKeys(defaults) {
if sensitiveKey.MatchString(key) && isCredential(defaults[key]) {
add("defaultConfig.%s looks like a credential; leave it empty or use a placeholder like {saved:%s}", key, key)
}
}
for _, key := range sortedKeys(props) {
prop, _ := props[key].(map[string]any)
if sensitiveKey.MatchString(key) && isCredential(prop["default"]) {
add("configSchema.properties.%s.default looks like a credential; leave it empty", key)
}
}
for _, key := range sortedKeys(props) {
prop, _ := props[key].(map[string]any)
if c, ok := prop["x-consent"]; !ok || c == false {
continue
}
if truthy(prop["default"]) || truthy(defaults[key]) {
add("consent %q must not default to true: users have to accept it themselves", key)
}
}
testRaw, err := os.ReadFile(filepath.Join(dir, "test.yaml"))
if errors.Is(err, os.ErrNotExist) {
return problems
}
if err != nil {
add("test.yaml: %v", err)
return problems
}
test, err := loadYAML(testRaw)
if err != nil {
add("test.yaml: %v", err)
return problems
}
if err := testSchema.Validate(test); err != nil {
add("test.yaml does not match schema:\n%s", indent(schemaErrors(err)))
return problems
}
scanPrivateIPs(testRaw, "test.yaml", add)
t := test.(map[string]any)
cfg, _ := t["config"].(map[string]any)
secrets, _ := t["secrets"].(map[string]any)
for _, key := range sortedKeys(cfg) {
if !known[key] {
add("test.yaml config.%s is not a key of this game", key)
}
if sensitiveKey.MatchString(key) {
add("test.yaml config.%s looks like a credential; map it under 'secrets' to a Gitea secret instead", key)
}
}
for _, key := range sortedKeys(secrets) {
if !known[key] {
add("test.yaml secrets.%s is not a key of this game", key)
}
}
return problems
}
func compileSchema(path string) (*jsonschema.Schema, error) {
raw, err := os.ReadFile(path)
if err != nil {
return nil, err
}
doc, err := jsonschema.UnmarshalJSON(bytes.NewReader(raw))
if err != nil {
return nil, fmt.Errorf("%s: %w", path, err)
}
id, _ := doc.(map[string]any)["$id"].(string)
if id == "" {
return nil, fmt.Errorf("%s: missing $id", path)
}
c := jsonschema.NewCompiler()
if err := c.AddResource(id, doc); err != nil {
return nil, err
}
return c.Compile(id)
}
// loadYAML decodes YAML into the JSON data model the schema validator expects.
func loadYAML(raw []byte) (any, error) {
var v any
if err := yaml.Unmarshal(raw, &v); err != nil {
return nil, err
}
if v == nil {
return nil, errors.New("file is empty")
}
j, err := json.Marshal(v)
if err != nil {
return nil, err
}
return jsonschema.UnmarshalJSON(bytes.NewReader(j))
}
func schemaProperties(g map[string]any) map[string]any {
s, _ := g["configSchema"].(map[string]any)
p, _ := s["properties"].(map[string]any)
return p
}
func scanPrivateIPs(raw []byte, file string, add func(string, ...any)) {
for i, line := range strings.Split(string(raw), "\n") {
if ip := privateIP.FindString(line); ip != "" {
add("%s line %d contains private address %s", file, i+1, ip)
}
}
}
func schemaErrors(err error) string {
var ve *jsonschema.ValidationError
if errors.As(err, &ve) {
return fmt.Sprintf("%v", ve)
}
return err.Error()
}
func indent(s string) string {
return " " + strings.ReplaceAll(strings.TrimSpace(s), "\n", "\n ")
}
func isCredential(v any) bool {
s, ok := v.(string)
return ok && s != "" && !placeholderOnly.MatchString(s)
}
func truthy(v any) bool {
switch x := v.(type) {
case bool:
return x
case string:
return strings.EqualFold(strings.TrimSpace(x), "true")
}
return false
}
func sortedKeys(m map[string]any) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
@@ -0,0 +1,332 @@
# yaml-language-server: $schema=../../schema/game.schema.json
id: ark-survival-ascended-crossplay
name: 'ARK: Survival Ascended (Crossplay Dedicated Server)'
defaultDockerImage: mschnitzer/asa-linux-server:latest
defaultStartupCommand: bash -c 'mkdir -p /server /data/Steam /data/steamcmd /data/cluster-shared && rm -rf /home/gameserver/server-files /home/gameserver/Steam /home/gameserver/steamcmd /home/gameserver/cluster-shared && ln -sfn /server /home/gameserver/server-files && ln -sfn /data/Steam /home/gameserver/Steam && ln -sfn /data/steamcmd /home/gameserver/steamcmd && ln -sfn /data/cluster-shared /home/gameserver/cluster-shared && export ASA_START_PARAMS="${ASA_START_PARAMS:-${SERVER_MAP:-TheIsland_WP}?listen?Port=${PORT:-7777}?RCONPort=${RCON_PORT:-27020}?RCONEnabled=True -WinLiveMaxPlayers=${MAX_PLAYERS:-70} -ServerPlatform=ALL}" && exec /usr/bin/start_server'
requiredMemoryMb: 16384
requiredDiskMb: 32768
defaultPorts:
- 7777/udp
installMethod: NONE
defaultConfig:
AdminLogging: false
AllowFlyerCarryPvE: false
AllowHitMarkers: true
AllowThirdPersonPlayer: true
AlwaysAllowStructurePickup: true
AutoSavePeriodMinutes: 15
DayCycleSpeedScale: 1
DayTimeSpeedScale: 1
DifficultyOffset: 1
DisableDinoDecayPvE: false
DisableStructureDecayPvE: false
EnablePVPGamma: false
MaxPlayers: 70
NightTimeSpeedScale: 1
OverrideOfficialDifficulty: 5
Port: 7777
PreventDiseases: false
PreventDownloadDinos: false
PreventDownloadItems: false
PreventDownloadSurvivors: false
PreventUploadDinos: false
PreventUploadItems: false
PreventUploadSurvivors: false
RCONEnabled: true
RCONPort: 27020
ServerAdminPassword: ""
ServerCrosshair: true
ServerHardcore: false
ServerMap: TheIsland_WP
ServerPVE: false
ServerPassword: ""
ShowFloatingDamageText: false
ShowMapPlayerLocation: true
bDisableStructurePlacementCollision: false
configSchema:
$schema: http://json-schema.org/draft-07/schema#
properties:
AdminLogging:
category: Security & Access
default: false
description: Broadcasts in-game administrative commands in chat to all connected players.
title: Admin Command Logging
type: boolean
AllowFlyerCarryPvE:
category: Gameplay & Rules
default: false
description: Allows airborne tamed creatures to pick up and carry wild or non-allied dinosaurs in PvE.
title: Allow Flyer Carry in PvE
type: boolean
AllowHitMarkers:
category: Gameplay & Rules
default: true
description: Shows floating visual indicators when striking an enemy or creature.
title: Allow Hit Markers
type: boolean
AllowThirdPersonPlayer:
category: Gameplay & Rules
default: true
description: Permits players to switch between first-person and third-person camera views.
title: Allow Third Person
type: boolean
AlwaysAllowStructurePickup:
category: Gameplay & Rules
default: true
description: Allows players to pick up placed structures indefinitely without demolition restrictions.
title: Always Allow Structure Pickup
type: boolean
AutoSavePeriodMinutes:
category: World & Environment
default: 15
description: Frequency in minutes at which the server automatically saves world and player state.
title: Auto-Save Interval (Minutes)
type: number
DayCycleSpeedScale:
category: World & Environment
default: 1
description: Global multiplier adjusting the overall speed of the 24-hour day/night cycle.
title: Day Cycle Speed Scale
type: number
DayTimeSpeedScale:
category: World & Environment
default: 1
description: Multiplier governing the passage speed of daytime hours relative to standard speed.
title: Day Time Speed Scale
type: number
DifficultyOffset:
category: Gameplay & Rules
default: 1
description: Base difficulty multiplier governing wild creature level distributions (0.0 to 1.0).
title: Difficulty Offset
type: number
DisableDinoDecayPvE:
category: Gameplay & Rules
default: false
description: Disables unclaiming timers and decay for inactive tamed creatures in PvE mode.
title: Disable Dino Decay in PvE
type: boolean
DisableStructureDecayPvE:
category: Gameplay & Rules
default: false
description: Disables the automatic structure decay and demolition timer on abandoned PvE bases.
title: Disable Structure Decay in PvE
type: boolean
EnablePVPGamma:
category: Gameplay & Rules
default: false
description: Allows players to use client gamma brightness adjustments during PvP sessions.
title: Enable PvP Gamma
type: boolean
MaxPlayers:
category: System & General
default: 70
description: Maximum number of simultaneous players allowed on the server.
title: Max Players
type: integer
NightTimeSpeedScale:
category: World & Environment
default: 1
description: Multiplier governing the passage speed of nighttime hours relative to standard speed.
title: Night Time Speed Scale
type: number
OverrideOfficialDifficulty:
category: Gameplay & Rules
default: 5
description: Sets the maximum wild dino level ceiling (e.g. 5.0 allows wild creatures up to level 150).
title: Override Official Difficulty
type: number
Port:
category: System & General
default: 7777
description: Primary UDP port used by game clients to connect to the dedicated server.
title: Game Port
type: integer
PreventDiseases:
category: Gameplay & Rules
default: false
description: Disables all permanent sicknesses and diseases from afflicting players.
title: Prevent Diseases
type: boolean
PreventDownloadDinos:
category: Security & Access
default: false
description: Blocks transferring tamed creatures into the server from external cluster servers.
title: Prevent Download Dinos
type: boolean
PreventDownloadItems:
category: Security & Access
default: false
description: Blocks downloading items or inventory into the server from external sources or cluster.
title: Prevent Download Items
type: boolean
PreventDownloadSurvivors:
category: Security & Access
default: false
description: Blocks transferring survivor characters into the server from other cluster servers.
title: Prevent Download Survivors
type: boolean
PreventUploadDinos:
category: Security & Access
default: false
description: Disallows survivors from uploading tamed creatures to cluster cloud storage.
title: Prevent Upload Dinos
type: boolean
PreventUploadItems:
category: Security & Access
default: false
description: Disallows survivors from uploading items and equipment to cluster cloud storage.
title: Prevent Upload Items
type: boolean
PreventUploadSurvivors:
category: Security & Access
default: false
description: Disallows survivors from uploading their character data to cluster cloud storage.
title: Prevent Upload Survivors
type: boolean
RCONEnabled:
category: Security & Access
default: true
description: Enables remote console (RCON) access for external server administration tools.
title: Enable RCON
type: boolean
RCONPort:
category: System & General
default: 27020
description: TCP port for remote console management and server administration.
title: RCON Port
type: integer
ServerAdminPassword:
category: Security & Access
default: ""
description: Password for admin commands in-game and for GBR actions over RCON (kick, ban, save, broadcast). Leave blank and GBR generates an easy one for your server.
showOnDeploy: true
title: Admin Password
type: string
x-savedValue:
key: GAME_ADMIN_PASSWORD
label: Game admin password
secret: true
x-generate:
type: password
replace:
- AdminPassword123
ServerCrosshair:
category: Gameplay & Rules
default: true
description: Enables an on-screen targeting crosshair for all players.
title: Enable Crosshair
type: boolean
ServerHardcore:
category: Security & Access
default: false
description: When enabled, player death permanently deletes the character and resets progression.
title: Hardcore Mode
type: boolean
ServerMap:
category: World & Environment
default: TheIsland_WP
description: Select the world map loaded by the dedicated server.
enum:
- TheIsland_WP
- ScorchedEarth_WP
- TheCenter_WP
- Aberration_WP
- Extinction_WP
showOnDeploy: true
title: Active World Map
type: string
ServerPVE:
category: Gameplay & Rules
default: false
description: Disables player-versus-player combat and structure damage, enabling cooperative PvE mode.
title: PvE Mode
type: boolean
ServerPassword:
category: Security & Access
default: ""
description: Password required for players to join the server. Leave blank to keep the server public.
showOnDeploy: true
title: Server Password
type: string
x-savedValue:
key: GAME_JOIN_PASSWORD
label: Game join password
secret: true
ShowFloatingDamageText:
category: Gameplay & Rules
default: false
description: Displays floating damage numbers overhead when inflicting damage on targets.
title: Show Floating Damage Text
type: boolean
ShowMapPlayerLocation:
category: Gameplay & Rules
default: true
description: Displays the player's current position pin on the in-game map.
title: Show Player On Map
type: boolean
bDisableStructurePlacementCollision:
category: Gameplay & Rules
default: false
description: Removes terrain and building clipping restrictions, allowing structures to clip into world geometry.
title: Disable Structure Placement Collision
type: boolean
required: []
type: object
configFilePath: ShooterGame/Saved/Config/WindowsServer/GameUserSettings.ini
configFileFormat: STANDARD
configFormatOptions:
assignment: =
falseValue: "False"
floatKeys: []
footer: null
header: '[ServerSettings]'
quoteStrings: false
separator: ""
trueValue: "True"
unquotedKeys: []
uppercaseKeys: false
agnosticCommandConfig:
actions:
Ban:
command: BanPlayer {target}
passwordKey: ServerAdminPassword
portKey: RCONPort
type: RCON
Broadcast:
command: Broadcast {message}
passwordKey: ServerAdminPassword
portKey: RCONPort
type: RCON
Kick:
command: KickPlayer {target}
passwordKey: ServerAdminPassword
portKey: RCONPort
type: RCON
Save:
command: SaveWorld
passwordKey: ServerAdminPassword
portKey: RCONPort
type: RCON
pingPort: null
pingPortKey: null
playerJoinRegex: (?:^.*?:\s+)?(.+?)\s+(?:has\s+)?joined this [Aa][Rr][Kk]!?
playerLeaveRegex: (?:^.*?:\s+)?(.+?)\s+(?:has\s+)?left this [Aa][Rr][Kk]!?
playersCommand: ListPlayers
playersFormat: REGEX
playersRegex: ^\d+\.\s+([^,]+)
queryPortKey: null
queryType: RCON
rconPasswordKey: ServerAdminPassword
rconPortKey: RCONPort
restEndpoint: null
restPasswordKey: null
restPortKey: null
restUser: null
logFilePath: ShooterGame/Saved/Logs/ShooterGame.log
backupPaths:
- ShooterGame/Saved
maxBackupSizeMb: 4096
maxPlayersConfigKey: MaxPlayers
mapConfigKey: ServerMap
aiCoverPrompt: A cinematic, photorealistic vista of a primeval tropical island built in Unreal Engine 5, featuring lush ancient rainforests, colossal waterfalls pouring into azure lagoons, and futuristic floating obelisks beaming energy into the sky. A massive Tyrannosaurus Rex roars on a cliffside overlooking prehistoric valleys while Pteranodons glide across a vivid sunset horizon.
@@ -0,0 +1,3 @@
# yaml-language-server: $schema=../../schema/test.schema.json
# Values CI uses to boot-test this game. Never put real credentials here: map them under 'secrets'.
timeoutSec: 900
+387
View File
@@ -0,0 +1,387 @@
# yaml-language-server: $schema=../../schema/game.schema.json
id: minecraft-crossplay
name: Minecraft (Crossplay Java & Bedrock)
defaultDockerImage: itzg/minecraft-server:latest
requiredMemoryMb: 4096
requiredDiskMb: 8192
defaultPorts:
- 25565/tcp
- 19132/udp
- 19132/tcp
installMethod: NONE
installConfig:
configPatches:
- enabledWhen: '{config:XBOX_BROADCAST_ENABLED}'
format: YAML
path: plugins/Geyser-Spigot/extensions/mcxboxbroadcast/config.yml
set:
session.remote-address: '{config:XBOX_BROADCAST_REMOTE_ADDRESS}'
session.remote-port: '{config:XBOX_BROADCAST_REMOTE_PORT}'
files:
- enabledWhen: '{config:XBOX_BROADCAST_ENABLED}'
path: plugins/Geyser-Spigot/extensions/MCXboxBroadcastExtension.jar
url: '{config:XBOX_BROADCAST_DOWNLOAD_URL}'
defaultConfig:
ALLOW_FLIGHT: true
DIFFICULTY: easy
ENABLE_RCON: true
ENABLE_WHITELIST: false
ENFORCE_WHITELIST: false
EULA: false
HARDCORE: false
JVM_OPTS: -DgeyserTransport=nethernet -DgeyserAdvertiseAddresses={PUBLIC_IP}:{PUBLIC_PORT_19132}
MAX_PLAYERS: 20
MEMORY: 4G
MODE: survival
MOTD: GBRHosting - {SERVER_NAME}
ONLINE_MODE: true
PAPER_CHANNEL: default
PLUGINS: https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot,https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot,https://api.spiget.org/v2/resources/19254/download
PVP: true
RCON_PASSWORD: ""
RCON_PORT: 25575
SERVER_PORT: 25565
TYPE: PAPER
USE_AIKAR_FLAGS: true
VERSION: LATEST
XBOX_BROADCAST_DOWNLOAD_URL: https://github.com/MCXboxBroadcast/Broadcaster/releases/download/159/MCXboxBroadcastExtension.jar
XBOX_BROADCAST_ENABLED: true
XBOX_BROADCAST_REMOTE_ADDRESS: '{PUBLIC_HOST}'
XBOX_BROADCAST_REMOTE_PORT: '{PUBLIC_PORT_19132}'
configSchema:
$schema: http://json-schema.org/draft-07/schema#
properties:
ALLOW_FLIGHT:
category: Gameplay & Rules
default: true
description: Required for Bedrock and Geyser crossplay compatibility to prevent phantom kick events.
title: Allow Flight
type: boolean
DIFFICULTY:
category: Gameplay & Rules
default: easy
description: The world difficulty level.
enum:
- peaceful
- easy
- normal
- hard
title: Difficulty
type: string
ENABLE_RCON:
category: Security & Access
default: true
description: Enables remote console (RCON) access for GBR action buttons and player moderation.
title: Enable RCON
type: boolean
ENABLE_WHITELIST:
category: Security & Access
default: false
description: When enabled, only players listed in the whitelist are permitted to join.
title: Enable Whitelist
type: boolean
ENFORCE_WHITELIST:
category: Security & Access
default: false
description: Enforces whitelist immediately upon server startup and reloading.
title: Enforce Whitelist
type: boolean
EULA:
category: System & General
default: false
description: Minecraft requires every server owner to accept Mojang's End User License Agreement. The server will not start without it.
showOnDeploy: true
title: Minecraft EULA
type: boolean
x-consent:
label: I have read and agree to the Minecraft End User License Agreement (EULA)
linkText: Read the Minecraft EULA
url: https://aka.ms/MinecraftEULA
HARDCORE:
category: Gameplay & Rules
default: false
description: Players are permanently switched to spectator mode upon death.
title: Hardcore Mode
type: boolean
JVM_OPTS:
category: System & General
default: -DgeyserTransport=nethernet -DgeyserAdvertiseAddresses={PUBLIC_IP}:{PUBLIC_PORT_19132}
description: Extra JVM flags. Enables Geyser NetherNet (required for Bedrock 26.60+, Oct 27 2026). {PUBLIC_IP} and {PUBLIC_PORT_19132} are filled in by GBR with the address players reach (relay, dedicated IP or node).
title: JVM Options
type: string
MAX_PLAYERS:
category: System & General
default: 20
description: The maximum number of concurrent players allowed on the server.
title: Max Players
type: integer
MEMORY:
category: System & General
default: 4G
description: Maximum heap memory allocated to the Java process (e.g. 4G, 6G, 8G).
title: Memory Allocation
type: string
MODE:
category: Gameplay & Rules
default: survival
description: Default game mode for players.
enum:
- survival
- creative
- adventure
- spectator
title: Game Mode
type: string
MOTD:
category: System & General
default: GBRHosting - {SERVER_NAME}
description: Server name shown in the Java server list and to Bedrock/console friends. Defaults to "GBRHosting - <your server name>"; type anything to change it.
title: Message of the Day
type: string
ONLINE_MODE:
category: Security & Access
default: true
description: Validates Java accounts with Mojang. Floodgate handles Bedrock account authentication automatically.
title: Online Mode
type: boolean
PAPER_CHANNEL:
category: System & General
default: default
description: Keep set to 'default' for rock-solid stability with Geyser crossplay. Use 'experimental' only for test builds.
enum:
- default
- experimental
title: Paper Release Channel
type: string
PLUGINS:
category: System & General
default: https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot,https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot,https://api.spiget.org/v2/resources/19254/download
description: Download URLs for Geyser, Floodgate, and ViaVersion for permanent crossplay compatibility.
title: Plugins List / URLs
type: string
PVP:
category: Gameplay & Rules
default: true
description: Allows players to attack and deal damage to one another.
title: Enable PvP
type: boolean
RCON_PASSWORD:
category: Security & Access
default: ""
description: Password GBR uses for RCON actions. RCON is only reachable from the host node. Leave blank and GBR generates one for your server.
title: RCON Password
type: string
x-generate:
type: password
replace:
- minecraft
RCON_PORT:
category: Security & Access
default: 25575
description: TCP port for remote console. Only reachable from the host node (not published publicly); GBR uses it for actions and player moderation.
title: RCON Port
type: integer
SERVER_PORT:
category: System & General
default: 25565
description: The TCP network port on which Java Edition Minecraft players connect.
title: Java Server Port
type: integer
TYPE:
category: System & General
default: PAPER
description: The Minecraft server distribution to run. PAPER provides high performance and plugin support.
title: Server Software Type
type: string
USE_AIKAR_FLAGS:
category: System & General
default: true
description: Applies tuned JVM garbage collection flags designed to reduce lag spikes on Paper servers.
title: Use Aikar's Flags
type: boolean
VERSION:
category: System & General
default: LATEST
description: The version of Minecraft to run. With ViaVersion installed, newer clients can always connect even if the server is on the stable release.
title: Minecraft Version
type: string
XBOX_BROADCAST_DOWNLOAD_URL:
category: Crossplay & Friends Broadcast
default: https://github.com/MCXboxBroadcast/Broadcaster/releases/download/159/MCXboxBroadcastExtension.jar
description: Pinned extension build. Update this URL to upgrade (or point it at your own mirror).
title: MCXboxBroadcast Extension URL
type: string
XBOX_BROADCAST_ENABLED:
category: Crossplay & Friends Broadcast
default: true
description: Shows this server in Xbox/PlayStation/Switch friends lists via a spare Microsoft account. Unofficial and not affiliated with Microsoft or Mojang; use a spare account. On first start, sign in with the code shown on the server's Overview page.
title: Friends Broadcast (MCXboxBroadcast)
type: boolean
XBOX_BROADCAST_REMOTE_ADDRESS:
category: Crossplay & Friends Broadcast
default: '{PUBLIC_HOST}'
description: Address friends are sent to when they join. {PUBLIC_HOST} is filled in with this server's relay/public address. Never leave this as 'auto' behind the relay (it would expose the node's home IP).
title: Broadcast Join Address
type: string
XBOX_BROADCAST_REMOTE_PORT:
category: Crossplay & Friends Broadcast
default: '{PUBLIC_PORT_19132}'
description: Bedrock port friends are sent to. {PUBLIC_PORT_19132} is filled in with the public Bedrock port.
title: Broadcast Join Port
type: string
required:
- EULA
type: object
configFileFormat: INI
configFormatOptions:
assignment: =
falseValue: "false"
footer: ""
header: ""
quoteStrings: false
separator: ""
trueValue: "true"
unquotedKeys: []
uppercaseKeys: false
agnosticCommandConfig:
actions:
Ban:
command: ban {target}
passwordKey: RCON_PASSWORD
portKey: RCON_PORT
type: RCON
Broadcast:
command: say {message}
passwordKey: RCON_PASSWORD
portKey: RCON_PORT
type: RCON
Kick:
command: kick {target}
passwordKey: RCON_PASSWORD
portKey: RCON_PORT
type: RCON
RefreshBroadcastSignIn:
command: mcxboxbroadcast restart
type: STDIN
Save:
command: save-all
passwordKey: RCON_PASSWORD
portKey: RCON_PORT
type: RCON
connectedAccountsConfig:
authType: MINECRAFT_BEDROCK
authUrl: https://www.microsoft.com/link
buttonLabel: Connect Account
clientId: "0000000048183522"
defaultPort: 19132
description: Hook spare Microsoft/Xbox accounts to keep your server visible in friends' tabs on Xbox, PlayStation, and Nintendo Switch 24/7.
deviceCodeUrl: https://login.live.com/oauth20_connect.srf
dynamicVariables:
- refreshMinutes: 360
select:
releaseType: release
type: HTTP_JSON
url: https://raw.githubusercontent.com/PrismarineJS/minecraft-data/master/data/bedrock/common/protocolVersions.json
vars:
BEDROCK_PROTOCOL: version
BEDROCK_VERSION: minecraftVersion
enabled: false
gameVersion: '{BEDROCK_VERSION}'
maxAccounts: 5
mpsdProperties:
BroadcastSetting: 3
CrossPlayDisabled: false
Joinability: joinable_by_friends
LanGame: false
MaxMemberCount: '{config:MAX_PLAYERS}'
MemberCount: 1
OnlineCrossPlatformGame: true
SupportedConnections:
- ConnectionType: 6
HostIpAddress: '{SERVER_HOST}'
HostPort: '{SERVER_PORT}'
RakNetGUID: ""
TitleId: 0
TransportLayer: 2
hostName: '{SERVER_HOST}'
isEditorWorld: false
isHardcore: '{config:HARDCORE}'
levelId: level
ownerId: '{XUID}'
protocol: '{BEDROCK_PROTOCOL}'
rakNetGUID: '{RAKNET_GUID}'
version: '{BEDROCK_VERSION}'
worldName: '{config:MOTD}'
worldType: Survival
provider: MICROSOFT_XBOX
providerLabel: Xbox / Microsoft Gamertag
rtaConnection: true
scope: service::user.auth.xboxlive.com::MBI_SSL
serviceConfigId: 4fc10100-5f7a-4470-899b-280835760c07
sessionTemplateName: MinecraftLobby
title: Crossplay Friends Broadcast
titleId: "1739947436"
tokenUrl: https://login.live.com/oauth20_token.srf
connectionGuides:
- actionText: Link Account
actionUrl: https://www.microsoft.com/link
badge: Crossplay
id: console
steps:
- Add the broadcast account (shown on the server's Overview page after sign-in) as a friend on your console or in the Xbox app.
- Open Minecraft and go to Play → Friends.
- Under 'Joinable Friends', select the server to join.
title: Console (Xbox, PS, Switch)
- actionText: 1-Click Connect
actionUrl: minecraft://?addExternalServer={SERVER_NAME}|{CONNECTION_HOST}:{BEDROCK_PORT}
id: bedrock-direct
steps:
- Open Minecraft (Bedrock Edition) -> Play -> Servers -> Add Server.
- 'Server Name: {SERVER_NAME}'
- 'Server Address: {CONNECTION_HOST}'
- 'Port: {BEDROCK_PORT}'
title: Bedrock (Mobile, Win10)
- id: java-direct
steps:
- Open Minecraft (Java Edition) -> Multiplayer -> Add Server.
- 'Server Address: {CONNECTION_HOST}:{PORT}'
title: Java Edition (PC, Mac)
consoleSignIn:
codePattern: open the page\s+(https://\S+)\s+and enter the code\s+([A-Z0-9-]+)
codeTtlMinutes: 5
description: Shows this server in Xbox, PlayStation and Switch friends lists using a spare Microsoft account. Unofficial - not affiliated with Microsoft or Mojang.
enabledConfigKey: XBOX_BROADCAST_ENABLED
failurePattern: Failed to get/refresh auth token
refreshAction: RefreshBroadcastSignIn
signInHint: Sign in with a SPARE Microsoft account, never your main one. Enter the code within 5 minutes.
signedInHint: Add this account as a friend on your console or in the Xbox app, then join from Play → Friends.
successPattern: Successfully authenticated as (.+?) \((\d+)\)
title: Crossplay Friends Broadcast
deviceCodePattern: open the page\s+(https://\S+)\s+and enter the code\s+([A-Z0-9-]+)
deviceCodeTitle: Friends Broadcast sign-in required
joinButtonLabel: How to Join
joinModalTitle: How to Join This Server
pingPort: 25565
pingPortKey: SERVER_PORT
playerJoinRegex: :\s+([a-zA-Z0-9_.*]+) joined the game
playerLeaveRegex: :\s+([a-zA-Z0-9_.*]+) left the game
playersCommand: null
playersFormat: null
playersRegex: null
queryPortKey: null
queryType: MINECRAFT_PING
rconPasswordKey: RCON_PASSWORD
rconPortKey: RCON_PORT
restEndpoint: null
restPasswordKey: null
restPortKey: null
restUser: null
backupPaths:
- world
- world_nether
- world_the_end
- plugins
- config
- server.properties
maxBackupSizeMb: 8192
maxPlayersConfigKey: MAX_PLAYERS
+5
View File
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=../../schema/test.schema.json
# Values CI uses to boot-test this game. Never put real credentials here: map them under 'secrets'.
config:
EULA: true
timeoutSec: 900
+562
View File
@@ -0,0 +1,562 @@
# yaml-language-server: $schema=../../schema/game.schema.json
id: palworld
name: Palworld
defaultDockerImage: cm2network/steamcmd
defaultStartupCommand: ./PalServer.sh -useperfthreads -NoAsyncLoadingThread -UseMultithreadForDS -publiclobby
requiredMemoryMb: 8000
requiredDiskMb: 20000
defaultPorts:
- 8211:8211/udp
installMethod: STEAMCMD
installConfig:
appId: "2394010"
defaultConfig:
AdminPassword: ""
AllowConnectPlatform: Xbox,Steam
AutoResetGuildTimeNoOnlinePlayers: "2160.000000"
BanListURL: https://api.palworldgame.com/api/banlist.txt
BaseCampMaxNum: 128
BaseCampMaxNumInGuild: 10
BaseCampWorkerMaxNum: 30
BuildObjectDamageRate: "1.000000"
BuildObjectDeteriorationDamageRate: "1.000000"
CollectionDropRate: "1.000000"
CollectionObjectHpRate: "1.000000"
CollectionObjectRespawnSpeedRate: "1.000000"
CoopPlayerMaxNum: 4
CrossplayPlatforms: Xbox,Steam
DayTimeSpeedRate: "1.000000"
DeathPenalty: All
Difficulty: None
DropItemAliveMaxHours: "1.000000"
DropItemMaxNum: 3000
DropItemMaxNum_UNKO: 100
EnemyDropItemRate: "1.000000"
ExpRate: "1.000000"
GuildPlayerMaxNum: 20
LogFormatType: Text
NightTimeSpeedRate: "1.000000"
PalAutoHPRegeneRate: "1.000000"
PalAutoHpRegeneRateInSleep: "1.000000"
PalCaptureRate: "1.000000"
PalDamageRateAttack: "1.000000"
PalDamageRateDefense: "1.000000"
PalEggDefaultHatchingTime: "3.000000"
PalSpawnNumRate: "1.000000"
PalStaminaDecreaceRate: "1.000000"
PalStomachDecreaceRate: "1.000000"
PlayerAutoHPRegeneRate: "1.000000"
PlayerAutoHpRegeneRateInSleep: "1.000000"
PlayerDamageRateAttack: "1.000000"
PlayerDamageRateDefense: "1.000000"
PlayerStaminaDecreaceRate: "1.000000"
PlayerStomachDecreaceRate: "1.000000"
PublicIP: ""
PublicPort: 8211
RCONEnabled: true
RCONPort: 25575
RESTAPIEnabled: true
RESTAPIPort: 8212
Region: ""
ServerDescription: Powered by GBR Hosting
ServerName: GBRHosting - {SERVER_NAME}
ServerPassword: ""
ServerPlayerMaxNum: 32
SupplyDropSpan: 180
WorkSpeedRate: "1.000000"
bActiveUNKO: false
bAllowGlobalPalboxExport: true
bAllowGlobalPalboxImport: true
bAutoResetGuildNoOnlinePlayers: false
bCanPickupOtherGuildDeathPenaltyDrop: false
bEnableAimAssistKeyboard: false
bEnableAimAssistPad: true
bEnableDefenseOtherGuildPlayer: false
bEnableFastTravel: true
bEnableFriendlyFire: false
bEnableInvaderEnemy: true
bEnableNonLoginPenalty: false
bEnablePlayerToPlayerDamage: false
bExistPlayerAfterLogout: false
bIsMultiplay: true
bIsPvP: false
bIsStartLocationSelectByMap: true
bIsUseBackupSaveData: true
bShowPlayerList: true
bUseAuth: true
configSchema:
properties:
AdminPassword:
default: ""
description: Password for in-game admin (/AdminPassword) and for GBR actions (kick, ban, save, metrics via the REST API). Leave blank and GBR generates an easy one for your server.
showOnDeploy: true
title: Admin Password
type: string
x-savedValue:
key: GAME_ADMIN_PASSWORD
label: Game admin password
secret: true
x-generate:
type: password
replace:
- Admin6!
AllowConnectPlatform:
default: Xbox,Steam
description: Platforms permitted to connect to this server.
enum:
- Steam
- Xbox
- None
- Xbox,Steam
title: Allowed Platforms
type: string
AutoResetGuildTimeNoOnlinePlayers:
default: "2160.000000"
description: Hours of inactivity before an empty guild is deleted (2160.0 = 90 days).
title: Guild Inactivity Disband Hours
type: string
BaseCampMaxNum:
default: 128
description: Total base camps permitted across the entire server.
title: Max Base Camps Worldwide
type: integer
BaseCampMaxNumInGuild:
default: 10
description: Maximum base camps a single guild is allowed to construct.
title: Max Bases Per Guild
type: integer
BaseCampWorkerMaxNum:
default: 30
description: Maximum number of active Pals assigned to work in each base camp.
title: Max Working Pals Per Base
type: integer
BuildObjectDamageRate:
default: "1.000000"
description: Multiplier for damage taken by built structures.
title: Structure Damage Multiplier
type: string
BuildObjectDeteriorationDamageRate:
default: "1.000000"
description: Decay damage applied to structures outside base boundaries (0.0 to disable decay).
title: Structure Decay Rate
type: string
CollectionDropRate:
default: "1.000000"
description: Multiplier for materials gathered from trees, rocks, and ore nodes.
title: Resource Gathering Yield
type: string
CollectionObjectHpRate:
default: "1.000000"
description: Health multiplier of gatherable trees and rocks.
title: Resource Node Durability
type: string
CollectionObjectRespawnSpeedRate:
default: "1.000000"
description: Speed at which mined trees and ore deposits reappear.
title: Resource Respawn Speed
type: string
CrossplayPlatforms:
default: Xbox,Steam
description: Platforms enabled for crossplay connectivity.
enum:
- Steam
- Xbox
- None
- Xbox,Steam
showOnDeploy: true
title: Crossplay Platforms
type: string
DayTimeSpeedRate:
default: "1.000000"
description: Multiplier for daylight progression speed.
title: Daytime Speed Multiplier
type: string
DeathPenalty:
default: All
description: 'Items dropped upon death: None, Item (materials only), ItemAndEquipment, or All.'
enum:
- None
- Item
- ItemAndEquipment
- All
title: Death Penalty
type: string
Difficulty:
default: None
description: Base difficulty preset (None recommended when using custom multipliers).
enum:
- None
- Easy
- Normal
- Hard
title: Difficulty Preset
type: string
DropItemAliveMaxHours:
default: "1.000000"
description: Hours before dropped items on the ground disappear.
title: Dropped Item Despawn Time (Hours)
type: string
EnemyDropItemRate:
default: "1.000000"
description: Quantity multiplier for items dropped by defeated Pals and bosses.
title: Enemy Item Drop Rate
type: string
ExpRate:
default: "1.000000"
description: Multiplier for player and Pal XP gained from all sources.
title: Experience Multiplier
type: string
GuildPlayerMaxNum:
default: 20
description: Maximum player members per guild.
title: Max Players Per Guild
type: integer
NightTimeSpeedRate:
default: "1.000000"
description: Multiplier for nighttime progression speed.
title: Nighttime Speed Multiplier
type: string
PalCaptureRate:
default: "1.000000"
description: Multiplier for successful Pal capture chances with Pal Spheres.
title: Pal Capture Rate Multiplier
type: string
PalDamageRateAttack:
default: "1.000000"
description: Multiplier for damage dealt by Pals.
title: Pal Attack Multiplier
type: string
PalDamageRateDefense:
default: "1.000000"
description: Multiplier for damage taken by Pals.
title: Pal Defense Multiplier
type: string
PalEggDefaultHatchingTime:
default: "3.000000"
description: Time in hours for huge eggs to incubate (e.g. 72.0 default, 1.0 to 3.0 for fast hatching).
title: Egg Hatching Time (Hours)
type: string
PalSpawnNumRate:
default: "1.000000"
description: Multiplier for the number of wild Pals that spawn in the world.
title: Pal Spawn Density
type: string
PalStaminaDecreaceRate:
default: "1.000000"
description: Rate at which Pal stamina drains while working or riding.
title: Pal Stamina Drain
type: string
PalStomachDecreaceRate:
default: "1.000000"
description: Rate at which Pal hunger drains.
title: Pal Hunger Rate
type: string
PlayerDamageRateAttack:
default: "1.000000"
description: Multiplier for damage dealt by players.
title: Player Attack Multiplier
type: string
PlayerDamageRateDefense:
default: "1.000000"
description: Multiplier for damage taken by players (lower = tankier).
title: Player Defense Multiplier
type: string
PlayerStaminaDecreaceRate:
default: "1.000000"
description: Rate at which player stamina depletes (lower = more stamina).
title: Player Stamina Drain
type: string
PlayerStomachDecreaceRate:
default: "1.000000"
description: Rate at which player hunger depletes (lower = less hungry).
title: Player Hunger Rate
type: string
PublicPort:
default: 8211
description: UDP game port clients connect to.
title: Public Game Port
type: integer
RCONEnabled:
default: true
description: Enables Remote Console administration port.
title: RCON Enabled
type: boolean
RCONPort:
default: 25575
description: Port used for RCON connections.
title: RCON Port
type: integer
RESTAPIEnabled:
default: true
description: Enables Palworld's built-in HTTP REST API for dashboards and metrics.
title: REST API Enabled
type: boolean
RESTAPIPort:
default: 8212
description: Port used for HTTP REST API access.
title: REST API Port
type: integer
ServerDescription:
default: Powered by GBR Hosting
description: Description displayed to players when viewing server details.
title: Server Description
type: string
ServerName:
default: GBRHosting - {SERVER_NAME}
description: Name shown in the in-game server browser. Defaults to "GBRHosting - <your server name>".
showOnDeploy: true
title: Server Name
type: string
ServerPassword:
default: ""
description: Password required for players to connect.
showOnDeploy: true
title: Server Password
type: string
x-savedValue:
key: GAME_JOIN_PASSWORD
label: Game join password
secret: true
ServerPlayerMaxNum:
default: 32
description: Maximum concurrent player connections.
title: Max Players
type: integer
SupplyDropSpan:
default: 180
description: Interval in minutes between meteorite and supply drop events (default 180).
title: Supply Drop Frequency (Minutes)
type: integer
WorkSpeedRate:
default: "1.000000"
description: Speed at which Pals craft, build, and farm inside bases.
title: Base Work Speed Multiplier
type: string
bAllowGlobalPalboxExport:
default: true
description: Allows players to export Pals to other worlds.
title: Allow Palbox Export
type: boolean
bAllowGlobalPalboxImport:
default: true
description: Allows players to import Pals from other worlds.
title: Allow Palbox Import
type: boolean
bAutoResetGuildNoOnlinePlayers:
default: false
description: Disbands guilds when all members remain offline past timeout.
title: Auto-Disband Inactive Guilds
type: boolean
bCanPickupOtherGuildDeathPenaltyDrop:
default: false
description: Allows players from other guilds to pick up items dropped on death.
title: Loot Other Guild Death Drops
type: boolean
bEnableFastTravel:
default: true
description: Allows fast traveling between unlocked Great Eagle statues.
title: Enable Fast Travel
type: boolean
bEnableFriendlyFire:
default: false
description: Allows players in the same guild to damage each other.
title: Enable Friendly Fire
type: boolean
bEnableInvaderEnemy:
default: true
description: Enables enemy NPCs and wild Pal raids attacking player bases.
title: Enable Raids
type: boolean
bIsPvP:
default: false
description: Enables combat and damage between opposing players.
title: Enable PvP
type: boolean
bIsStartLocationSelectByMap:
default: true
description: Allows players to choose their respawn location from the map.
title: Select Respawn Location By Map
type: boolean
bShowPlayerList:
default: true
description: Displays connected players in the server player list.
title: Show Player List
type: boolean
bUseAuth:
default: true
description: Enforces valid Steam account authentication upon connection.
title: Require Steam Authentication
type: boolean
type: object
configFilePath: Pal/Saved/Config/LinuxServer/PalWorldSettings.ini
configFileFormat: STANDARD
configFormatOptions:
assignment: =
falseValue: "False"
footer: )
header: |-
[/Script/Pal.PalGameWorldSettings]
OptionSettings=(
quoteStrings: true
separator: ','
trueValue: "True"
unquotedKeys:
- Difficulty
- RandomizerType
- DeathPenalty
- CrossplayPlatforms
- AllowConnectPlatform
- LogFormatType
- DenyTechnologyList
- DayTimeSpeedRate
- NightTimeSpeedRate
- ExpRate
- PalCaptureRate
- PalSpawnNumRate
- PalDamageRateAttack
- PalDamageRateDefense
- PlayerDamageRateAttack
- PlayerDamageRateDefense
- PlayerStomachDecreaceRate
- PlayerStaminaDecreaceRate
- PlayerAutoHPRegeneRate
- PlayerAutoHpRegeneRateInSleep
- PalStomachDecreaceRate
- PalStaminaDecreaceRate
- PalAutoHPRegeneRate
- PalAutoHpRegeneRateInSleep
- BuildObjectHpRate
- BuildObjectDamageRate
- BuildObjectDeteriorationDamageRate
- CollectionDropRate
- CollectionObjectHpRate
- CollectionObjectRespawnSpeedRate
- EnemyDropItemRate
- DropItemAliveMaxHours
- AutoResetGuildTimeNoOnlinePlayers
- PalEggDefaultHatchingTime
- WorkSpeedRate
- AutoSaveSpan
- ItemWeightRate
- ServerReplicatePawnCullDistance
- EquipmentDurabilityDamageRate
- ItemContainerForceMarkDirtyInterval
- PlayerDataPalStorageUpdateCheckTickInterval
- ItemCorruptionMultiplier
- MonsterFarmActionSpeedRate
- AutoTransferMasterCheckIntervalSeconds
- BlockRespawnTime
- RespawnPenaltyDurationThreshold
- RespawnPenaltyTimeScale
- VoiceChatMaxVolumeDistance
- VoiceChatZeroVolumeDistance
uppercaseKeys: false
agnosticCommandConfig:
actions:
Ban:
body:
message: '{reason}'
userid: '{target}'
endpoint: /v1/api/ban
passwordKey: AdminPassword
portKey: RESTAPIPort
type: REST_POST
user: admin
Broadcast:
body:
message: '{message}'
endpoint: /v1/api/announce
passwordKey: AdminPassword
portKey: RESTAPIPort
type: REST_POST
user: admin
Kick:
body:
message: '{reason}'
userid: '{target}'
endpoint: /v1/api/kick
passwordKey: AdminPassword
portKey: RESTAPIPort
type: REST_POST
user: admin
Save:
body: {}
endpoint: /v1/api/save
passwordKey: AdminPassword
portKey: RESTAPIPort
type: REST_POST
user: admin
Shutdown:
body:
message: '{message}'
waittime: 60
endpoint: /v1/api/shutdown
passwordKey: AdminPassword
portKey: RESTAPIPort
type: REST_POST
user: admin
chatRegex: \[CHAT\] <(.*?)> (.*)
commandMap:
Ban: BanPlayer {target}
Broadcast: Broadcast {message}
Kick: KickPlayer {target}
Save: Save
Shutdown: DoExit
metricsConfig:
endpoint: /v1/api/metrics
fields:
- decimals: 1
key: serverfps
label: Server Tickrate
suffix: ' FPS'
- decimals: 1
key: serverframetime
label: Frame Time
suffix: ' ms'
- key: currentplayernum
label: Active Players
- key: maxplayernum
label: Max Capacity
- key: days
label: World Day
- key: basecampnum
label: Base Camps
- format: duration
key: uptime
label: Uptime
passwordKey: AdminPassword
portKey: RESTAPIPort
type: REST_API
user: admin
playerConfig:
actions:
- destructive: false
name: Kick
title: Kick Player
- destructive: true
name: Ban
title: Ban Player
fields:
- key: level
prefix: 'Lvl '
- decimals: 0
key: ping
suffix: ms
- decimals: 0
key: location_x
label: X
- decimals: 0
key: location_y
label: "Y"
queryType: REST_API
restEndpoint: /v1/api/players
restPasswordKey: AdminPassword
restPortKey: RESTAPIPort
restUser: admin
backupPaths:
- Pal/Saved/SaveGames/*
- Pal/Saved/Config/LinuxServer/*
- Pal/Saved/Config/WindowsServer/*
maxBackupSizeMb: 5000
publicIpConfigKey: PublicIP
maxPlayersConfigKey: ServerPlayerMaxNum
+3
View File
@@ -0,0 +1,3 @@
# yaml-language-server: $schema=../../schema/test.schema.json
# Values CI uses to boot-test this game. Never put real credentials here: map them under 'secrets'.
timeoutSec: 2400
@@ -0,0 +1,117 @@
# yaml-language-server: $schema=../../schema/game.schema.json
id: runescape-dragonwilds-native-linux
name: 'RuneScape: Dragonwilds (Native Linux Server)'
defaultDockerImage: cm2network/steamcmd:root
defaultStartupCommand: ./RSDragonwildsServer.sh -log -Port=7777
requiredMemoryMb: 10240
requiredDiskMb: 20480
defaultPorts:
- 7777/udp
- 8888/udp
installMethod: STEAMCMD
installConfig:
appId: "4019830"
defaultConfig:
AdminPassword: ""
DefaultWorldName: '{SERVER_NAME}'
OwnerId: ""
PlatformPolicy: Crossplay
ServerName: GBRHosting - {SERVER_NAME}
WorldPassword: ""
configSchema:
$schema: http://json-schema.org/draft-07/schema#
properties:
AdminPassword:
category: Security & Access
default: ""
description: Password required to access the Server Management screen in-game.
showOnDeploy: true
title: Admin Password
type: string
x-savedValue:
key: GAME_ADMIN_PASSWORD
label: Game admin password
secret: true
DefaultWorldName:
category: World & Environment
default: '{SERVER_NAME}'
description: Players find your server in Dragonwilds under Worlds → Public by searching this name. Defaults to your server's name in GBR; type any short name to change it.
showOnDeploy: true
title: World Name (what players search for)
type: string
OwnerId:
category: Security & Access
default: ""
description: 'Your RuneScape: DragonWilds Player ID (bottom of in-game Settings). Required for server to boot.'
showOnDeploy: true
title: Owner Player ID
type: string
x-savedValue:
key: DRAGONWILDS_PLAYER_ID
label: Dragonwilds Player ID
PlatformPolicy:
category: Security & Access
default: Crossplay
description: Controls platform authorization and crossplay access policies.
enum:
- Crossplay
- PC
- PlayStation
- Xbox
- Nintendo
title: Platform Policy
type: string
ServerName:
category: System & General
default: GBRHosting - {SERVER_NAME}
description: Display name of the dedicated server. Defaults to "GBRHosting - <your server name>".
showOnDeploy: true
title: Server Name
type: string
WorldPassword:
category: Security & Access
default: ""
description: Optional password for players to join. Leave empty for public access.
showOnDeploy: true
title: World Password
type: string
x-savedValue:
key: GAME_JOIN_PASSWORD
label: Game join password
secret: true
required:
- OwnerId
- AdminPassword
type: object
configFilePath: RSDragonwilds/Saved/Config/LinuxServer/DedicatedServer.ini
configFileFormat: STANDARD
configFormatOptions:
assignment: =
falseValue: "False"
footer: ""
header: |
[/Script/Dominion.DedicatedServerSettings]
quoteStrings: false
separator: ""
trueValue: "True"
uppercaseKeys: false
agnosticCommandConfig:
actions:
Ban:
type: UNSUPPORTED
Broadcast:
type: UNSUPPORTED
Kick:
type: UNSUPPORTED
Save:
type: UNSUPPORTED
playerJoinRegex: 'LogNet: Join succeeded: ([^\r\n]+)'
playerLeaveRegex: 'LogNet: UNetConnection::.*Player(?: name)?:\s*([^,\r\n]+)'
queryType: LOG_ONLY
logFilePath: RSDragonwilds/Saved/Logs/RSDragonwilds.log
backupPaths:
- RSDragonwilds/Saved
maxBackupSizeMb: 5000
publicIpConfigKey: MULTIHOME
maxPlayersConfigKey: MaxPlayers
aiCoverPrompt: 'A cinematic wide shot of Ashenfall in the fantasy world of Gielinor from RuneScape: Dragonwilds. Ancient stone spires and forgotten fortresses rise amidst untamed wilderness. Colossal ancient dragons circle through stormy twilight skies illuminated by magical embers, while adventurers gather around a runic encampment wielding enchanted sorcery and survival gear.'
@@ -0,0 +1,3 @@
# yaml-language-server: $schema=../../schema/test.schema.json
# Values CI uses to boot-test this game. Never put real credentials here: map them under 'secrets'.
timeoutSec: 2400
+190
View File
@@ -0,0 +1,190 @@
# yaml-language-server: $schema=../../schema/game.schema.json
id: satisfactory-vanilla-stable
name: Satisfactory (Vanilla Stable)
defaultDockerImage: wolveix/satisfactory-server:latest
requiredMemoryMb: 8192
requiredDiskMb: 16384
defaultPorts:
- 7777/tcp
- 7777/udp
- 8888/tcp
installMethod: NONE
defaultConfig:
AUTOSAVENUM: 5
DEBUG: false
DISABLESEASONALEVENTS: false
LOG: false
MAXOBJECTS: 2162688
MAXPLAYERS: 4
MAXTICKRATE: 30
MULTIHOME: '::'
PGID: 1000
PUID: 1000
SERVERGAMEPORT: 7777
SERVERMESSAGINGPORT: 8888
SERVERSTREAMING: true
SKIPUPDATE: false
STEAMBETA: false
STEAMBETAID: ""
STEAMBETAKEY: ""
TIMEOUT: 30
VMOVERRIDE: false
configSchema:
$schema: http://json-schema.org/draft-07/schema#
properties:
AUTOSAVENUM:
category: World & Environment
default: 5
description: The number of rotating autosave files to keep in the save folder.
title: Autosave Rotation Count
type: integer
DEBUG:
category: System & General
default: false
description: Prints diagnostic environment and system details on startup, then stops.
title: Debug Mode
type: boolean
DISABLESEASONALEVENTS:
category: Gameplay & Rules
default: false
description: Disables seasonal in-game events such as FICSMAS holiday events.
title: Disable Seasonal Events
type: boolean
LOG:
category: System & General
default: false
description: Disables automatic pruning of previous Satisfactory server log files on container startup.
title: Retain Old Logs
type: boolean
MAXOBJECTS:
category: World & Environment
default: 2162688
description: Unreal Engine garbage collector UObject limit to support large late-game factories.
title: Max Objects Limit
type: integer
MAXPLAYERS:
category: System & General
default: 4
description: Sets the maximum number of concurrent players allowed on the server.
title: Max Players
type: integer
MAXTICKRATE:
category: System & General
default: 30
description: Sets the maximum simulation tick rate for the server in Hz.
title: Max Tick Rate
type: integer
MULTIHOME:
category: System & General
default: '::'
description: 'Network interface binding IP address (defaults to :: for dual-stack IPv4/IPv6).'
title: Multihome Address
type: string
PGID:
category: System & General
default: 1000
description: Sets the Linux group ID under which the dedicated server process runs.
title: Process Group ID
type: integer
PUID:
category: System & General
default: 1000
description: Sets the Linux user ID under which the dedicated server process runs.
title: Process User ID
type: integer
SERVERGAMEPORT:
category: System & General
default: 7777
description: Primary game port for UDP and TCP network communication.
title: Server Game Port
type: integer
SERVERMESSAGINGPORT:
category: System & General
default: 8888
description: Port used for reliable server messaging and beacon network traffic.
title: Server Messaging Port
type: integer
SERVERSTREAMING:
category: System & General
default: true
description: Toggles whether the game server utilizes Unreal Engine World Partition asset streaming.
title: Server Streaming
type: boolean
SKIPUPDATE:
category: System & General
default: false
description: Skips automatic SteamCMD game file update checks on container startup.
title: Skip Update
type: boolean
STEAMBETA:
category: System & General
default: false
description: When enabled, updates and runs the Experimental branch instead of the stable release.
title: Steam Beta Branch
type: boolean
STEAMBETAID:
category: System & General
default: ""
description: Specific beta branch identifier to download via SteamCMD.
title: Steam Beta Branch Name
type: string
STEAMBETAKEY:
category: Security & Access
default: ""
description: Password required to access a private Steam beta branch.
title: Steam Beta Password
type: string
TIMEOUT:
category: System & General
default: 30
description: Client network connection timeout threshold in seconds.
title: Connection Timeout
type: integer
VMOVERRIDE:
category: System & General
default: false
description: Skips CPU model checking on hypervisors to prevent crash warnings on KVM/QEMU hosts.
title: VM CPU Check Override
type: boolean
required: []
type: object
configFileFormat: INI
configFormatOptions:
assignment: =
falseValue: "false"
footer: ""
header: ""
quoteStrings: false
separator: ""
trueValue: "true"
unquotedKeys: []
uppercaseKeys: false
agnosticCommandConfig:
actions:
Ban:
type: UNSUPPORTED
Broadcast:
type: UNSUPPORTED
Kick:
type: UNSUPPORTED
Save:
type: UNSUPPORTED
pingPort: null
pingPortKey: null
playerJoinRegex: '.*Join succeeded: (\S+).*'
playerLeaveRegex: .*UNetConnection::Close:.*?\[PlayerName:\s*([^\]]+)\].*
playersCommand: null
playersFormat: null
playersRegex: null
queryPortKey: null
queryType: LOG_ONLY
rconPasswordKey: null
rconPortKey: null
restEndpoint: null
restPasswordKey: null
restPortKey: null
restUser: null
backupPaths:
- saved
maxBackupSizeMb: 1024
maxPlayersConfigKey: MAXPLAYERS
@@ -0,0 +1,3 @@
# yaml-language-server: $schema=../../schema/test.schema.json
# Values CI uses to boot-test this game. Never put real credentials here: map them under 'secrets'.
timeoutSec: 900
+10
View File
@@ -0,0 +1,10 @@
module www.gitea.gbreed.com/gbreed-public/gbr-games
go 1.24
require (
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3
gopkg.in/yaml.v3 v3.0.1
)
require golang.org/x/text v0.14.0 // indirect
+10
View File
@@ -0,0 +1,10 @@
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+79
View File
@@ -0,0 +1,79 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://www.gitea.gbreed.com/gbreed-public/gbr-games/raw/branch/main/schema/game.schema.json",
"title": "GBR Hosting game template",
"description": "One game.yaml per game. Field names match the control panel's Game entity. Business settings (enabled, paid/private hosting, cover art, pricing tiers) are managed in the panel, not here.",
"type": "object",
"additionalProperties": false,
"required": ["id", "name", "defaultDockerImage", "installMethod"],
"properties": {
"id": {
"description": "Stable identifier. Must match the folder name. Never rename: servers reference it.",
"type": "string",
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
"maxLength": 64
},
"name": { "description": "Display name shown to users.", "type": "string", "minLength": 1 },
"defaultDockerImage": { "description": "Image the game server runs in.", "type": "string", "minLength": 1 },
"defaultStartupCommand": { "description": "Command run inside the container. May use config placeholders.", "type": ["string", "null"] },
"requiredMemoryMb": { "type": ["integer", "null"], "minimum": 128 },
"requiredDiskMb": { "type": ["integer", "null"], "minimum": 128 },
"defaultPorts": {
"description": "Ports to expose, e.g. \"25565/tcp\", \"7777/udp\" or \"8211:8211/udp\".",
"type": ["array", "null"],
"items": { "type": "string", "pattern": "^([0-9]{1,5}:)?[0-9]{1,5}(-[0-9]{1,5})?(/(tcp|udp))?$" }
},
"installMethod": { "enum": ["STEAMCMD", "BASH_SCRIPT", "NONE"] },
"installConfig": {
"description": "STEAMCMD needs appId; BASH_SCRIPT needs script.",
"type": ["object", "null"]
},
"defaultConfig": {
"description": "Default values for every server. Users override these per server. Keys may only contain letters, digits, '_', '-' and '.' (the panel drops anything else).",
"type": ["object", "null"],
"propertyNames": { "pattern": "^[a-zA-Z0-9_.-]+$", "maxLength": 128 }
},
"configSchema": {
"description": "JSON Schema for the settings users can edit. A property with \"x-consent\" (e.g. an EULA) must be explicitly accepted on deploy.",
"type": ["object", "null"]
},
"configFilePath": { "description": "Where defaultConfig + user overrides are written, relative to the server root.", "type": ["string", "null"] },
"configFileFormat": {
"description": "INI writes key=value lines; STANDARD uses configFormatOptions (header, separator, quoting) for formats like Unreal's OptionSettings=(...).",
"enum": ["INI", "STANDARD", "JSON", "ENV", null]
},
"configFormatOptions": { "type": ["object", "null"] },
"agnosticCommandConfig": { "description": "How the panel sends console commands (save, broadcast, kick...).", "type": ["object", "null"] },
"clusterConfig": { "type": ["object", "null"] },
"logFilePath": { "type": ["string", "null"] },
"backupPaths": { "type": ["array", "null"], "items": { "type": "string" } },
"maxBackupSizeMb": { "type": ["integer", "null"], "minimum": 1 },
"publicIpConfigKey": { "description": "Config key that receives the server's public address.", "type": ["string", "null"] },
"maxPlayersConfigKey": { "description": "Config key locked to the pricing tier's player count.", "type": ["string", "null"] },
"mapConfigKey": { "type": ["string", "null"] },
"aiCoverPrompt": { "type": ["string", "null"] }
},
"allOf": [
{
"if": { "properties": { "installMethod": { "const": "STEAMCMD" } } },
"then": {
"required": ["installConfig"],
"properties": { "installConfig": { "type": "object", "required": ["appId"] } }
}
},
{
"if": { "properties": { "installMethod": { "const": "BASH_SCRIPT" } } },
"then": {
"required": ["installConfig"],
"properties": { "installConfig": { "type": "object", "required": ["script"] } }
}
}
]
}
+27
View File
@@ -0,0 +1,27 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://www.gitea.gbreed.com/gbreed-public/gbr-games/raw/branch/main/schema/test.schema.json",
"title": "GBR Hosting game boot-test fixture",
"description": "Values CI uses when boot-testing a template. Never put real credentials here: map them to a Gitea Actions secret under 'secrets'.",
"type": "object",
"additionalProperties": false,
"properties": {
"config": {
"description": "Config values for the test server, layered on top of defaultConfig (e.g. EULA: true).",
"type": "object",
"propertyNames": { "pattern": "^[a-zA-Z0-9_.-]+$" }
},
"secrets": {
"description": "Config key -> name of a Gitea Actions secret. If a secret is missing, the boot test is skipped, not failed.",
"type": "object",
"propertyNames": { "pattern": "^[a-zA-Z0-9_.-]+$" },
"additionalProperties": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" }
},
"timeoutSec": {
"description": "How long to wait for the server to become ready, including install.",
"type": "integer",
"minimum": 60,
"maximum": 7200
}
}
}