SunUO

Max Kellermann


Table of Contents

What is SunUO?
1. Installation
Requirements
Installing Mono
Installing the UO data files
Installing a new server
Upgrading a shard from RunUO
Compiling SunUO from the sources
2. Upgrading
Upgrading to 0.5.0
Upgrading to 0.3.0
3. Configuration
Basics
UO client directory
Networking
Server list
Features
Accounting
Automatic saving
Encryption
Tricks
Separating login server from shard server
SunUO behind a NATted private network
Working around RunUO bugs
Making [restart work
Making [restart work with BINFMT_MISC
Customized houses
GDIPlus related crashes
The RunUO faction direntry order bug
Arya's auction
Logging
4. Scripts
Why script libraries?
Library path
Excludes
Disabling a library
Dependencies
Overlays
Taming the warnings
5. Troubleshooting
Getting help

List of Tables

3.1. Feature flags

What is SunUO?

SunUO is a free Ultima Online server for Linux/Mono and Windows.NET, based on RunUO.

Chapter 1. Installation

Requirements

Experience has shown that CPU power is not that important. Even a huge shard will not load a consumer-grade Pentium IV more than 10%. Memory is much more important; for a big shard, you should consider using a 64 bit operating system, since you cannot make a process larger than 3 GB with a 32 bit operating system. A quick hard disk can accelerate world saves.

Installing Mono

SunUO requires a .NET 1.1 runtime. On Windows, you can get Microsoft's .NET Framework via Windows Update. On other operating systems like Linux, you have to use Mono instead; please use the most recent version available. Most current Linux distributions come with Mono nowadays. On Debian Etch, the following procedure will install Mono:

apt-get install mono mono-mcs libmono-winforms1.0-cil

I have been told that you can do the following on Fedora:

yum install mono

Also ensure that the Mono C# Compiler (mcs) is installed, SunUO needs it to compile scripts.

Installing the UO data files

SunUO uses the data files from the original Ultima Online to calculate its world. Copy the whole UO directory to your SunUO server, e.g. /opt/games/uo. On Windows, SunUO should be able auto-detect an UO client.

Installing a new server

Unzip the SunUO binary zip file.

Edit the file conf/sunuo.xml and set your preferences. You might want to set the location of the UO client (element data-path).

If everything is set up, you can start your new SunUO server by running run.bat or run64.bat (Windows 32/64 bit) or ./run.sh (all other operating systems, including Linux).

If you have got less than 512 MB of physical memory or a slow CPU, the first script compilation can take 15 minutes or longer.

The first account created gets administrator privileges. Therefore make sure that auto-accounting is enabled during installation.

Upgrading a shard from RunUO

Important

Don't forget to back up your old server!

  1. Shut down RunUO.

  2. Unpack the SunUO binary zip file somewhere, and copy all files from the base directory plus the etc and bin directory into the old RunUO directory.

  3. Read the section Working around RunUO bugs carefully.

  4. Start SunUO by running run.bat (Windows) or ./run.sh (all other operating systems, including Linux).

Compiling SunUO from the sources

If you are on Unix with Mono, edit the file config.mk and change the paths. Then type:

make

Note that the resulting executable does not work on Windows. I am yet unsure if this is a Mono MCS bug or a Microsoft.NET bug. On windows, run the file compile.bat. If that does not work, edit compile.bat and check if the "csc.exe" location is correct. The executable compiled on Windows also runs on Mono.

Chapter 2. Upgrading

Important

Don't forget to back up your old server!

  1. Shut down SunUO.

  2. Delete SunUO.exe and the directory bin

  3. Unpack the SunUO binary zip file somewhere.

  4. Copy the files run*.bat, run.sh and the directory bin to your SunUO base directory. You should also copy the external libraries (*.dll).

  5. Start SunUO by running run.bat or run64.bat (Windows 32/64 bit) or ./run.sh (all other operating systems, including Linux).

The rest of this chapter describes other actions required for a smooth upgrade.

Upgrading to 0.5.0

SunUO 0.5.0 adds support for the UO client version 6. This patch requires several script changes. The following scripts have been changed for this:

Items/Misc/BulletinBoards.cs
Items/Skill Items/Magical/Spellbook.cs
Mobiles/Vendors/BaseVendor.cs

Upgrading to 0.3.0

The ZLib.cs workaround was removed from the core; instead of excluding that script from compilation, overwrite it with the version shipped with SunUO.

Core.AOS is disabled by default. Enable the feature age-of-shadows instead.

Chapter 3. Configuration

Basics

In RunUO, much of the configuration is done by editing the ./Scripts/ source codes. That makes upgrading a nightmare. SunUO tries to put as much as possible into the file ./etc/sunuo.xml, although this is limited currently, because compatibility with RunUO is important. SunUO creates this file on its first run.

UO client directory

You have to tell SunUO where you have installed the UO client. Enter the absolute path in the element data-path:

<sunuo-config>
  <locations>
    <data-path>/usr/local/games/uo</data-path>
  </locations>
</sunuo-config>

Networking

In the network section, you can configure which ports SunUO listens on:

<sunuo-config>
  <network>
    <bind address="127.0.0.1" port="2593"/>
    <bind port="2594"/>
  </network>
</sunuo-config>

If you have more than one public IP, you can bind several SunUO instances on the same port, but on different IPs.

If you omit the address attribute, SunUO listens on all interfaces. The default port is 2593. When no bind configuration is present at all, SunUO creates one listener which binds to all interfaces on port 2593.

Server list

The default server list only includes this one server itself. To create a custom server list, add a server-list section:

<sunuo-config>
  <server-list>
    <game-server>
      <name>Our first server</name>
      <address>1.2.3.4:2593</address>
    </game-server>
    <game-server>
      <name>The second server</name>
      <address>5.6.7.8:2594</address>
    </game-server>
  </server-list>
</sunuo-config>

Features

The "feature" element is used by SunUO to enable features in the core, and possibly in scripts. Unknown feature specifications are ignored. Example:

<sunuo-config>
  <global>
    <feature name="disable-context-menus"/>
    <feature name="prefer-ascii"/>
    <feature name="delocalize"/>
  </global>
</sunuo-config>

The following feature flags are currently recognized by the SunUO core:

Table 3.1. Feature flags

NameDescription
multi-threading enable the multi threaded world save; this gives a significant speed boost if you have more than one CPU core
manual-gc run the CLI's garbage collector manually after world load and world save; this is recommended for Mono's non-generational GC
quick-local-connect do not use two separate connections for login and game play. As a side effect due to a protocol limitation, compression is permanently disabled. Enable this feature if your SunUO server is behind a DNAT gateway. The game server should be configured with its internal IP.
disable-tile-patch don't load mapdif*.mul, stadif*.mul
disable-context-menus disable the client's context menus
prefer-ascii prefer ASCII over Unicode messages whenever possible
delocalize don't send localized messages to the client
age-of-shadows enable AOS features (set Core.AOS)
samurai-empire enable SE features (set Core.SE)
test-center enable test center rules, i.e. players can set stats and skills with the "set" command
allow-docgen enable the [docgen command

Accounting

Disable auto-accounting

By default, everybody can create new accounts by just typing a new user name at login. To disable this, configure:

<sunuo-config>
  <login>
    <auto-create-accounts value="no"/>
  </login>
</sunuo-config>

Limit number of logins per IP

<sunuo-config>
  <login>
    <max-logins-per-ip value="2"/>
  </login>
</sunuo-config>

Limit number of account creations per IP

<sunuo-config>
  <login>
    <max-created-accounts-per-ip value="1"/>
  </login>
</sunuo-config>

Limit number of characters a user can create

<sunuo-config>
  <login>
    <max-chars-per-account value="3"/>
  </login>
</sunuo-config>

Automatic saving

By default, SunUO saves the world every 15 minutes. You can customize this setting; the following example saves every 60 minutes:

<sunuo-config>
  <global>
    <save-interval>60</save-interval/>
  </global>
</sunuo-config>

Encryption

Starting with version 0.2.0, SunUO has out-of-the-box support for encrypted clients, dropping the need to disable encryption in all clients.

The element <encryption> in etc/sunuo.xml is responsible for configuration:

<sunuo-config>
  <encryption>
    <enabled value="yes"/>
    <allow-unencrypted value="no"/>
    <login-key name="6.5.4" key1="0xdeadbeef" key2="0xbeefdead"/>
  </encryption>
</sunuo-config>

The variable enabled enables or disables the encryption code. By modifying allow-unencrypted, you may command SunUO to reject all clients without encryption.

Optionally, you may specify additional login keys with login-key, one element per key. A number of those is already hard-coded in the sources.

Tricks

Separating login server from shard server

To make SunUO ignore the AuthID, configure:

<sunuo-config>
  <login>
    <ignore-auth-id value="on"/>
  </login>
</sunuo-config>

This allows you to run the login server and the shard server on different machines. This is safe, because both check the password independently. It is however important that the account databases on both servers are the same.

SunUO behind a NATted private network

If your SunUO server has a private IP address and it is being accessed via DNAT (sometimes called "port forwarding"), the default server list is incorrect. In this case, you have to explicitly specify a custom server list (as described above):

<sunuo-config>
  <server-list>
    <game-server>
      <name>DSL shard</name>
      <address>dsl-shard.dyndns.org</address>
    </game-server>
  </server-list>
</sunuo-config>

Note that SunUO resolves the host name during server bootup, so if you have a dynamic IP, you probably have to restart the shard after every DSL reconnect.

Working around RunUO bugs

Many of the original RunUO scripts are written in a non-portable way, or just buggy. This section is a collection of workarounds. You do not need to read this section if you did not upgrade from RunUO, since the SunUO scripts have been corrected.

Making [restart work

On Unix / Linux, server restart does not work. This is because .NET assemblies cannot be run directly, you have to call the "mono" wrapper ("mono SunUO.exe"), unless you have BINFMT_MISC configured correctly, but that's a solution for the Linux wizards.

Solution: edit the following files:

./Scripts/Misc/CrashGuard.cs
./Scripts/Misc/AutoRestart.cs
./Scripts/Gumps/AdminGump.cs

And replace:

Process.Start( Core.ExePath );

by:

Process.Start( "mono", Core.ExePath );

Making [restart work with BINFMT_MISC

If your linux kernel supports BINFMT_MISC (check if the file /proc/sys/fs/binfmt_misc/register exists), you don't need to edit scripts. The following command activates BINFMT_MISC for Mono:

echo ':CLR:M::MZ::/usr/local/bin/mono:' > /proc/sys/fs/binfmt_misc/register

You may have to change the path to the mono binary. You should add this command to your startup scripts, because the change is gone after a reboot.

Customized houses

RunUO imports code from zlib.dll on windows. This is done in a non-portable way. To fix this, overwrite overwrite the file Scripts/Misc/ZLib.cs with the version shipped with SunUO.

GDIPlus related crashes

On many Mono installations, libgdiplus is not properly installed. That means that the Reports engine will crash the server. As a workaround, you should turn off the Reports:

<libraries>
  <library name="legacy">
    <ignore-type name="Server.Engines.Reports.Reports"/>
  </library>
</libraries>

The RunUO faction direntry order bug

I reported a bug to the RunUO bug tracker:

http://www.runuo.com/bugs/bug_view_page.php?bug_id=0000304

Basically, Reflector.cs in the faction scripts assumes that types in an assembly are sorted alphabetically, and uses array indices as an identification for factions and faction towns. These are broken when the order of source code on the hard disk changes, which can happen for many reasons (editing with an editor creating backup files).

SunUO 0.1.4 introduced a workaround which sorts the list of file names before passing them to the compiler. Note that this is only a hack; you simply must not make any assumptions on the order of file names on the hard disk.

Arya's auction

Arya's auction was released in the RunUO forum. It is, unfortunately, yet another bugged script library. The following instructions work around these problems:

  1. download the file Auction.1.7.9.zip

  2. unzip it in the script library directory:

    cd local/src
    unzip /tmp/Auction.1.7.9.zip

    This will create the directory ./local/src/Auction/.

  3. the file ./local/src/Auction/AuctionItem.cs is in an invalid text file format which confuses the Mono C# compiler; fix that:

    perl -pi -e 's,\r\n,\n,gs' local/src/Auction/AuctionItem.cs
    perl -pi -e 's,\r,\n,gs' local/src/Auction/AuctionItem.cs
  4. the ZIP file ships the closed-source library Ultima.dll; install this file as a binary script library:

    mv local/src/Auction/Ultima.dll local/lib/

    Now set a dependency to enforce the correct loading order:

    <libraries>
      <library name="Auction">
        <depends name="Ultima"/>
      </library>
    </libraries>
  5. Arya's code uses the type IUsesRemaining, which is not marked as "public". Edit the file ./Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs and make the interface public:

    public interface IUsesRemaining

Logging

SunUO includes the log4net library, which is a very flexible library for logging. SunUO provides a good default configuration, which should be enough for most cases. If you want to do more, please refer to the examples section on the log4net home page.

For scripts authors, the use of log4net is very easy. Add the following declaration at the top of each class body:

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

Now in your code, you may replace Console.WriteLine() with method calls to this log object. The following example demonstrates some of these:

log.Debug("Entering MyMethod");
try {
    if (!foo)
        log.Warn("Foo is disabled, bla");
    int result = DoSomething();
    log.InfoFormat("Did something, result={0}", result);
    if (result < 0)
        log.Error("Invalid foobar");
} catch (Exception e) {
    log.Fatal(e);
}

For more information, read the API documentation.

Chapter 4. Scripts

SunUO consists of two parts: the core, and the scripts. Scripts can be added at runtime, and may contain features like new item types, commands, gumps. They are compiled when SunUO is starting.

The RunUO base scripts are located in ./Scripts/. SunUO further supports to organize additional scripts in "script libraries". The directory structure below ./local/src/NAME/ contains the scripts of the library "NAME". Binary script libraries are loaded from ./local/lib/NAME.dll.

Librares can be configured in ./etc/sunuo.xml, e.g.:

<sunuo-config>
  <libraries>
    <library name="foo">
      <!-- configuration goes here -->
    </library>
  <libraries>
</sunuo-config>

Why script libraries?

Whether you use script libraries is a matter of taste. There are good reasons for doing so:

  • during script development, SunUO only compiles the libraries which have been recently modified instead of everything - which would be much slower

  • less memory is required for compilation

  • putting scripts from several authors into one directory structure becomes a mess sooner or later

  • upgrading a single library to a new version is much easier: delete old script library, unzip new library, done

  • every library can be compiled with its own set of compiler flags, e.g. warning level

Library path

You can specify an arbitrary path where SunUO should compile sources from:

<library name="foo">
  <path>/opt/sunuo/src/foo</path>
</library>

Excludes

<library name="foo">
  <ignore-source name="Bar.cs"/>
  <ignore-type name="Blubb"/>
</library>

This tells SunUO not to compile the file "Bar.cs", and to ignore the type "Blubb". You can use this to disable commands or to disable items in the game.

Disabling a library

<library name="foo" disabled="true"/>

SunUO ignores libraries marked disabled. By default, if no explicit configuration is available, all libraries are enabled.

Dependencies

In many cases, you want to use classes from another script library, but for doing this, the other library has to be loaded before the new library is compiled. To change the order in which libraries are compiled and loaded, you may declare library dependencies:

<libraries>
  <library name="bar">
    <depends name="foo"/>
  </library>
  <library name="foo">
  </library>
</libraries>

This tells SunUO that "bar" imports classes from "foo", and that "foo" has to be compiled and loaded first.

If you do not use the "<depends/>" element, libraries are loaded in random order.

Overlays

To configure RunUO, you need to edit the original RunUO scripts (./Scripts/) often. However, for easier upgrades, it is better to move edited files over to another library and simply replace the files in ./Scripts/ - this method is called "overlay":

<libraries>
  <library name="legacy">
    <overlay name="bar"/>
  </library>
  <library name="bar"/>
</libraries>

Now you can edit the file ./local/src/bar/Misc/ServerList.cs, which is then used instead of ./Scripts/Misc/ServerList.cs.

Taming the warnings

It is obvious that you should pay attention to compiler warnings, as they may reveal bugs which are otherwise hard to find. However, if you are using code from others which emits lots of warnings and the author won't fix them, you might want to disable compiler warnings:

<library name="legacy" warn="0"/>

According to the Mono MCS manual, the default warning level is 2, and 4 is the highest level.

Chapter 5. Troubleshooting

Table of Contents

Getting help

Getting help

There is a mailing list for SunUO support.