Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6e48f0d
Add submodules for OPResource + OPDB
clouths Mar 15, 2026
5af7381
Add container support using linux containers, add migration script fo…
clouths Mar 15, 2026
26512e6
Update mssql-tools to a more recent version (18) to fix migration, up…
clouths Mar 16, 2026
0689ed4
Fix comment in .env.local, remove preparePatch from the migration scr…
clouths Mar 16, 2026
1073ced
Move db persistent storage into a docker volume
clouths Mar 17, 2026
0fa79c6
Most fo the refactor from System.Drawing to SkiaSharp is done.
clouths Mar 21, 2026
decdcfd
Fix migration order of copy to ensure the generated perpetuum.ini is …
clouths Mar 21, 2026
67f8314
Add DefinitionConfig refactor
clouths Mar 21, 2026
b31e821
Update db submodule + migration script to use P34 and P35 full sql files
clouths Mar 21, 2026
1eba63b
Update port mapping to allow more ports for the server to fix black s…
clouths Mar 24, 2026
984ed0a
Fix port mapping, defined extra SERVER_PORTS for port range to forewa…
clouths Mar 24, 2026
0bf693c
Disable EnlistTransactaction
clouths Mar 25, 2026
c19dedf
Add documentation in the readme for how to setup the containers, make…
clouths Mar 28, 2026
17c38fa
Update db image to use mssql-2025
clouths Mar 28, 2026
afe07ea
Fix WithCanvas extension to preserve the Bitmap using SKCanvas instea…
clouths Mar 28, 2026
cba0e76
Fix font.size to use Size property
clouths Mar 28, 2026
8a40610
Fix pixel check to use Alpha instead of the Luminance
clouths Mar 29, 2026
005b8ce
Fix typo, replace usage of manual creation of Area with size.ToArea()…
clouths Mar 29, 2026
14a1e65
Fix PresenceConfiguration to use the Configuration size instead of th…
clouths Mar 29, 2026
c1a425d
Merge develop branch into linux+containerize
clouths Aug 30, 2026
a10dcd8
Merge branch 'develop' of github.com:OpenPerpetuum/PerpetuumServer2 i…
clouths Aug 30, 2026
3adb6bf
Try fix merge of FakeDb.cs causing ci build error
clouths Aug 30, 2026
d8c5168
Add make commands to run tests (unit+integration) using the docker co…
clouths Aug 30, 2026
0af068c
Add Live_36 to migration, all integration tests passes now
clouths Aug 31, 2026
8256cf6
Add unit and integration tests
clouths Aug 31, 2026
a75e424
Merge branch 'develop' of github.com:OpenPerpetuum/PerpetuumServer2 i…
clouths Sep 2, 2026
4953b3d
Update db submodule
clouths Sep 2, 2026
87cd9d8
Add CI to run tests with docker
clouths Sep 2, 2026
2d884d9
Revert "Add CI to run tests with docker" for now, I'll create a new P…
clouths Sep 2, 2026
c9d5ec0
perf(migration): automate patch discovery and add snapshot caching
clouths Sep 4, 2026
da38e09
perf(server): add SIMD acceleration, terrain metadata, and idle throt…
clouths Sep 4, 2026
96d4826
fix(data): share connection within TransactionScope to prevent MSDTC …
clouths Sep 4, 2026
bb0d416
Update db submodule
clouths Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Environment for local development.
# Compatible with podman/docker with linux containers.

# Database settings
DB_PASSWORD="l3<Nv2-QIat4YK*ydt#u-^+VAAVVdytL"

# Uncomment to force a reset of the DB + run migration
# FORCE_MIGRATION="true"

# Port mapping setting
# Here you can modify the default values
# Only the SERVER and the ASSET ports are required
# The SERVER port is used to allow access to the server when you connect your client
# The SERVER ports is a range that needs to start from the SERVER_PORT + ~300
# Note Without proper SERVER_PORTS, the client will have a black screen when entering a zone
# The ASSET port is used by the client to fetch assets when connecting to the server
# The DB port is optional, used for debugging
SERVER_PORT=17700
SERVER_PORTS=17700-17900
ASSET_PORT=16999
DB_PORT=16998

ASSET_URL="http://localhost:${ASSET_PORT}"

GAME_ROOT="/data"

