8 Commits
master ... ut

Author SHA1 Message Date
47427e7381 Add kind cluster config example 2025-05-12 12:21:54 +02:00
53354a2113 Add gameserver example 2025-05-12 12:21:48 +02:00
efbb9d5d7e Make sure assets dir is set in example fleet 2025-05-12 12:21:35 +02:00
f8625d9fad Add player tracking to example fleet 2025-05-12 12:21:24 +02:00
f9a2f5bdb0 Fix bzp99 gitea user to bp99 2025-05-06 23:42:05 +02:00
6a7195e6da Adapt containerization to urban terror 2025-05-06 23:23:56 +02:00
dd2c9160aa Adapt example configs to urban terror 2025-05-06 23:23:40 +02:00
21d1628b26 Adapt code to urban terror 2025-05-06 23:23:26 +02:00
9 changed files with 204 additions and 106 deletions

View File

@ -1,4 +1,4 @@
FROM golang:1.13 as builder FROM golang:1.13 AS builder
WORKDIR /workspace WORKDIR /workspace
COPY go.mod go.mod COPY go.mod go.mod
@ -14,17 +14,21 @@ COPY public public/
RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on taskset -c 1 /usr/local/go/bin/go build -a -o q3 ./cmd/q3 RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on taskset -c 1 /usr/local/go/bin/go build -a -o q3 ./cmd/q3
FROM alpine:3.12 as quake-n-bake
RUN apk add --no-cache git gcc make libc-dev FROM alpine:3 AS urt-download
RUN git clone https://github.com/ioquake/ioq3
RUN cd /ioq3 && make BUILD_MISSIONPACK=0 BUILD_BASEGAME=0 BUILD_CLIENT=0 BUILD_SERVER=1 BUILD_GAME_SO=0 BUILD_GAME_QVM=0 BUILD_RENDERER_OPENGL2=0 BUILD_STANDALONE=1
RUN cp /ioq3/build/release-linux-$(uname -m)/ioq3ded.$(uname -m) /usr/local/bin/ioq3ded
FROM alpine:3.12 WORKDIR /ut/
RUN apk add --no-cache libxml2-utils=2.13.4-r5 curl=8.12.1-r1 bash=5.2.37-r0
COPY updater-cfg ./
RUN curl -sSLO 'https://raw.githubusercontent.com/FrozenSand/UrTUpdater/master/ded/UrTUpdater_Ded.sh' && bash ./UrTUpdater_Ded.sh -q
COPY --from=builder /workspace/q3 /usr/local/bin
COPY --from=quake-n-bake /usr/local/bin/ioq3ded /usr/local/bin
COPY --from=quake-n-bake /lib/ld-musl-*.so.1 /lib
FROM alpine:3
RUN apk add --no-cache gcompat=1.1.0-r4
COPY --from=builder /workspace/q3 /usr/local/bin/
COPY --from=urt-download /ut/Quake3-UrT-Ded.x86_64 /usr/local/bin/
COPY --from=urt-download /ut/q3ut4/ /root/.q3a/q3ut4/
# ENTRYPOINT ["/bin/sh"]
ENTRYPOINT ["/usr/local/bin/q3"] ENTRYPOINT ["/usr/local/bin/q3"]

View File

