Highly Performant & Scalable Ultima Online Server Emulator
https://www.modernuo.com
c-sharpcsharpcsharp-coredotnetdotnet-coreemulatorgplgplv3mmommo-enginemmorpgmmorpg-serveronlinerpgrunuoserverservuoultimaultima-onlineuo
Players could not place any door while customizing a house, and placing other
pieces could disconnect them outright. Staff saw neither problem, because
Designer_Build only enforces ValidPiece below GameMaster.
Doors: the retail client's doors.txt separates its header rows with lines of
bare tabs. Spreadsheet.ReadLine skipped lines only when `line.Length > 0`, so a
10-tab line was accepted as the names row - every column ended up named "",
GetColumnID resolved nothing, and not one of the 230 door graphics was
registered. Unregistered pieces keep the NotAComponent sentinel, so ValidPiece
rejected every door. The client skips these lines with IsNullOrWhiteSpace; now
so do we. Verified against a retail 7.0.x doors.txt: 0 door graphics before,
230 after.
Crash: every sheet ends in a cosmetic Comment column that is never read, and
client sheets write an empty comment as a plain newline with no trailing tab.
Split('\t') then returns one field fewer than the header declares and the
parser indexed past the end, throwing IndexOutOfRangeException out of the
design packet handler. The client's parser only requires the columns up to
FeatureMask (ClassicUO's CustomHouseMisc.Parse guards on `scanf.Length >= 12`
for a 13-column misc.txt), so such a row is valid data listing real pieces.
Treat a missing trailing field as empty rather than dropping the row, which
would unregister every piece the row lists.
EnsureLoaded also set _loaded before loading, so after the throw an all -1
table stayed cached and rejected everything for players from then on - the same
symptom as #2500.
Also made the failure modes explicit rather than accidental:
- Named the table sentinels. NotAComponent (-1) is the anti-cheat guard and the
initial state; NoFeatureRequired (0) is a piece with no expansion gate.
- A sheet with no FeatureMask column is now refused and logged. GetInt32 on a
missing column returns NoFeatureRequired, which would have silently marked
every piece in that sheet unconditionally placeable regardless of expansion.
- A sheet matching none of its expected tile columns is refused and logged.
Individual missing columns stay tolerated: older sheets predate columns such
as walls.txt's SecondAltWindowS/E.
- Catch per sheet, so one unreadable file no longer costs the other six.
- Guard the header rows: an empty file or a types-only file raised a
NullReferenceException, and a short names row indexed past the end.
- Fall back to the component sheets when housing.bin cannot be read, rather
than passing null into a SpanReader.
_loaded is still set before loading, deliberately: retrying would re-read every
sheet on each subsequent placement attempt from the packet path.
Sheet precedence is unchanged - the client's copies stay authoritative and
Data/Components remains the fallback.
Co-authored-by: SynPDX <mickelonis@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .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
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-devel zstd libargon2-devel liburing-devel
Ubuntu, Debian, etc
apt-get update -y
apt-get install -y libicu-dev libdeflate-dev zstd libargon2-dev liburing-dev
OSX Requirements
brew install icu4c libdeflate zstd 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