Building the Paracosm server
build/build_server.py builds the whole server in one command: from the pristine OpenSimulator 0.9.3.0 source zip
to a runnable bin/ with our seven source patches, the official SQLite DLL, our WorldBridge region module and a
config made from the templates in config/.
Prerequisites
The versions used for the reference build (2026-09-27):
| what | version used | notes |
|---|---|---|
| .NET SDK | 8.0.422 | any .NET 8 SDK; it includes the runtimes (Microsoft.NETCore.App 8.0.28 and Microsoft.AspNetCore.App 8.0.28 here). Mono and Visual Studio are not needed. |
| Python | 3.12.10 | 3.8 or later; standard library only |
| OS | Windows 11 Pro 10.0.22631, x64 | the script also handles Linux, but has not been run there (see Limits) |
| OpenSimulator source | opensim-0.9.3.0-source.zip, 43,218,173 bytes, SHA-256 44811934c289195420ec82a5d448e6ee28b6cfa6094e1a8e6882e489c0967ab7 |
from http://opensimulator.org/dist/opensim-0.9.3.0-source.zip |
| SQLite (Windows) | the official sqlite3.dll 3.47.0 x64, 3,209,728 bytes, SHA-256 982cedc4aaebeec3e8efa8e98fb40491bfb1c7e928d3a3dd97d7440eff1536c5 |
inside https://www.sqlite.org/2024/sqlite-dll-win-x64-3470000.zip |
Not needed: git, patch, NuGet packages (the projects reference none; dotnet build's restore is satisfied by the
SDK itself), network access (unless you use --fetch-sqlite3).
The one command
Put opensim-0.9.3.0-source.zip in the repository root (or pass --zip PATH), copy .env.example to .env and
fill it in, then from the repository root:
python build/build_server.py ../paracosm-server --fetch-sqlite3
Offline, give it the SQLite DLL or its official zip instead of --fetch-sqlite3:
--sqlite3-dll PATH/sqlite3.dll or --sqlite3-zip PATH/sqlite-dll-win-x64-3470000.zip.
Other options: --env PATH (a different env file; default .env in the repository), --clean (delete the output
directory first; without it the script refuses a non-empty one), --low-priority (run dotnet at idle priority,
for building beside a running region), --dotnet PATH, --no-sqlite3, --sqlite3-sha256 HEX (accept a different
SQLite release on purpose). The output directory must be outside the repository.
It takes a few minutes. It prints each step and ends with [build] DONE (exit code 0), or [build] FAILED: <why>
(exit code 1).
What it does
- Prerequisites. Checks for Python 3.8+ and a .NET 8 SDK on
PATH, and records the SDK it builds with. - Verify the zip. Its SHA-256 must equal the pinned hash above; anything else stops the build.
- Extract the zip into the output directory (its top folder
opensim/is stripped). - Apply the patches in
opensim-patches/, in the order listed inopensim-patches/series:asset-instr,sqlite-groups,bulletsim-ghost,startup-script-guard,terrain-script-pbr,sqlite-offlineim,sqlite-profiles. Each is a git-style (-p1) unified diff against the pristine 0.9.3.0 file. The script's own applier is strict: every context and removed line must match byte for byte at the line the hunk names (no fuzz, no offset), and all patches are checked in memory before any file is written. Then every patched file's SHA-256 is compared withopensim-patches/patched-files.sha256, the expected hashes of the patched sources. The seven patches touch disjoint files; each folder's README says what it fixes. - Prebuild, as upstream's
runprebuild.bat/runprebuild.shdo: copy the per-OSbin/System.Drawing.Common.dll.win(or.linux) tobin/System.Drawing.Common.dll, then rundotnet bin/prebuild.dll /target vs2022 /targetframework net8_0 /excludedir = "obj | bin" /file prebuild.xml, which writesOpenSim.slnand every.csproj. The script passes the arguments as a list, so the"obj | bin"argument arrives intact (a POSIX shell mangles the.bat's line). Prebuild's wildcards add the new files ofsqlite-groupsandsqlite-offlineimtoOpenSim.Data.SQLite.csproj; the script checks that they are there. - Compile:
dotnet build --configuration Release OpenSim.sln(with-nodeReuse:falseand-p:UseSharedCompilation=false, so no build server outlives the build). The output lands inbin/. - sqlite3.dll (Windows). The zip's
bin/lib64/sqlite3.dllis a Mono-era build that linksMSVCR90.dll, which Windows no longer has. .NET 8 ignores Mono's dllmap (bin/Mono.Data.Sqlite.dll.config), soDllImport("sqlite3")findsbin/sqlite3.dllfirst. The script puts the official SQLite 3.47.0 x64 DLL there, after checking its SHA-256 against the pin;bin/lib64/is left as upstream shipped it. Skipped on other systems. - WorldBridge. Copies
worldbridge/*.csandWorldBridge.csprojto<out>/.paracosm-build/worldbridge/, builds it there against<out>/bin(-p:OpenSimBin=<out>/bin/), and copiesWorldBridge.dllintobin/. The repository is never written to. - Config. Runs
tools/make_config.py <out>/bin --env <env file>, which writesOpenSim.ini,config-include/StandaloneCommon.ini,config-include/FlotsamCache.ini,config-include/osslEnable.iniandRegions/Regions.inifrom upstream's*.examplefiles, our templates inconfig/and the env file (a new region UUID is made once), and putsconfig/OpenSim.exe.config(log4net:OpenSim.logrolls at 20 MB, five old files kept) in place of upstream's copy. With no--envand no.envin the repository this step is skipped, and the command to run later is printed. - Manifest. Writes
<out>/paracosm-build.json: the repository commit, the version inVERSION, the zip hash, each patch's hash and files, every patched file's hash, the SQLite DLL's source (a download's URL, or a local file's name only) and hash, the hashes ofOpenSim.dllandWorldBridge.dll, the config files written, and the host's OS, Python and SDK. The commit comes from git when the repository root is a checkout (with-dirtyfor uncommitted changes), and otherwise frombuild/source-commit, whichgit archivefills in (export-subst), so a build from a source release records its commit too.
The server is <out>/bin. The rest of <out> is the patched source tree it was built from.
build/make_release.py runs this script on a release's own source zip to make the prebuilt Windows server of a
release: handbook/packaging.md.
Verify
The build checks itself and fails on any mismatch: the zip hash, every hunk of every patch, the patched files'
hashes, the generated csproj, the key DLLs in bin/, the SQLite DLL hash, and the config files. To check by hand:
cd <out>
sha256sum -c <repo>/opensim-patches/patched-files.sha256 # every patched source file: OK
ls bin/OpenSim.dll bin/WorldBridge.dll bin/sqlite3.dll bin/OpenSim.ini bin/Regions/Regions.ini
cat paracosm-build.json
(sha256sum is in Git Bash on Windows; in PowerShell use Get-FileHash -Algorithm SHA256 per file.)
To run it: cd <out>/bin, then dotnet OpenSim.dll in a terminal. For running without a terminal (the REST
console), see handbook/operations.md #5.
Changing a patch
Edit the file in a patched tree, then regenerate that patch's diff against the pristine file, keeping git-style
paths (for a new file the old side is /dev/null):
diff -u --label a/<rel> --label b/<rel> <pristine>/<rel> <patched>/<rel> > opensim-patches/<name>.diff
(git diff --no-index also works.) Then update that file's line in opensim-patches/patched-files.sha256
(sha256sum <rel>, run from the patched tree's root), and list a new diff in opensim-patches/series. Upstream's
files use CRLF line endings, and the diffs carry them: .gitattributes marks the diffs -text so git never
rewrites them. Check with git apply --check or patch -p1 --dry-run on a fresh extraction.
Limits
- The
--fetch-sqlite3download has not been exercised (the reference build ran offline with--sqlite3-dll). The pinned hash is that of the DLL the reference server runs, so if the official zip's DLL differs, the build stops rather than installing it. - Linux: the script handles it (the per-OS System.Drawing DLL, executable bits, no sqlite3.dll step) but has not been run there, and which native SQLite a .NET 8 OpenSim loads on Linux is not verified.
WorldBridge.dllis built from the checked-out source. It is not expected to be byte-identical to a DLL built elsewhere; only the patched OpenSim sources are pinned by hash.