# Original data directory from Stream: Perpetuum Dedicated Server installer
PERPETUUM_DATA="./perpetuum-data"

# User-provided additional map layers assets
# TODO: Move to a guide/readme
# Required if you want to load the server with Gamma Islands
# Download URL: https://drive.google.com/file/d/1qDjPHbTSdal_aKN6SvYC_EoGW-COkwhJ/view?usp=sharing
# sha256sum:
# f4d42d5dbf6a61d2d7730b2058f5d2bb80a63d0994bbc84b906f19441bb8e425 GAMMA_LAYERS_2021_10_17_P26.rar
CUSTOM_LAYERS="./custom-layers"

# Connection string: Specific changes made to work on linux:
# - Added "sa" user, password to use SQL server authentication;
# - Added TrustServerCertificate=True to trust the self-signed certificate
# - Changed Server to the name of the database container: "db"
# - Removed due to incompatibility on linux: "Connection Reset=True;"
# - Removed Trusted_Connection since we don't want to use Windows Authentication (SPPI)
CONNECTION_STRING="Server=db;Database=perpetuumsa;User Id=sa;Password=${DB_PASSWORD};TrustServerCertificate=True;Pooling=True;Connection Timeout=30;Connection Lifetime=260;Min Pool Size=20;Max Pool Size=60;"


RUNTIME_IDENTIFIER="linux-x64" # TODO env for windows as well (windows-x64)
DISTRIBUTED_TRANSACTIONS=false # .NET on linux does not support Distributed Transactions
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ src/Perpetuum.ServerService2/data/layers/
src/Perpetuum.ServerService2/data/logs/
bin/
Releases/

custom-assets/

# User-provided additional map layers assets
custom-layers/

# Original directory folder from Stream: Perpetuum Dedicated Server installer
perpetuum-data/

.claude/settings.local.json
.planning/
*.log
Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "db"]
path = db
url = https://github.com/OpenPerpetuum/OPDB.git
[submodule "asset"]
path = asset
url = https://github.com/OpenPerpetuum/OPResource.git
47 changes: 47 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
help:
@echo "Commands to compile, deploy, log services used to run an OpenPerpetuum server, and run the test tiers (used for local development)"

# Create and start the containers
up:
./script/compose.sh up -d --build --remove-orphans --wait

# Start the containers
start:
./script/compose.sh start

# Stop the containers
stop:
./script/compose.sh stop

# Stop and delete the containers
down:
./script/compose.sh down

# Stop and delete the containers, also delete the volumes (openperpetuum-data, openperpetuum-db)
delete:
./script/compose.sh down -v

# Stop, delete and start the containers
restart: down up

log-asset:
./script/compose.sh logs asset -f

log-db:
./script/compose.sh logs db -f

log-server:
./script/compose.sh logs server -f

# Run the unit test tier (2) in the test container, no database required
test-unit:
./script/compose.sh --profile test run --build --rm test dotnet test src/Perpetuum.Tests/Perpetuum.Tests.csproj -c Release -p:Platform=x64 --no-build

# Run the integration test tier (3) in the test container, against the live database,
# bringing up db + migration first (migration is idempotent and exits when already done)
test-integration:
./script/compose.sh up -d db --wait
./script/compose.sh up migration
./script/compose.sh --profile test run --build --rm test dotnet test src/Perpetuum.Tests.Integration/Perpetuum.Tests.Integration.csproj -c Release -p:Platform=x64 --no-build

PHONY: help up start stop down log-asset log-db log-server test-unit test-integration
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

# The Open Perpetuum Server 2

## Native Windows host

