Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

708 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Moongate

Moongate logo

A modern Ultima Online server, built from scratch.

Latest release CI Docker pulls Image size

AGPL-3.0 license .NET 10 ClassicUO 7.x Lua scripting

Moongate is an Ultima Online server written from scratch in .NET 10: a single game-loop thread, Lua scripting, YAML shard data, binary snapshot persistence, and generated documentation for every implemented packet. It is built on the SquidStd toolkit and targets the ClassicUO 7.x client only.

Status: early development. Today the server takes a 7.x client through login, character creation, selection and deletion, and into the world, with movement, items, containers and the paperdoll working. It is not a fully playable shard yet. The exact protocol surface lives in the packet reference.

Why Another Rewrite?

Yes, rewriting a UO server from scratch is not the most practical path. I know. Moongate exists because starting from a blank slate is how I like to learn: it gives me room to test architecture ideas, rebuild systems from first principles, and understand the tradeoffs by writing the code myself. Starting over gives me clarity, curiosity, and the calm needed to keep exploring how things work.

Looking For Collaborators

Moongate is young and moving fast. Contributors and reviewers are welcome.

Quick Start

Requirements

  • .NET SDK 10.0+
  • Docker, if you want to run the container image
  • Ultima Online 7.x client data files. Moongate does not distribute them.

Run The Server Locally

git clone https://github.com/moongate-community/moongate.git
cd moongate
dotnet run --project src/Moongate.Server -- --root-directory ~/moongate --uo-directory ~/uo

On first boot, Moongate creates the runtime directory structure, writes a default moongate.yaml, and seeds an administrator account:

admin / admin

Change the password before using a reachable server. The UO TCP server listens on localhost:2593; point ClassicUO 7.x at it.

Run Tests

dotnet test Moongate.slnx

Docker

Run the published image with persistent server data and read-only UO client files:

docker run -d --name moongate \
  -p 2593:2593 \
  -v /path/to/uo-files:/uo:ro \
  -v moongate-data:/data \
  -e MOONGATE_ROOT=/data \
  tgiachi/moongate-server:latest --uo-directory /uo

Or with Docker Compose:

services:
  moongate:
    image: tgiachi/moongate-server:latest
    command: ["--uo-directory", "/uo"]
    ports:
      - "2593:2593"
    environment:
      MOONGATE_ROOT: /data
    volumes:
      - /path/to/uo-files:/uo:ro
      - moongate-data:/data
    restart: unless-stopped

volumes:
  moongate-data:

Images are published to Docker Hub as tgiachi/moongate-server and to GHCR as ghcr.io/moongate-community/moongate, tagged latest, X.Y, X.Y.Z and sha-<commit>.

NuGet packages

The abstraction assemblies plugin authors compile against are published to GitHub Packages on each release: Moongate.Server.Abstractions plus its dependency closure (Moongate.Core, Moongate.Network, Moongate.Persistence, Moongate.UO.Data, Moongate.Ultima).

GitHub Packages requires authentication even for public feeds, so add a nuget.config next to your plugin project with a GitHub token that has the read:packages scope:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="moongate" value="https://nuget.pkg.github.com/moongate-community/index.json" />
  </packageSources>
  <packageSourceCredentials>
    <moongate>
      <add key="Username" value="%GITHUB_USER%" />
      <add key="ClearTextPassword" value="%GITHUB_TOKEN%" />
    </moongate>
  </packageSourceCredentials>
</configuration>

Then reference the abstractions — the rest of the closure comes transitively:

<PackageReference Include="Moongate.Server.Abstractions" Version="X.Y.Z" />

Match the version to the server you target. See the Writing plugins guide for the full walkthrough.

What Is In Scope Today

  • UO TCP networking with typed packet records and opcode dispatch.
  • Login server flow: account auth, shard list, game-server handoff.
  • Character creation, selection and deletion, and the enter-world sequence.
  • Movement, items, containers with gumps, and the paperdoll.
  • YAML runtime configuration through moongate.yaml.
  • Item, mobile and loot templates as embedded YAML assets, seeded into the runtime data directory.
  • Loot tables validated against concrete item templates at startup.
  • Persistence as binary snapshots per entity kind, with no database.
  • Lua scripting modules: item, mobile, loot, account and events, always dispatched on the game loop.
  • Generated packet reference: every packet class carries a [PacketDocumentation] attribute and the docs are built from the code.
  • CI, semantic-release, Docker images and GitHub Pages documentation.

Project Highlights

  • Two layers by design: SquidStd provides the generic server infrastructure (host, game loop, event bus, plugins, persistence, Lua runtime), Moongate adds everything Ultima Online.
  • One game-loop thread owns all world mutation; packet handlers publish domain events and behaviour lives in subscribers.
  • Runtime data is YAML-first, so shard content can be edited without recompiling.
  • The packet documentation can never drift from the code: the generator fails the build when a packet is missing its metadata.

Documentation

Published documentation: https://moongate-community.github.io/moongate/

Useful starting points:

Build it locally:

dotnet tool restore
dotnet docfx docs/docfx.json --serve

Contributing

Contributions are welcome. For non-trivial changes, open an issue or discussion first so the design can be aligned before implementation.

Before sending a pull request:

  • Follow CODE_CONVENTION.md.
  • Keep changes scoped.
  • Keep tests green.
  • Update docs when runtime behavior changes.

Acknowledgements

Moongate is inspired by the Ultima Online server ecosystem and by the long-running work of projects such as:

License

Copyright 2026 tgiachi.

Moongate is licensed under the GNU Affero General Public License v3.0. Moongate stays open: if you distribute a modified server, or run one that players connect to, you must publish your sources under the same license.

About

A modern Ultima Online server, built from scratch. .NET 10, Lua scripting, ClassicUO 7.x

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages