How to Set Up Reverse-Engineered Ultima Online Server on Linux 2025

How to Set Up Reverse-Engineered Ultima Online Server on Linux 2025

The release of the fully reverse-engineered 1998 Ultima Online demo server (ouo) in 2026 opened a unique opportunity for developers interested in legacy MMORPG architecture, binary analysis, and retro game server infrastructure. This guide walks you through compiling and running the C99 port on modern Linux systems—a significant technical achievement given the original code was Windows x86 MSVC compiled from 1998.

Why Reverse-Engineer the UO Demo Server?

The original UoDemo.exe was compiled with Microsoft Visual C++ 5.0 (Visual Studio 97) and contained approximately 5,000 functions representing actual production Ultima Online server code from mid-1998. The reverse-engineered C99 version maintains:

  • Instruction-level accuracy: Each function was hand-translated and re-disassembled to verify binary equivalence
  • Original class hierarchy: Preserved vtable dispatch (CEntity → CResourceEntity → CItem → CMobile → CPlayer)
  • Playable game state: Full Ocllo island map with NPCs, combat, trading, and quest mechanics

For developers studying game architecture, this is invaluable reference material. For emulator developers, it provides the canonical implementation.

Prerequisites

Before starting, ensure you have:

  • Linux system (Ubuntu 22.04+ or equivalent)
  • Build tools: GCC/Clang, Make, autotools
  • Development libraries: Standard C99 libc, platform-specific APIs
  • Disk space: ~500MB for source, build artifacts, and server data
  • Git: To clone the repository
sudo apt-get update
sudo apt-get install build-essential git gcc make autoconf automake libtool

Optional but recommended:

  • radare2: For binary verification and disassembly comparison
  • gdb: Debugging reverse-engineered functions

Step 1: Clone the Reverse-Engineered Repository

The source code is hosted at https://github.com/draxinar/ouo:

git clone https://github.com/draxinar/ouo.git
cd ouo
git log --oneline | head -20  # Verify commit history

Inspect the directory structure:

ouo/
├── src/              # C99 source files (5,000+ functions)
├── data/             # Server data files (items, NPCs, spawn tables)
├── tools/            # Data format manipulation utilities
├── Makefile
└── README.md

Key source layout:

  • src/entity.c: Core CEntity class and vtable dispatch
  • src/item.c: CItem and CContainer implementations
  • src/mobile.c: CMobile and CPlayer logic
  • src/world.c: Map loading, region management (Ocllo island + reconstructed world)

Step 2: Review Platform-Specific Adaptations

The reverse-engineered code includes Windows→Linux adaptations. Critical sections to understand:

1. Virtual Function Dispatch Original vtable indices are preserved:

// From src/entity.h
struct CEntity {
    void **vtable;      // vtable[0x18] = IsPlayer, [0xD0] = IsMobile, [0xE4] = IsNPC
    uint32_t serial;    // Entity unique identifier
    uint16_t graphic;   // Sprite/appearance ID
    // ... 0x10 bytes base size
};

2. Endianness Handling Ultime Online uses network byte order (big-endian). Check conversions:

grep -r "htonl\|ntohl" src/  # Host-to-network long conversions

3. Memory Layout Verification Each struct has explicit size assertions:

grep -r "sizeof(struct" src/ | grep -E "0x[0-9A-Fa-f]+"

Expected sizes (from original binary):

  • CEntity: 0x10 bytes
  • CItem: 0x50 bytes
  • CMobile: 0x37C bytes
  • CPlayer: 0x458 bytes

Step 3: Compile the Server

Standard Build

./configure
make clean
make -j$(nproc)

Verification Build (with binary comparison)

To verify your compilation matches the original UoDemo.exe:

make clean
CC=gcc CFLAGS="-O2 -march=native" make

# Compare against disassembly (requires radare2)
radare2 -a x86 -b 32 ./bin/uodemo > build/disasm_new.txt
radare2 -a x86 -b 32 /path/to/UoDemo.exe > build/disasm_orig.txt
diff build/disasm_orig.txt build/disasm_new.txt | head -50