`Perpetuum.Server` is annotated `[SupportedOSPlatform("windows")]` and the Admin Tool is WPF. You need the .NET 8 SDK, a SQL Server instance, and the `perpetuumsa` database — see [OPDB](https://github.com/OpenPerpetuum/OPDB) for restore and patches.
## Running a local server

Windows and x64 only. The bootstrapper is annotated `[SupportedOSPlatform("windows")]` and the Admin
Expand Down Expand Up @@ -79,3 +82,89 @@ dotnet run -- "C:\PerpetuumServer\data"
The server is up when the log reads `>>>> Perpetuum Server State : [Online]`. Ctrl+C shuts it down;
a clean shutdown ends at `State : [Off]`.

## Docker compose

Local development runs in **Linux containers** (Docker or Podman).

`compose.yml` defines the asset server, SQL Server, migration job, and game server. Configuration lives in `.env.local`.

Two named volumes persist between restarts:

- `openperpetuum-data` — original `PerpetuumServer/data`, custom layers, and a generated `perpetuum.ini`
- `openperpetuum-db` — SQL Server files

`make` wraps the compose commands; you can call `docker compose` / `podman compose` yourself if you prefer.

### Requirements

- Docker or Podman (Linux containers)
- (optional) `make`
- Steam: Perpetuum Dedicated Server installed
- Latest gamma island layers: https://drive.google.com/file/d/1Xp0T1K57Pv-vjgmpXMG8Iea_ec0bWYR4/view?usp=drive_link
- Latest asset resource: https://drive.google.com/file/d/18fh8aRqMP1J7ycGBNGraFyQ31mMXZaq1/view?usp=drive_link

### 1. Clone and submodules

```sh
git clone https://github.com/OpenPerpetuum/PerpetuumServer2.git
# or: git clone git@github.com:OpenPerpetuum/PerpetuumServer2.git
cd PerpetuumServer2
git submodule init && git submodule update
```

Submodules:

- `db` (OPDB) — database migration files per game update
- `asset` (OPResource) — client resources served when a client connects (definitions, translations, gfx, layers, audio, custom bot models)

### 2. Custom resources

Do this whenever the gamma layers or asset pack are updated.

- Uncompress the gamma layers and copy every `.bin` into both:
- `asset/lang0000/layers/GAMMA_LAYERS_NEW`
- a new `custom-layers` directory (same files)
- Unarchive the asset resource and copy `gfx`, `sfx`, and `textures` into `asset/lang0000`
- Create `perpetuum-data` and copy the Dedicated Server installer `data` folder into it (`database`, `layers`)

Paths for `perpetuum-data` and `custom-layers` can be changed in `.env.local`.

### 3. Configuration

Edit `.env.local` for ports, the database password, paths, and the SQL connection string.

The migration job writes `perpetuum.ini` from `template/perpetuum.ini.template`. Do not copy the installer `perpetuum.ini` into the data volume — that file was written for `System.Data.SqlClient` and this server uses `Microsoft.Data.SqlClient`. The template already uses a Linux-compatible string: SQL authentication (`sa`), `TrustServerCertificate=True`, no `Trusted_Connection`, and no keywords the driver refuses (`Connection Reset`, `Network Library`, `Context Connection`).

Linux does not support distributed transactions. `.env.local` sets `DISTRIBUTED_TRANSACTIONS=false` for that reason.

`SERVER_PORTS` must be a range of about 300 ports starting at `SERVER_PORT` (default `17700-17900`). A single mapped port is enough to log in; entering a zone then shows a black screen.

### 4. Run the server

```sh
make up
```

This builds and starts the containers and runs migrations. The command returns before the game host is fully up; wait a few minutes.

```sh
make log-server
```

The server is ready for a client when you see lines such as `Unit enter to zone` or `Planthandler STOP SIGNAL received`.

### 5. Point the client at this host

- Open the client → **Server list** → **ADD PRIVATE SERVER**
- Name: `local`
- Address: `127.0.0.1:17700` (use `SERVER_PORT` from `.env.local` if you changed it)
- Connect, then log in with user `test` / password `test`

The first connect can take several minutes while the asset server transfers files.

### 6. Stop

```sh
make down # stop and remove containers; keep data and db volumes
make delete # also delete the volumes
```
1 change: 1 addition & 0 deletions asset
Submodule asset added at e00fe9
104 changes: 104 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
services:
asset:
build:
context: ./asset
dockerfile: ../docker/Dockerfile.asset.dev
restart: unless-stopped
networks:
- dev_env
volumes:
- .:/asset
ports:
- ${ASSET_PORT}:1337

db:
image: mcr.microsoft.com/mssql/server:2025-latest
ports:
- ${DB_PORT}:1433
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=${DB_PASSWORD}
networks:
- dev_env
healthcheck:
test: /opt/mssql-tools18/bin/sqlcmd -S localhost -C -U sa -P "${DB_PASSWORD}" -Q "SELECT 1" -b -o /dev/null
interval: 10s
timeout: 3s
retries: 10
hostname: db
volumes:
# Note for linux/WSL2, it can cause permission denied, fix:
# sudo chown -R 10001:10001 openperpetuum-db
- openperpetuum-db:/var/opt/mssql
# Mount perpetuum database path that contains the perpetuumsa.bak
- "${PERPETUUM_DATA}/database:/data"

migration:
build:
context: .
dockerfile: ./docker/Dockerfile.migration.dev
args:
ASSET_URL: ${ASSET_URL}
CONNECTION_STRING: ${CONNECTION_STRING}
SERVER_PORT: ${SERVER_PORT}
depends_on:
db:
condition: service_healthy
environment:
DB_PASSWORD: ${DB_PASSWORD}
FORCE_MIGRATION: ${FORCE_MIGRATION}
networks:
- dev_env
volumes:
- ./db:/migration
- "${PERPETUUM_DATA}:/base-data"
- "${CUSTOM_LAYERS}:/custom-layers"
- "./src/Perpetuum.ServerService2/data:/perpetuum-service-data"
- openperpetuum-data:/data

server:
build:
context: .
dockerfile: ./docker/Dockerfile.server.dev
args:
RUNTIME_IDENTIFIER: ${RUNTIME_IDENTIFIER}
restart: unless-stopped
networks:
- dev_env
ports:
- ${SERVER_PORTS}:17700-17900
environment:
GameRoot: ${GAME_ROOT}
DistributedTransactions: ${DISTRIBUTED_TRANSACTIONS}
depends_on:
migration:
condition: service_completed_successfully
volumes:
- openperpetuum-data:/data


# Test runner (unit + integration tiers). Excluded from the default stack via the "test" profile:
# make test-unit / make test-integration
# or manually: docker compose --profile test run --rm test <dotnet test args>
test:
profiles: [test]
build:
context: .
dockerfile: ./docker/Dockerfile.test
args:
SERVER_PORT: ${SERVER_PORT}
ASSET_URL: ${ASSET_URL}
CONNECTION_STRING: ${CONNECTION_STRING}
networks:
- dev_env
depends_on:
db:
condition: service_healthy

networks:
dev_env:
driver: bridge

volumes:
openperpetuum-data:
openperpetuum-db:
1 change: 1 addition & 0 deletions db
Submodule db added at 2c842b
11 changes: 11 additions & 0 deletions docker/Dockerfile.asset.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Development dockerfile for the asset

FROM node:alpine3.23

WORKDIR /var/www/OPResource

COPY . .

RUN npm install .

CMD ["node", "index.js"]
44 changes: 44 additions & 0 deletions docker/Dockerfile.migration.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
FROM ubuntu:22.04

ARG ASSET_URL
ARG CONNECTION_STRING
ARG SERVER_PORT

# Install dependencies for mssql-tools18
RUN apt-get update && apt-get install -y \
curl \
gnupg \
apt-transport-https \
&& rm -rf /var/lib/apt/lists/*

# Add Microsoft repository
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \
curl https://packages.microsoft.com/config/ubuntu/22.04/prod.list | tee /etc/apt/sources.list.d/msprod.list

# Install mssql-tools18
RUN apt-get update && ACCEPT_EULA=Y apt-get install -y \
mssql-tools18 \
&& rm -rf /var/lib/apt/lists/*

# Add sqlcmd to PATH
ENV PATH="/opt/mssql-tools18/bin:${PATH}"

WORKDIR /work

COPY script/migration.sh .
COPY template/perpetuum.ini.template .
COPY template/restore_DB_to_original_state.sql .

RUN mv perpetuum.ini.template perpetuum.ini

RUN sed -i "s/{SERVER_PORT}/${SERVER_PORT}/" perpetuum.ini
# Update the connection string but hides the command to hide the password
RUN set +x && \
sed -i "s/{CONNECTION_STRING}/${CONNECTION_STRING}/" perpetuum.ini && \
set -x
# Using # delimiter to avoid conflict with / from the url
RUN sed -i "s#{ASSET_URL}#${ASSET_URL}#" perpetuum.ini



ENTRYPOINT ["/work/migration.sh"]
Loading
Loading