@ -4,16 +4,16 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/criticalstack/quake-kube/pkg/extensions" "github.com/criticalstack/quake-kube/pkg/extensions"
"net/url" // "net/url"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
quakeclient "github.com/criticalstack/quake-kube/internal/quake/client" quakeclient "github.com/criticalstack/quake-kube/internal/quake/client"
"github.com/criticalstack/quake-kube/internal/quake/content" // "github.com/criticalstack/quake-kube/internal/quake/content"
quakeserver "github.com/criticalstack/quake-kube/internal/quake/server" quakeserver "github.com/criticalstack/quake-kube/internal/quake/server"
httputil "github.com/criticalstack/quake-kube/internal/util/net/http" // httputil "github.com/criticalstack/quake-kube/internal/util/net/http"
"github.com/criticalstack/quake-kube/public" "github.com/criticalstack/quake-kube/public"
) )
@ -37,22 +37,22 @@ func NewCommand() *cobra.Command {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
csurl, err := url.Parse(opts.ContentServer) // csurl, err := url.Parse(opts.ContentServer)
if err != nil { // if err != nil {
return err // return err
} // }
if !opts.AcceptEula { if !opts.AcceptEula {
fmt.Println(quakeserver.Q3DemoEULA) fmt.Println(quakeserver.Q3DemoEULA)
return errors.New("You must agree to the EULA to continue") return errors.New("You must agree to the EULA to continue")
} }
if err := httputil.GetUntil(opts.ContentServer, ctx.Done()); err != nil { // if err := httputil.GetUntil(opts.ContentServer, ctx.Done()); err != nil {
return err // return err
} // }
// TODO(chrism): only download what is in map config // TODO(chrism): only download what is in map config
if err := content.CopyAssets(csurl, opts.AssetsDir); err != nil { // if err := content.CopyAssets(csurl, opts.AssetsDir); err != nil {
return err // return err
} // }
go func() { go func() {
s := quakeserver.Server{ s := quakeserver.Server{

View File

@ -3,32 +3,20 @@ timeLimit: 15m
bot: bot:
minPlayers: 3 minPlayers: 3
game: game:
motd: "Welcome to Critical Stack" motd: "Welcome to my UrT Server"
type: FreeForAll type: FreeForAll
forceRespawn: false forceRespawn: false
inactivity: 10m inactivity: 10m
#password: "letmein" # password: "letmein"
quadFactor: 3
weaponRespawn: 3
server: server:
hostname: "quakekube" hostname: "quakekube"
maxClients: 16 maxClients: 16
password: "changeme" # password: "changeme"
commands: commands:
- addbot sarge 2 - addbot sarge 2
maps: maps:
- name: q3dm7 - name: ut4_uptown
type: FreeForAll type: FreeForAll
timeLimit: 10m timeLimit: 10m
- name: q3dm17 - name: ut4_swim
type: FreeForAll type: FreeForAll
- name: q3wctf1
type: CaptureTheFlag
captureLimit: 8
- name: q3tourney2
type: Tournament
- name: q3wctf3
type: CaptureTheFlag
captureLimit: 8
- name: ztn3tourney1
type: Tournament

View File

@ -1,16 +1,16 @@
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: quake name: urbanterror
spec: spec:
selector: selector:
matchLabels: matchLabels:
run: quake run: urbanterror
replicas: 1 replicas: 1
template: template:
metadata: metadata:
labels: labels:
run: quake run: urbanterror
annotations: annotations:
prometheus.io/scrape: 'true' prometheus.io/scrape: 'true'
prometheus.io/port: '8080' prometheus.io/port: '8080'
@ -22,7 +22,7 @@ spec:
- --config=/config/config.yaml - --config=/config/config.yaml
- --content-server=http://127.0.0.1:9090 - --content-server=http://127.0.0.1:9090
- --agree-eula - --agree-eula
image: docker.io/criticalstack/quake:latest image: gitea.bp99.eu/bp99/urban-terror-server:latest
name: server name: server
ports: ports:
- containerPort: 8080 - containerPort: 8080
@ -32,36 +32,36 @@ spec:
initialDelaySeconds: 15 initialDelaySeconds: 15
periodSeconds: 5 periodSeconds: 5
volumeMounts: volumeMounts:
- name: quake3-server-config - name: server-config
mountPath: /config mountPath: /config
- name: quake3-content - name: content
mountPath: /assets mountPath: /assets
- command: - command:
- q3 - q3
- content - content
- --seed-content-url=http://content.quakejs.com - --seed-content-url=http://content.quakejs.com
image: docker.io/criticalstack/quake:latest image: gitea.bp99.eu/bp99/urban-terror-server:latest
name: content-server name: content-server
ports: ports:
- containerPort: 9090 - containerPort: 9090
volumeMounts: volumeMounts:
- name: quake3-content - name: content
mountPath: /assets mountPath: /assets
volumes: volumes:
- name: quake3-server-config - name: server-config
configMap: configMap:
name: quake3-server-config name: server-config
- name: quake3-content - name: content
emptyDir: {} emptyDir: {}
--- ---
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: quake name: urbanterror
spec: spec:
type: NodePort type: NodePort
selector: selector:
run: quake run: urbanterror
ports: ports:
- port: 8080 - port: 8080
targetPort: 8080 targetPort: 8080
@ -79,7 +79,7 @@ spec:
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: quake3-server-config name: server-config
data: data:
config.yaml: | config.yaml: |
fragLimit: 25 fragLimit: 25
@ -87,31 +87,19 @@ data:
bot: bot:
minPlayers: 3 minPlayers: 3
game: game:
motd: "Welcome to Critical Stack" motd: "Welcome to my Urban Terror server"
type: FreeForAll type: FreeForAll
forceRespawn: false forceRespawn: false
inactivity: 10m inactivity: 10m
quadFactor: 3
weaponRespawn: 3
server: server:
hostname: "quakekube" hostname: "quakekube"
maxClients: 12 maxClients: 12
password: "changeme" # password: "changeme"
commands: commands:
- addbot sarge 2 - addbot sarge 2
maps: maps:
- name: q3dm7 - name: ut4_uptown
type: FreeForAll type: FreeForAll
timeLimit: 10m timeLimit: 10m
- name: q3dm17 - name: ut4_swim
type: FreeForAll type: FreeForAll
- name: q3wctf1
type: CaptureTheFlag
captureLimit: 8
- name: q3tourney2
type: Tournament
- name: q3wctf3
type: CaptureTheFlag
captureLimit: 8
- name: ztn3tourney1
type: Tournament

View File

@ -2,7 +2,7 @@
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: quake3-server-config name: server-config
data: data:
config.yaml: | config.yaml: |
fragLimit: 25 fragLimit: 25
@ -10,39 +10,27 @@ data:
bot: bot:
minPlayers: 3 minPlayers: 3
game: game:
motd: "Welcome to Critical Stack" motd: "Welcome to my Urban Terror server"
type: FreeForAll type: FreeForAll
forceRespawn: false forceRespawn: false
inactivity: 10m inactivity: 10m
quadFactor: 3
weaponRespawn: 3
server: server:
hostname: "quakekube" hostname: "quakekube"
maxClients: 12 maxClients: 12
password: "changeme" # password: "changeme"
commands: commands:
- addbot sarge 2 - addbot sarge 2
maps: maps:
- name: q3dm7 - name: ut4_uptown
type: FreeForAll type: FreeForAll
timeLimit: 10m timeLimit: 10m
- name: q3dm17 - name: ut4_swim
type: FreeForAll type: FreeForAll
- name: q3wctf1
type: CaptureTheFlag
captureLimit: 8
- name: q3tourney2
type: Tournament
- name: q3wctf3
type: CaptureTheFlag
captureLimit: 8
- name: ztn3tourney1
type: Tournament
--- ---
apiVersion: "agones.dev/v1" apiVersion: "agones.dev/v1"
kind: Fleet kind: Fleet
metadata: metadata:
name: octops name: urbanterror
labels: labels:
cluster: gke-1.17 cluster: gke-1.17
region: us-east-1 region: us-east-1
@ -58,10 +46,9 @@ spec:
octops.io/terminate-tls: "true" octops.io/terminate-tls: "true"
octops.io/issuer-tls-name: "selfsigned-issuer" octops.io/issuer-tls-name: "selfsigned-issuer"
spec: spec:
players:
# Set initial player capacity if using PlayerTracking Alpha()
initialCapacity: 100
container: gameserver container: gameserver
players:
initialCapacity: 8
ports: ports:
- name: default - name: default
containerPort: 8081 containerPort: 8081
@ -74,11 +61,12 @@ spec:
containers: containers:
- name: gameserver - name: gameserver
imagePullPolicy: Always imagePullPolicy: Always
image: octops/quake:latest image: gitea.bp99.eu/bp99/urban-terror-server:latest
command: command:
- q3 - q3
- server - server
- --config=/config/config.yaml - --config=/config/config.yaml
- --assets-dir=/root/.q3a
- --content-server=http://127.0.0.1:9090 - --content-server=http://127.0.0.1:9090
- --agree-eula - --agree-eula
- --client-addr=0.0.0.0:8081 - --client-addr=0.0.0.0:8081
@ -98,13 +86,13 @@ spec:
memory: "2Gi" memory: "2Gi"
cpu: "1" cpu: "1"
volumeMounts: volumeMounts:
- name: quake3-server-config - name: server-config
mountPath: /config mountPath: /config
- name: quake3-content - name: content
mountPath: /assets mountPath: /assets
- name: content-server - name: content-server
imagePullPolicy: Always imagePullPolicy: Always
image: octops/quake:latest image: gitea.bp99.eu/bp99/urban-terror-server:latest
command: command:
- q3 - q3
- content - content
@ -119,11 +107,11 @@ spec:
memory: "2Gi" memory: "2Gi"
cpu: "1" cpu: "1"
volumeMounts: volumeMounts:
- name: quake3-content - name: content
mountPath: /assets mountPath: /assets
volumes: volumes:
- name: quake3-server-config - name: server-config
configMap: configMap:
name: quake3-server-config name: server-config
- name: quake3-content - name: content
emptyDir: {} emptyDir: {}

111
examples/gameserver.yaml Normal file
View File

@ -0,0 +1,111 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: server-config
data:
config.yaml: |
fragLimit: 25
timeLimit: 15m
bot:
minPlayers: 3
game:
motd: "Welcome to my Urban Terror server"
type: FreeForAll
forceRespawn: false
inactivity: 10m
server:
hostname: "quakekube"
maxClients: 12
# password: "changeme"
commands:
- addbot sarge 2
maps:
- name: ut4_uptown
type: FreeForAll
timeLimit: 10m
- name: ut4_swim
type: FreeForAll
---
apiVersion: "agones.dev/v1"
kind: GameServer
metadata:
name: urbanterror
labels:
cluster: gke-1.17
region: us-east-1
spec:
container: gameserver
players:
initialCapacity: 8
ports:
- name: default
portPolicy: Static
containerPort: 27000
hostPort: 27000
protocol: UDP
- name: client
portPolicy: Static
containerPort: 27080
hostPort: 27080
protocol: TCP
template:
spec:
containers:
- name: gameserver
imagePullPolicy: IfNotPresent
image: gitea.bp99.eu/bp99/urban-terror-server:latest
command:
- q3
- server
- --config=/config/config.yaml
- --assets-dir=/root/.q3a
- --content-server=http://127.0.0.1:9090
- --agree-eula
- --client-addr=0.0.0.0:8081
- --server-addr=0.0.0.0:27000
- --with-agones
ports:
- containerPort: 8081
readinessProbe:
tcpSocket:
port: 8081
initialDelaySeconds: 15
periodSeconds: 5
resources:
requests:
memory: "1Gi"
cpu: "0.5"
limits:
memory: "2Gi"
cpu: "1"
volumeMounts:
- name: server-config
mountPath: /config
- name: content
mountPath: /assets
- name: content-server
imagePullPolicy: Always
image: gitea.bp99.eu/bp99/urban-terror-server:latest
command:
- q3
- content
- --seed-content-url=http://content.quakejs.com
ports:
- containerPort: 9090
resources:
requests:
memory: "1Gi"
cpu: "0.5"
limits:
memory: "2Gi"
cpu: "1"
volumeMounts:
- name: content
mountPath: /assets
volumes:
- name: server-config
configMap:
name: server-config
- name: content
emptyDir: {}

15
examples/kind.yaml Normal file
View File

@ -0,0 +1,15 @@
---
apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: ut-kind
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 27000
hostPort: 27000
listenAddress: "127.0.0.1"
protocol: UDP
- containerPort: 27080
hostPort: 27080
listenAddress: "127.0.0.1"
protocol: TCP

View File

@ -32,15 +32,15 @@ func (s *Server) Start(ctx context.Context) error {
return err return err
} }
args := []string{ args := []string{
"+set", "dedicated", "1", "+set", "dedicated", "2",
"+set", "net_ip", host, "+set", "net_ip", host,
"+set", "net_port", port, "+set", "net_port", port,
"+set", "com_homepath", s.Dir, "+set", "com_homepath", s.Dir,
"+set", "com_basegame", "baseq3", "+set", "com_basegame", "q3ut4",
"+set", "com_gamename", "Quake3Arena", "+set", "com_gamename", "UrbanTerror",
"+exec", "server.cfg", "+exec", "server.cfg",
} }
cmd := exec.CommandContext(ctx, "ioq3ded", args...) cmd := exec.CommandContext(ctx, "Quake3-UrT-Ded.x86_64", args...)
cmd.Dir = s.Dir cmd.Dir = s.Dir
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
@ -51,7 +51,7 @@ func (s *Server) Start(ctx context.Context) error {
if err != nil { if err != nil {
return err return err
} }
if err := ioutil.WriteFile(filepath.Join(s.Dir, "baseq3/server.cfg"), data, 0644); err != nil { if err := ioutil.WriteFile(filepath.Join(s.Dir, "q3ut4/server.cfg"), data, 0644); err != nil {
return err return err
} }
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
@ -145,7 +145,7 @@ func (s *Server) reload() error {
if err != nil { if err != nil {
return err return err
} }
return ioutil.WriteFile(filepath.Join(s.Dir, "baseq3/server.cfg"), data, 0644) return ioutil.WriteFile(filepath.Join(s.Dir, "q3ut4/server.cfg"), data, 0644)
} }
func (s *Server) watch(ctx context.Context) (<-chan struct{}, error) { func (s *Server) watch(ctx context.Context) (<-chan struct{}, error) {

4
updater-cfg Normal file
View File

@ -0,0 +1,4 @@
CURRENTVERSION=${CURRENTVERSION:-1}
DOWNLOADSERVER=${DOWNLOADSERVER:-2}
GAMEENGINE=${GAMEENGINE:-1}
ASKBEFOREUPDATING=${ASKBEFOREUPDATING:-1}