Expect minimal differences (typically platform-specific syscalls, not logic).

Step 4: Load Server Data

The demo ships with Ocllo island data extracted from the June 2, 1998 production database. The reverse-engineered source includes tools to load and manipulate this data:

# Convert and verify server data files
cd tools
./uodataconv ../data/UoDemo.dat --output ../data/processed/

# Inspect loaded world state
./worlddump ../data/processed/ --region ocllo

Critical data files:

  • map0.mul: Terrain heightmap for Ocllo
  • statics0.mul: Static object placement (trees, buildings, decorations)
  • itemid.txt: Item definitions and properties
  • tiledata.mul: Tile and static properties

Step 5: Run the Server

Basic Startup

./bin/uodemo --config config/default.ini

With Logging

./bin/uodemo --config config/default.ini --loglevel debug --logfile server.log

Connection Details

  • Default port: 2593 (standard UO login port)
  • Server address: 127.0.0.1 (local testing)
  • Playable account: Username: demo, Password: demo (bundled with data)

Verification Checklist

| Component | How to Verify | Expected Output | |-----------|---------------|------------------| | World load | ./bin/uodemo --dump-world | Ocllo island with 50+ NPCs | | Item database | ./bin/uodemo --dump-items | 5,000+ item definitions | | Spawn system | telnet localhost 2593 then observe | NPCs appear in expected locations | | Quest state | In-game, talk to Lord British | Dragon quest available on Ocllo | | Combat mechanics | Engage NPC in combat | Damage calculations match 1998 formulas |

Step 6: Known Fixes Applied

The reverse-engineered version includes stability improvements flagged in source comments:

Fixed issues:

  • Spawn system: Originally disabled for demo; re-wired dispatch to enable persistent creature spawning
  • Decay system: Reactivated item decay (was stubbed in shipping demo)
  • Skill gain: Corrected formula to match production behavior
  • Fame/notoriety: Fixed directional calculation (was inverted in some cases)
  • Memory issues: Fixed buffer overflows, uninitialized variables (x86 assembly-level bugs)

Each fix is tagged:

grep -r "FIX:" src/ | head -20

Step 7: Extending the World

The original demo only included Ocllo island. The reverse-engineered tooling allows reconstruction of the full Britannia map:

# Reconstruct doors, signs, teleporters for remaining regions
./tools/reconstruct_world ../data/processed/ --regions all

# Verify reconstructed data
./tools/worlddump ../data/processed/ --verify-integrity

Troubleshooting

Compilation Errors

Error: undefined reference to htonl

# Link against libc network functions
CFLAGS="-D_GNU_SOURCE" make

Error: struct size mismatch (expected 0x458, got 0x450)

# Verify GCC uses same struct padding as MSVC
CC=gcc CFLAGS="-mno-ms-bitfields" make

Runtime Errors

Segfault on world load

# Enable bounds checking and logging
./bin/uodemo --config config/debug.ini --sanitize=address

NPCs don't spawn

  • Check spawn system re-wiring: grep -A 5 "SpawnMgr::Init" src/world.c
  • Verify data files loaded: ./bin/uodemo --dump-spawns

Performance Considerations

The 1998 code was optimized for Pentium II hardware (233 MHz). On modern systems:

  • Single-threaded execution (no multithreading in original code)
  • Estimated throughput: 10,000+ concurrent players on modern CPU
  • Memory footprint: ~50MB for full Britannia with 1,000 NPCs

Next Steps

  1. Binary verification: Use radare2 to compare function-by-function against original
  2. Feature expansion: Study the codebase to implement missing 1998 features (PvP balancing, item rarity)
  3. Network analysis: Extend to handle modern UO client versions
  4. Emulator integration: Port specific modules into RunUO, ServUO, or custom frameworks

References

Recommended Tools