Moongate.Ultima
0.6.0
Prefix Reserved
dotnet add package Moongate.Ultima --version 0.6.0
NuGet\Install-Package Moongate.Ultima -Version 0.6.0
<PackageReference Include="Moongate.Ultima" Version="0.6.0" />
<PackageVersion Include="Moongate.Ultima" Version="0.6.0" />
<PackageReference Include="Moongate.Ultima" />
paket add Moongate.Ultima --version 0.6.0
#r "nuget: Moongate.Ultima, 0.6.0"
#:package Moongate.Ultima@0.6.0
#addin nuget:?package=Moongate.Ultima&version=0.6.0
#tool nuget:?package=Moongate.Ultima&version=0.6.0

Moongate.Ultima
Ultima Online client data readers and rendering utilities for MUL/UOP assets, maps, art, and localization.
Installation
Requires .NET 10. Use the package version available in your configured NuGet feed.
dotnet add package Moongate.Ultima
Features
- Readers for Ultima Online client data, including MUL and UOP resources.
- APIs for maps, art, gumps, animations, fonts, audio, and localization.
- Client file discovery and client version reading.
- Bitmap helpers and rendering support using SkiaSharp.
Example
Create an in-memory surface and convert it to a caller-owned SkiaSharp bitmap. This example does not require UO client files.
using Moongate.Ultima.Imaging;
using var bitmap = new UltimaBitmap(2, 2);
using var image = bitmap.ToImage();
Console.WriteLine($"{image.Width}x{image.Height}");
Read client art, a map tile and localization
The following Program.cs accepts one client directory argument. Configure the
global file mapping before accessing static asset readers. Use one client
installation per process; changing Files.SetDirectory is not a coordinated
reload of every reader/cache already initialized.
using Moongate.Ultima.Graphics;
using Moongate.Ultima.Io;
using Moongate.Ultima.Localization;
using Moongate.Ultima.Maps;
if (args.Length != 1 || !Directory.Exists(args[0]))
{
throw new ArgumentException("Pass an existing Ultima Online client directory");
}
var clientDirectory = Path.GetFullPath(args[0]);
Files.SetDirectory(clientDirectory);
// Land art is a 44x44 image in 16bppArgb1555. This buffer belongs to the caller.
var pixels = new ushort[44 * 44];
if (Art.TryGetLandPixels(0, pixels, out var patched))
{
Console.WriteLine($"Land art decoded; patched: {patched}, pixels: {pixels.Length}");
}
else
{
Console.WriteLine("Land art 0 is unavailable");
}
var mapPath = Files.GetFilePath("map0.mul") ?? Files.GetFilePath("map0LegacyMUL.uop");
if (mapPath is not null)
{
// Use dimensions matching the client map; these are the modern Felucca defaults.
// The implementation accepts null for Files mapping despite its non-null annotation.
using var tiles = new TileMatrix(0, 0, 6144, 4096, path: null!);
var tile = tiles.GetLandTile(0, 0);
Console.WriteLine($"Map tile: {tile.Id}, Z: {tile.Z}");
}
else
{
Console.WriteLine("Map 0 is unavailable");
}
var clilocPath = Files.GetFilePath("cliloc.enu");
if (clilocPath is not null)
{
var strings = new StringList("enu", clilocPath, decompress: false);
if (!string.IsNullOrEmpty(strings.LoadWarning))
{
Console.WriteLine(strings.LoadWarning);
}
Console.WriteLine(strings.GetString(3000000) ?? "Localization entry is unavailable");
}
else
{
Console.WriteLine("English localization is unavailable");
}
Run with dotnet run -- /absolute/path/to/client. File lookup handles the known
client filenames case-insensitively. Some client versions omit assets or use a
different map size; check required inputs explicitly and surface parse/I/O failures.
The localization reader tries the alternate compression interpretation when
necessary and reports partially salvaged data through LoadWarning.
Art.GetLand/GetStatic offer bitmap APIs, but can return cache-owned objects;
do not dispose or mutate those as if they were private copies. The pixel API above
avoids that ownership ambiguity. A TileMatrix created by your application is
disposable and owns file handles. UltimaBitmap instances you construct and
ToImage() results you create are caller-owned and should be disposed, as in the
first example. These examples demonstrate reading; they do not modify client files.
Client data and native dependencies
Provide your own Ultima Online client data when using the asset readers and configure its location through Moongate.Ultima.Io.Files.SetDirectory. Client assets are not included in this package.
The package depends on SkiaSharp, SkiaSharp.NativeAssets.Linux.NoDependencies, and System.IO.Hashing. NuGet resolves these dependencies. Rendering requires the appropriate native SkiaSharp runtime for the deployment platform; validate that runtime on the systems where your application will run.
This package has no dependency on another Moongate package. It provides client-data APIs, not a game server or a complete game client.
License and source
Licensed under AGPL-3.0-or-later. See the source repository and license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- SkiaSharp (>= 4.152.1)
- SkiaSharp.NativeAssets.Linux.NoDependencies (>= 4.152.1)
- System.IO.Hashing (>= 10.0.12)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.