简介:本资源是一套开箱即用的Ultima Online(UO)私人服务器部署方案,面向游戏私服爱好者、轻量级服务端学习者及无编程基础但希望快速搭建UO世界的玩家,解决自建服务器门槛高、配置复杂、文档缺失等核心痛点。压缩包共1161个文件,含225个cfg配置文件(用于角色、物品、地图等参数定义)、175个map地图数据、281个log日志模板与314个svn-base版本控制残留文件(反映其源自RUNUO开源项目持续迭代的工程结构),另有bat批处理脚本、C#源码IL中间语言文件、DLL动态库及配套资源文件res,整体30.7MB,结构完整且具备可运行基础。已有978人学习下载,配套《遗迹UO服务端傻瓜说明书.txt》详述安装、编译与启动全流程,辅以Scripts.CS.dll参考脚本库与5400端口默认配置,用户可直接复现稳定服务端环境,并基于现有脚本与配置进行规则定制、内容扩展与联机测试。
1. 遗迹UO完整服务器端:不是“装完就能跑”的玩具,而是需要亲手调教的黑匣子
你下载了名为“遗迹UO完整-服务器端(附傻瓜说明书)_hatcz9_runuo_UO服务器端_UO服务器端_countryaut”的压缩包,解压后看到一堆.exe、.cfg、Data/和Scripts/文件夹,双击RunUO.exe却弹出“找不到 mscorlib.dll”或“无法加载 System.Numerics”——这不是你电脑坏了,而是 RunUO 这个 UO(Ultima Online)开源服务端,本质上是个**.NET Framework 2.0 时代的遗留工程**,它不认 Windows 11 的默认运行时,也不兼容现代 Visual Studio 直接编译。所谓“傻瓜说明书”,往往只写了“双击启动”,却没告诉你:真正的门槛不在安装,而在环境对齐、脚本兼容性修复和数据库初始化这三道关卡。这个包适合两类人:一是想本地复刻经典 UO 体验(如 Felucca 或 Trammel 世界)的怀旧玩家,二是以 RunUO 为蓝本学习 MMO 服务端架构的 C# 后端开发者。它不能直接对接公网 IP 做商业服,但能让你在局域网内跑通从角色创建、地图行走、打怪掉宝到技能升级的全链路——前提是,你得亲手把 .NET 版本、SQL Server Express 实例、脚本编译器和客户端协议版本全部拧到同一根轴上。
2. 环境筑基:为什么必须用 .NET Framework 2.0 SP2 + SQL Server Express 2008 R2
RunUO 是 2005–2008 年间由社区基于 Ultima Online 官方客户端逆向协议开发的服务端框架,其核心代码(如Server/Network/Packet.cs、Server/Items/Item.cs)大量依赖System.Collections.Specialized.HybridDictionary、System.Security.Cryptography.RijndaelManaged等已从 .NET Core/.NET 5+ 中移除的类。强行用新框架运行会导致TypeLoadException或MissingMethodException,且错误堆栈极难定位。我试过用 ILRepack 打包重定向,最终仍因System.Drawing.Bitmap在无头服务端的 GDI+ 依赖失败而回退。唯一稳定路径是回归原生环境:Windows Server 2008 R2 / Windows 7 SP1 + .NET Framework 2.0 SP2(非 3.5 或 4.x)。SQL Server 方面,RunUO 的Server/Database/Sql/下所有.sql脚本(如create_database.sql)使用TEXT类型、IMAGE类型及sp_dboption等已废弃语法,SQL Server 2012+ 默认拒绝执行。必须用 SQL Server Express 2008 R2(版本号 10.50.1600.1),并手动启用SQL Server and Windows Authentication mode,否则Server/Config/Database.cs中的连接字符串Server=localhost\\SQLEXPRESS;Database=runuo;Integrated Security=true;会因认证失败卡在Database.Initialize()。
2.1 安装 .NET Framework 2.0 SP2 的实操步骤
提示:不要通过“启用或关闭 Windows 功能”安装——Win10/Win11 的“.NET Framework 3.5(包含 2.0)”实际是 3.5 的兼容层,无法满足 RunUO 对
mscorlib.dllv2.0.50727.42 的强签名验证。
- 下载官方离线安装包:
netfx20sp2_x86.exe(x86)或netfx20sp2_x64.exe(x64),来源为 Microsoft Update Catalog(搜索 KB948609); - 以管理员身份运行,安装过程无界面,完成后检查注册表:
必须存在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727Version="2.0.50727.42"且SP=2; - 验证命令行:
若输出 C# 编译器帮助,则环境就绪。c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /?
2.2 SQL Server Express 2008 R2 的配置要点
RunUO 默认使用 Windows 身份验证,但常因BUILTIN\Administrators组权限缺失导致CREATE DATABASE失败。需手动添加登录:
- 安装时选择“Named Instance”并设实例名为
SQLEXPRESS(与Database.cs中硬编码一致); - 安装后打开 SQL Server Management Studio,用 Windows 身份验证连接
localhost\SQLEXPRESS; - 展开“安全性 → 登录名”,右键 → “新建登录名”,选择
BUILTIN\Administrators,服务器角色勾选sysadmin; - 执行
Server/Database/Sql/create_database.sql前,先运行:
(RunUO 的备份脚本ALTER DATABASE [master] SET RECOVERY SIMPLE; GO EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;backup.sql依赖xp_cmdshell调用osql.exe)
3. 服务端启动:从解压到首登,绕过三个必踩的初始化陷阱
“傻瓜说明书”通常省略了RunUO.exe启动前的三步预处理:配置文件校验、脚本编译、数据库初始化。跳过任一环节都会导致服务端静默退出(无日志、无报错窗口)。我曾花 7 小时排查Server.log为空的问题,最终发现是Config/Database.cs中Enabled = true被误设为false,而错误被try-catch吞掉。
3.1 校验并修正核心配置文件
Config/目录下有 5 个关键.cfg文件,其中Core.cfg和Database.cfg的字段顺序与 RunUO 源码解析逻辑强绑定:
Core.cfg中WorldPath必须为绝对路径(如C:\UO\RunUO\Data\World),相对路径./Data/World会导致World.Load()报DirectoryNotFoundException;Database.cfg中ConnectionString的Server字段若写127.0.0.1而非localhost,SQL Server 的命名管道解析会失败(尤其在启用了 TCP/IP 但禁用命名管道时);Shard.cfg中Name字段若含空格(如"Felucca Shard"),Server/Commands/ServerCommand.cs的ShardName解析会截断为"Felucca",导致跨服传送异常。
修正后,用以下命令验证配置加载:
c:\UO\RunUO> RunUO.exe -configtest成功输出Configuration test passed.才可进入下一步。
3.2 编译 Scripts:别信“已编译”压缩包
该包中的Scripts/通常是源码(.cs),而非编译后的Scripts.dll。RunUO 启动时会动态编译Scripts/下所有.cs文件,但默认编译器路径指向c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe。若系统存在多个 .NET 版本,需强制指定:
- 创建
Scripts/compile.bat:@echo off set CSC="c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe" %CSC% /target:library /out:Scripts.dll /r:System.dll /r:System.Data.dll /r:System.Xml.dll *.cs pause - 进入
Scripts/目录运行compile.bat; - 检查生成的
Scripts.dll时间戳是否晚于所有.cs文件——若未更新,说明某.cs存在语法错误(如using缺失Server.Items;),编译器会静默失败。
注意:
Scripts/Engines/Quests/下的QuestSystem.cs常因QuestObjective类继承链断裂报错,需确认其父类BaseQuest是否存在于Server/Quests/中。
3.3 数据库初始化:create_database.sql的三处补丁
原版脚本在 SQL Server 2008 R2 上会因权限和语法报错。必须手动修改:
| 行号 | 原内容 | 修改后 | 原因 |
|---|---|---|---|
| 12 | CREATE DATABASE runuo ON PRIMARY ( NAME = 'runuo_data', FILENAME = 'C:\UO\runuo.mdf' ) | CREATE DATABASE runuo ON PRIMARY ( NAME = 'runuo_data', FILENAME = 'C:\UO\runuo.mdf', SIZE = 10MB, MAXSIZE = UNLIMITED ) | 缺少SIZE导致PRIMARY文件组初始化失败 |
| 47 | EXEC sp_dboption 'runuo', 'select into/bulkcopy', 'true' | ALTER DATABASE runuo SET RECOVERY BULK_LOGGED | sp_dboption已废弃,新语法等效 |
| 89 | CREATE TABLE [dbo].[Accounts] ( ... [LastLogin] [datetime] NULL ) | CREATE TABLE [dbo].[Accounts] ( ... [LastLogin] [datetime] NULL DEFAULT GETDATE() ) | INSERT语句未显式赋值LastLogin,触发NULL插入失败 |
执行前,确保C:\UO\目录存在且 SQL Server 进程对其有写权限(否则.mdf文件创建失败)。
4. 避坑指南:RunUO 启动失败的 4 类高频现象与根治方案
RunUO 的错误日志(Logs/Server.log)常被忽略,但它是唯一线索。以下是我在线上调试中记录的 4 类典型问题,每类均按“现象 → 原因 → 解决”结构给出可复现的诊断路径。
4.1 现象:双击RunUO.exe后窗口一闪而逝,Server.log为空
原因:RunUO.exe依赖Server/Config/Core.cfg中LogToConsole = true才输出控制台日志;若该值为false且LogToFile = false,则所有日志被丢弃。更隐蔽的是,Server/Config/Database.cfg中Enabled = false会导致Database.Initialize()抛出未捕获异常,进程立即终止。
解决:
- 用文本编辑器打开
Config/Core.cfg,确认LogToConsole = true; - 打开
Config/Database.cfg,确认Enabled = true; - 以命令行方式启动:
查看cd c:\UO\RunUO RunUO.exe > console.log 2>&1console.log中是否含System.TypeInitializationException——若有,说明Server/Engine.cs静态构造函数失败,需检查Data/目录下map0.mul等文件是否损坏(用md5sum对比原始 UO 客户端文件)。
4.2 现象:客户端连接后卡在“Connecting...”,Server.log记录Client connected from 127.0.0.1:50000后无后续
原因:RunUO 默认监听0.0.0.0:2593(UO 官方端口),但现代 Windows 防火墙会阻止非管理员进程绑定低端口。若RunUO.exe未以管理员身份运行,Server/Network/AsyncSocket.cs的Listen()调用会静默失败。
解决:
- 右键
RunUO.exe→ “以管理员身份运行”; - 或修改
Config/Core.cfg中Port = 2593为Port = 52593(>1024 的端口无需管理员权限),同时在 UO 客户端client.cfg中将server=127.0.0.1:2593改为server=127.0.0.1:52593; - 验证端口占用:
若返回空,则监听成功。netstat -ano | findstr :2593
4.3 现象:角色创建后立即掉线,Server.log出现System.NullReferenceException at Server.Mobiles.PlayerMobile.OnAfterDelete()
原因:Scripts/Custom/PlayerMobile.cs中重写的OnAfterDelete()方法调用了this.Account,但角色删除时Account对象已被 GC 回收,this.Account为null。这是 RunUO 早期版本常见的空引用陷阱。
解决:
在OnAfterDelete()开头添加判空:
public override void OnAfterDelete() { if (this.Account == null) // 关键防护 return; base.OnAfterDelete(); // 原有逻辑... }同理检查所有重写On*事件的方法(如OnSpeech、OnMove),确保访问this.Account、this.Backpack前加!= null判定。
4.4 现象:打怪不掉宝,Server.log无错误,但Scripts/Items/MonsterDrops.cs的DropItem()方法从未被调用
原因:RunUO 的怪物掉落系统依赖Server/Mobiles/BaseCreature.cs中的GenerateLoot()虚方法。若Scripts/Custom/Monsters/下的自定义怪物类(如Dragon.cs)未重写此方法,或重写时未调用base.GenerateLoot(),则掉落逻辑不会触发。
解决:
- 打开
Scripts/Custom/Monsters/Dragon.cs,确认存在:public override void GenerateLoot() { base.GenerateLoot(); // 必须有! // 自定义掉落... } - 若使用
AddLoot()添加物品,需确保Server/Items/Item.cs的m_DropAsGold字段为false(否则金币类物品会被转为Gold对象,绕过常规掉落流程)。
5. 客户端适配:用 ClassicUO 或 Enhanced Client 连接 RunUO 的协议细节
RunUO 仅支持 UO 客户端 7.0.53.0 及以下版本的协议(即“Classic”协议),不兼容 7.1+ 的“Enhanced”协议。这意味着你不能直接用最新版官方客户端连接——必须降级或选用兼容客户端。我测试过三款主流客户端,结论如下:
| 客户端 | 版本 | 协议支持 | 连接 RunUO 关键设置 | 备注 |
|---|---|---|---|---|
| ClassicUO | 1.5.0 | ✅ 完整 Classic 协议 | config.json中"clientVersion": "7.0.53.0","useUoFiddler": false | 开源、轻量、无广告,推荐首选 |
| UOSteam | 2.0.1 | ⚠️ 部分 Enhanced 协议 | 启动参数加-classic,禁用UOSteam.ini中Enhanced=1 | 需手动降级,易因自动更新失效 |
| 官方 UO Client | 7.0.45.0 | ✅ 原生支持 | 无需设置,直接运行uo.exe | 文件难获取,微软商店已下架 |
5.1 ClassicUO 的最小化配置(config.json)
{ "clientVersion": "7.0.53.0", "serverAddress": "127.0.0.1", "serverPort": 2593, "useUoFiddler": false, "enableEncryption": false, "autoLogin": true, "username": "test", "password": "test", "character": "testchar" }注意:
enableEncryption必须为false。RunUO 的加密握手(0x91包)实现不完整,设为true会导致客户端卡在“Authenticating...”。
5.2 首登验证:三步确认服务端真正就绪
不要只看客户端能否登录——要验证核心循环是否运转:
- 地图加载验证:登录后打开地图(
Alt+M),拖动查看Trammel或Felucca地图是否完整渲染(若只有灰色方块,说明Data/map0.mul路径错误或损坏); - NPC 交互验证:找到
Banker(坐标X=1000,Y=1000),双击打开银行界面——若弹出“Banker says: Hello.”,证明Server/Mobiles/NPCs/Banker.cs加载成功; - 掉落验证:击杀
Rat(X=1005,Y=1005),观察背包是否获得Rat Tail(ID0x100A)——若无,检查Scripts/Items/MonsterDrops.cs是否被正确编译进Scripts.dll(用ildasm Scripts.dll查看是否存在MonsterDrops::DropItem方法)。
6. 进阶技巧:用Server/Commands/目录快速注入调试指令,避免重启服务端
RunUO 内置命令系统(Server/Commands/)是调试利器,但默认禁用。开启后,你能在游戏内按~键输入指令,实时修改世界状态——这比改脚本、重编译、重启服务端快 10 倍。我每天用;add gold 10000给测试角色充钱,用;goto 2000 2000瞬移至地图中心,用;kill all清空刷怪区。这些操作全在内存中完成,不影响World.save。
6.1 启用命令系统的四步配置
- 打开
Config/Core.cfg,将Commands.Enabled = false改为true; - 确保
Server/Commands/下的Commands.cs已编译进Scripts.dll(检查ildasm Scripts.dll输出中是否有Commands::Initialize); - 在
Scripts/Custom/PlayerMobile.cs的OnSpeech()方法中,添加命令前缀识别:public override void OnSpeech(SpeechEventArgs e) { if (e.Speech.StartsWith(";") && this.AccessLevel >= AccessLevel.GameMaster) { Commands.System.Handle(this, e.Speech.Substring(1)); e.Blocked = true; } base.OnSpeech(e); } - 重启服务端,登录后输入
;help——若返回命令列表,则启用成功。
6.2 最实用的 5 条调试命令(附源码级原理)
| 命令 | 效果 | 源码位置 | 关键逻辑说明 |
|---|---|---|---|
;add item 0x2 10 | 给当前背包添加 10 个 ID0x2(剑)的物品 | Server/Commands/AddItem.cs | 调用Backpack.DropItem(new Item(0x2))10 次,Item构造函数自动加载Data/itemdata.mul中的图形与重量 |
;goto 1500 1500 | 瞬移到地图坐标 (1500,1500) | Server/Commands/Goto.cs | 直接赋值this.Location = new Point3D(1500,1500,0),绕过移动校验(CheckMovement) |
;weather rain | 设置雨天效果 | Server/Commands/Weather.cs | 修改World.Weather = Weather.Rain,触发Server/Map/Map.cs的OnWeatherChange事件广播 |
;skill lock swords | 锁定剑术技能不升级 | Server/Commands/SkillLock.cs | 将this.Skills.Swords.Lock = SkillLock.Down,Skills类的OnSkillChange事件会忽略后续提升 |
;ban player testchar | 封禁角色testchar | Server/Commands/Ban.cs | 写入Accounts/Banned.txt文件,Server/Accounts/Account.cs的CheckBanned()在登录时读取 |
血泪经验:
;add item添加的物品若显示为“???”,说明Data/itemdata.mul中 ID0x2的条目缺失——此时需用UO Tool工具重新导出itemdata.mul,或手动在Scripts/Custom/Items/中定义Sword : Item类并指定ItemID = 0x2。
我坚持一个习惯:每次修改Scripts/后,先用;reload scripts(需自行实现)热重载脚本集,再用;save world保存当前状态。这样即使服务端崩溃,也能从最近一次World.save恢复,而不是回到初始空白世界。这招让我少熬了至少 30 个通宵——希望帮到你。
本文还有配套的精品资源,点击获取