Three pre-existing world-save failure-handling bugs, found while reviewing the delta-saves engine (#2610), split out so they land and get adopted on their own before the larger change. #2610 will be rebased on top once this merges. Tracked in project Delta Saves (#7). ## 1. A snapshot missing a segment was published `GenericEntityPersistence.WriteSnapshot` logged a segment (or self-payload) write error and carried on. The save was published without those records, and every entity in the failed segment was deleted at the next load. The error now propagates: `WriteFiles` never moves a partial snapshot over `Saves/`, the previous save stays authoritative, and staff are told. ## 2. A serializer exception killed the process, or published a partial freeze An entity whose `Serialize` threw on a worker thread was an unhandled exception on that thread, which terminates the process. On the inline (main-thread) drain it was caught, but the snapshot was still queued for writing with whatever the workers had produced. Workers now record the first exception and keep draining so the queue empties and the wake/pause handshake completes; after every worker paused, `Snapshot` treats a recorded error (or a failure of the drain itself) as a failed save: nothing is written, the previous save stays, staff are told, and the world resumes. A `WorldSave` handler throwing is logged but does not invalidate the serialized snapshot. ## 3. Publication was not transactional Publishing moved the previous `Saves/` away (`AutoArchive` in `WorldSavePostSnapshot`) and only then moved the new files in. A subscriber throwing after the archive, or the final move failing, left nothing at `Saves/` until the next save; a crash in that window lost the newest save at the next boot. The snapshot now moves to `Saves.next` as soon as its files are complete; only then do subscribers archive the previous save (same event, same `OldSavePath`, so `AutoArchive` and shard subscribers are unchanged), and the staged directory is renamed into place, which is atomic on one volume (file-by-file move across volumes). A staged directory is by construction a complete save newer than `Saves/`, so an interrupted publish is finished at the next boot (before load) or before the next save: whatever sits at `Saves/` is set aside as `Saves.previous-<timestamp>` (never deleted) and the staged save is published, with a warning naming the directory to archive or delete by hand. ## Tests Server.Tests 860 / UOContent.Tests green. New: a throwing serializer is recorded on the worker and the next drain starts clean; a segment that cannot be indexed fails `WriteSnapshot` instead of dropping records; staged-save recovery with and without an existing `Saves/`, and as a no-op. |
||
|---|---|---|
| .config | ||
| .github | ||
| branding | ||
| dev-docs | ||
| Distribution/Data | ||
| Projects | ||
| tools | ||
| .cursorrules | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| azure-pipelines.yml | ||
| CLAUDE.md | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| Directory.Build.props | ||
| FAQ.md | ||
| GEMINI.md | ||
| global.json | ||
| LICENSE | ||
| ModernUO.slnx | ||
| publish.cmd | ||
| publish.ps1 | ||
| publish.sh | ||
| README.md | ||
| rider-settings.zip | ||
| Rules.ruleset | ||
| SPONSORS.md | ||
| stylecop.json | ||
| THIRD-PARTY-NOTICES | ||
| version.json | ||
ModernUO

Ultima Online Server Emulator for the modern era!
Requirements
Supported Operating Systems
Required Frameworks
All Operating Systems
Windows
Hardware
| Use | vCPU | RAM | Storage |
|---|---|---|---|
| Development / test | 2 dedicated | 2 GB | SSD |
| Small live shard (< 50 concurrent) | 4 dedicated | 4 GB | NVMe |
| Medium (50–200) | 4–8 | 8 GB | NVMe |
| Large (200+) | 8+, high clock | 16 GB+ | NVMe |
See dev-docs/server-requirements.md for more information.
Development
Supported IDEs
Getting Started
- Install prerequisite requirements
- Clone this repository (or download the latest):
git clone https://github.com/modernuo/ModernUO.git
- Open
ModernUO.slnto start developing
Building/Publishing
Interactive Mode (Recommended for new users)
Run ./publish.cmd (Windows) or ./publish.sh (Linux/macOS) with no arguments to launch the guided build tool. It will:
- Check prerequisites (.NET SDK, native libraries)
- Walk you through configuration and platform selection
- Build and publish the server to the
Distributiondirectory - Show deployment instructions for cross-compiled builds
Command Line
./publish.cmd [release|debug] [os] [arch]
os- Supported operating systemsarchx64- Intel/AMD 64-bitarm64- ARM 64-bit
Linux Prerequisites
Fedora, CentOS, RHEL, AlmaLinux, Rocky, etc
dnf upgrade --refresh -y
# RHEL-family distributions (CentOS Stream, AlmaLinux, Rocky, RHEL) need CRB and EPEL enabled.
# Fedora skips this block.
dnf install -y dnf-plugins-core
dnf config-manager --set-enabled crb
dnf install -y epel-release
# Prerequisites
dnf install -y findutils libicu libdeflate libargon2 tzdata
Ubuntu, Debian, etc
apt-get update -y
# The ICU runtime package carries the ABI version in its name (libicu74, libicu76, …) and has no
# stable alias, so match it by pattern rather than pinning a release-specific name.
apt-get install -y '^libicu[0-9]+$' libdeflate0 libargon2-1 tzdata
Only the runtime libraries are needed — the -dev/-devel packages are not. Run
./build-tool --check-prereqs to check the current machine and print the exact packages your
release needs.
zstd is not listed because ZstdNet bundles libzstd for every platform, and liburing is not
listed because IORingGroup issues io_uring syscalls directly.
If the shard's configured time zone is a legacy alias such as US/Eastern, Debian 12 and Ubuntu
24.04 also need tzdata-legacy. See Platform Prerequisites
for what each dependency is for and what breaks without it.
OSX Requirements
brew install icu4c libdeflate argon2
Running the Server
- Follow the publish instructions
- The
Distributiondirectory is portable — copy it to your production server for deployment - Run
ModernUO.exeordotnet ModernUO.dllfrom theDistributiondirectory - On first run, the server will prompt you to configure game data file locations
Troubleshooting / FAQ
- See FAQ
Want to sponsor?
Thank you for supporting us! You can find out how by visiting the sponsors page.
Collaborators
Thanks
- RunUO Team & Community
- Voxpire, the ServUO Team & Community
- Karasho, Jaedan and the ClassicUO Community
Development Tools & Plugins provided with ♥ by
Code Signing Policy
Free code signing provided by SignPath.io, certificate by SignPath Foundation.
This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it
Teams & Roles
Approvers & Committers: Development Team