Highly Performant & Scalable Ultima Online Server Emulator https://www.modernuo.com
Find a file
Kamron Batman d3bf283e2d
feat: event-driven target acquisition with a reaction-time gradient (#2601)
Fixes walk-up aggro latency (up to a full 10 s of obliviousness) and hardens the reacquire gate so no state can silence acquisition, while turning `AcquireOnApproach` into the reaction-time knob for future per-creature intelligence tuning.

### Why

`AcquireFocusMob` re-armed the 10 s `ReacquireDelay` **before** scanning, success or failure. A creature that scanned an empty room was blind for 10 s to a player walking up — walk-up aggro latency was uniform in 0..10 s. Waking from sector sleep stacked the AI timer's 0–3 s construction stagger on top. And `NextReacquireTime` is not serialized: on hosts whose tick counter starts negative (GCP pass-through), the 0 default blocked **all** acquisition shard-wide after a restart until the counter crossed zero.

### What

**Event-driven reaction — `AcquireOnApproachDelay` (the intelligence gradient)**
- The paragon `AcquireOnApproach` bool becomes a `TimeSpan` on every creature: an enemy moving inside `AcquireOnApproachRange` (10 for all creatures — on-screen reactive aggro; the periodic scan keeps the wide `RangePerception` sweep) *clamps* the next scan to at most the delay. Repeated steps cannot shorten it further — one scan per delay period, not per step or think.
- `Zero` (paragons) also prods the AI timer: the ranked scan engages within a wheel turn — the old snap, minus the special-cased engage path. The target now comes from the normal FightMode ranking instead of whichever mobile happened to move, and the `Combatant == null` guard stops re-engage spam.
- The 2 s default reads as "took a beat to notice you"; larger values are dumber; `ReacquireDelay` alone is the oblivious floor. Mover checks are the approach logic's `IsEnemy` + `CanBeHarmful` (so pets count and hidden movers are excluded via `CanSee`), with `IsEnemy` first to cheaply reject same-team wild creatures wandering past. The check rides the `OnMovement` callback every step already pays for — no polling added.

**Gate correctness**
- Every scan re-arms the full `ReacquireDelay`, success or failure (classic semantics; reaction time is the approach path, not the poll).
- Self-healing by construction: a deadline further out than `ReacquireDelay` is an illegal state and reads as open — no wedged or wrapped value can silence acquisition beyond one delay period.
- `NextReacquireTime` is seeded from a live tick on deserialize (the GCP negative-tick blackout).

**AI timer wake**
- Activation (sector wake, spawn, resurrection) starts within a 0–256 ms spread instead of the 0–3 s construction stagger, which read as lag.
- The stagger's real job — keeping same-speed cohorts out of lock-step (the RunUO town artifact) — is now a zero-mean ±period/8 jitter on each **idle** think, so phases random-walk apart within seconds and can never re-lock. Instrumentation showed why a one-shot spread can't do this job: the timer wheel fires within ±1 ms, so with 10 creatures on a 500 ms period some pair collides on nearly the same phase ~75% of the time (birthday paradox) and then steps in the same loop iteration *forever*. Jitter is scoped to passive speed: engaged cadence stays exact, since pursuit timing anchors to real step times.

**Debug**
- The `AcquireFocusMob` scan message no longer re-arms the shared 5 s debug cooldown, which swallowed every AI's "I have detected X" transition line.

**API change** for custom scripts: `AcquireOnApproach` (bool) → `AcquireOnApproachDelay` (TimeSpan). Documented in `content-patterns.md` § Target Acquisition, `runuo-migration-docs/09` + `11`, and the migration skill checklist.

### Tests

`AcquisitionTests`: both scan outcomes honor `ReacquireDelay`; a 60 s-wedged gate still acquires; enemy movement clamps the deadline (same-team wild movers and out-of-range movers ignored); repeated movement cannot shorten below the delay; `Zero` opens the gate and prods without a direct engage. Full suite: 755 UOContent green.
2026-09-01 20:42:15 -07:00
.config feat: adopt serialization generator v4 (field-side linkage, anchored timers) (#2586) 2026-08-22 17:54:02 -07:00
.github fix: Require only runtime packages on Linux, and check ICU and tzdata the way the runtime does (#2561) 2026-08-07 15:03:08 -07:00
branding feat(build-tool): add application icon and refresh MUO.ico (#2487) 2026-06-14 11:59:54 -07:00
dev-docs feat: event-driven target acquisition with a reaction-time gradient (#2601) 2026-09-01 20:42:15 -07:00
Distribution/Data feat: Adds independent think/move clocks for creature AI to fix speed (#2591) 2026-08-23 10:19:59 -07:00
Projects feat: event-driven target acquisition with a reaction-time gradient (#2601) 2026-09-01 20:42:15 -07:00
tools feat(network): allowlist false-positive IPs, escalate on behavior (#2556) 2026-07-30 23:12:17 -07:00
.cursorrules chore: Adds AI instructions and SKILLs for ModernUO codebase (#2347) 2026-03-01 11:42:19 -08:00
.editorconfig chore(docs): Adds UnmanagedDataReader & BinaryFileReader documentation (#1968) 2024-10-01 17:07:51 -07:00
.gitattributes fix: Adds migration checks to CICD, updates dependencies, adds Fedora 37, alpine 3.17 support (#1309) 2022-12-22 12:12:47 -08:00
.gitignore perf: Sleep the event loop when idle. Fixes networking micro-stalls. Adds event loop instrumentation. (#2559) 2026-08-09 13:24:59 -07:00
AGENTS.md chore: Adds AI instructions and SKILLs for ModernUO codebase (#2347) 2026-03-01 11:42:19 -08:00
azure-pipelines.yml chore: Cleans workflows for NodeJS 24 (#2394) 2026-03-28 21:55:29 -07:00
CLAUDE.md docs: update serialization docs and skills for generator v4 (#2588) 2026-08-22 18:29:27 -07:00
CODE_OF_CONDUCT.md Create CODE_OF_CONDUCT.md 2020-05-05 08:51:39 -07:00
CONTRIBUTING.md chore(license): Removes CLA requirement. All contributors moving forward will retain copyright. (#2038) 2024-12-31 02:52:58 -08:00
Directory.Build.props feat: Bumps dependencies. Introduces Serialization Generator v3 (#2584) 2026-08-22 15:48:53 -07:00
FAQ.md docs: Updates FAQ for time zone issues. (#1368) 2023-03-10 00:18:36 -08:00
GEMINI.md chore: Adds AI instructions and SKILLs for ModernUO codebase (#2347) 2026-03-01 11:42:19 -08:00
global.json feat: Adds Build Tool for Publishing/Setup (#2392) 2026-03-28 21:21:50 -07:00
LICENSE Fixes more line ending issues (#267) 2020-09-27 13:54:56 -07:00
ModernUO.slnx feat: Adds Build Tool for Publishing/Setup (#2392) 2026-03-28 21:21:50 -07:00
publish.cmd feat: Adds Build Tool for Publishing/Setup (#2392) 2026-03-28 21:21:50 -07:00
publish.ps1 fix: Adds stamp check for build tool versioning (#2400) 2026-04-06 16:18:02 -06:00
publish.sh fix: Adds stamp check for build tool versioning (#2400) 2026-04-06 16:18:02 -06:00
README.md chore: Simplify server requirements section in README (#2582) 2026-08-21 19:22:04 -07:00
rider-settings.zip Cleanup/Housekeeping (#242) 2020-09-12 15:31:21 -07:00
Rules.ruleset chore(docs): Adds UnmanagedDataReader & BinaryFileReader documentation (#1968) 2024-10-01 17:07:51 -07:00
SPONSORS.md chore: Updates readme files (#2247) 2025-07-27 11:04:32 -07:00
stylecop.json Updates formatting rules (#199) 2020-08-25 18:00:51 -07:00
THIRD-PARTY-NOTICES docs: Adds RunUO-Encryption notice attribution to DarkStorm (#2369) 2026-03-12 23:35:47 -07:00
version.json feat: Adds Build Tool for Publishing/Setup (#2392) 2026-03-28 21:21:50 -07:00

ModernUO - Ultima Online Server Emulator for the modern era!

ModernUO Discord Subreddit subscribers Twitter Follow

Ultima Online Server Emulator for the modern era!

GitHub license GitHub stars GitHub issues
GitHub build Azure Pipelines build

Requirements

Supported Operating Systems

Windows 10/11/2012 R2/2016/2019/2022/2025 MacOS 14+ Debian 12+ Ubuntu 22+ LTS
Alpine 3.22+ Fedora 42+ RedHat 9+ CentOS Stream 9+ AlmaLinux 10 openSUSE 15.6+ SUSE Enterprise 15 SP6 Linux Mint 21+ Arch

Required Frameworks

All Operating Systems

.NET

Windows

VC++ Redistributable v14

Hardware

Use vCPU RAM Storage
Development / test 2 dedicated 2 GB SSD
Small live shard (< 50 concurrent) 4 dedicated 4 GB NVMe
Medium (50200) 48 8 GB NVMe
Large (200+) 8+, high clock 16 GB+ NVMe

See dev-docs/server-requirements.md for more information.

Development

git .NET

Supported IDEs

Jetbrains Rider 2025.3+ space VSCode space Visual Studio 2026

Getting Started

  • Install prerequisite requirements
  • Clone this repository (or download the latest):
    • git clone https://github.com/modernuo/ModernUO.git
  • Open ModernUO.sln to start developing

Building/Publishing

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 Distribution directory
  • Show deployment instructions for cross-compiled builds

Command Line

./publish.cmd [release|debug] [os] [arch]

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 Distribution directory is portable — copy it to your production server for deployment
  • Run ModernUO.exe or dotnet ModernUO.dll from the Distribution directory
  • On first run, the server will prompt you to configure game data file locations

Troubleshooting / FAQ

Want to sponsor?

Thank you for supporting us! You can find out how by visiting the sponsors page.

Collaborators

Kamron Batman Mark1145

Thanks

  • RunUO Team & Community
  • Voxpire, the ServUO Team & Community
  • Karasho, Jaedan and the ClassicUO Community



Development Tools & Plugins provided with ♥ by

JetBrains
Material Theme

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