
2026/03/06 23:22
**Show HN:Moongate – .NET 10 で構築した Ultima Online サーバーエミュレーター(Lua スクリプティング対応)**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Moongate v2 は .NET 10 をベースに構築された次世代 Ultima Online サーバーで、クリーンでモジュラーなアーキテクチャ、決定論的ゲームループ処理、および堅牢なパケットツールを重視しています。起動時には TCP を使用し、フレーム/パケットを解析し、属性ベースのソース生成(
[PacketHandler(...)])でマッピングし、インバウンド/アウトバウンドイベントバスを介してトラフィックをルーティングします。また、柔軟なサーバーロジックのために Lua スクリプティングもサポートしています。埋め込み HTTP ホストはヘルスチェックと管理エンドポイントを公開し、永続化は軽量なファイルベースモデル(snapshot.world.snapshot.bin + append‑only journal.world.journal.bin)で行い、MessagePack‑CSharp ソース生成でシリアライズされます。起動時にスナップショットを読み込み、その後ジャーナルを再生します。
空間ストリーミングはセクタ/チャンク戦略に従っており、16 × 16 のセクタが設定可能な半径の周囲で遅延ロードされ、メモリ増大と CPU 使用量を制限します。サーバーには対話型コンソール UI、パフォーマンス指標用タイマウィール、および Scriban/Smtp を利用したメールスタックが含まれています。
設定はすべて
MOONGATE_ プレフィックス付き環境変数で上書き可能で、二重アンダースコアを使用したネストされたプロパティもサポートしています。Docker イメージ(tgiachi/moongate:latest)は Native AOT バイナリを提供し、Prometheus/Grafana を用いた監視スタックが stack/ ディレクトリに配置されています。
Moongate は ModernUO、RunUO、および ServUO などのレガシープロジェクトからインスピレーションを得ていますが、独自のコードベースです。GitHub の issue/discussion や Matrix チャットルーム(https://matrix.to/#/#moongate:matrix.org)を通じて貢献者を歓迎しています。本プロジェクトは GPL‑3.0 の下でリリースされ、ビルド・テスト・カバレッジ分析・セキュリティチェックの CI パイプラインが整備されています。
現在サポートしているパケットにはログイン/認証、移動、アイテム相互作用、スピーチ/チャット、ターゲティング、およびさまざまなアウトバウンドゲームプレイパケットがあります。Lua サブシステムはモジュール、関数、イベントフック、視覚効果、Gump フロー、スクリプト ID ディスパッチ、NPC ブレインループをサポートし、
moongate_data/scripts/ からスクリプトをロードします。
今後の作業計画としては、パケット処理の拡張、空間ストリーミングの改善、スクリプティング機能の追加、および Docker イメージと Prometheus/Grafana ダッシュボードを通じた監視強化が挙げられます。GitHub の pull request による貢献は積極的に奨励されています。
本文
Moongate v2 ― .NET 10で構築されたモダンな Ultima Online サーバーです。
クリーン・モジュラーアーキテクチャ
• 強力なパケットツール
• 決定論的ゲームループ処理
• 実用的なテストカバレッジ
コラボレーション
現在、コードレビューや技術指導を特に歓迎しています。
- Issue / Discussions: https://github.com/moongate-community/moongatev2/issues, https://github.com/moongate-community/moongatev2/discussions
- Discord: https://matrix.to/#/#moongate:matrix.org
Moongate は ModernUO、RunUO、ServUO などのクローンではなく、あくまでそれらからインスピレーションを得たものです。
謝辞
| プロジェクト | リンク |
|---|---|
| POLServer | https://github.com/polserver/polserver |
| ModernUO | https://github.com/modernuo/modernuo |
データクレジット
- ワールド装飾(Assets/data/decoration/**) – ModernUO 配布物から
- ワールド位置情報(Assets/data/locations/**) – ModernUO 配布物から
- 看板データ(Assets/data/signs/signs.cfg) – ModernUO から適応
プロジェクト概要
目標
- 正確さとイテレーション速度に重点を置いた保守性の高い基盤
- 明示的でスレッドセーフなネットワーク & ゲームループ境界
- ソース生成された登録付き型安全プロトコルパケット
- AOT にも対応しつつローカル開発フローを維持
ストーリー
背景は https://orivega.io/moongate-v2-rewriting-a-ultima-online-server-from-scratch-because-i-wanted-to/ をご覧ください。
フロントエンド
UI は
ui/ にあり、アイテムテンプレート検索と画像プレビューが可能です。
現在の状態
実装済みの主要機能は以下の通りです。
| 項目 | 詳細 |
|---|---|
| Networking | TCP 起動、パケットフレーミング/解析、 ソース生成、入出力イベントバス。 |
| Game Loop | タイムスタンプ駆動、タイマウィール、オプションのアイドルCPUスロットリング。 |
| Lua Scripting | 実行時エンジン、モジュール/関数バインディング、 生成。 |
| Persistence | スナップショット + ジャーナル(MessagePack‑CSharp)、ファイルロックモード、スレッドセーフリポジトリ。 |
| Scriban テンプレートを備えた最小 SMTP スタック。 | |
| Templates | JSON アイテム/モビールテンプレート;実行時に仕様解決。 |
| Metrics & HTTP | 埋め込み ASP.NET Core ホスト、OpenAPI / Scalar ドキュメント、Prometheus メトリクス。 |
| Background Jobs | スレッド外作業用 と安全なコールバック。 |
ハイライト
- ソース生成されたパケットテーブルとリスナー登録(AOT フレンドリー)。
- 空間セクタ/チャンクストリーミング;予測可能なメモリ使用量。
- ドアジェネレーター (
) は Lua でライブオープン/クロージング。.spawn_doors - ライトサイクルは
に分離。ILightService
アーキテクチャ
src/ ├─ Moongate.Server – ブートストラップ、ゲームループ、ネットワーク ├─ Moongate.Network.Packets – パケット契約とレジストリ ├─ Moongate.Generators – ソースジェネレーター(パケット、ハンドラー、メトリクス) ├─ Moongate.UO.Data – ドメイン型・ユーティリティ ├─ Moongate.Core – 共有ヘルパー ├─ Moongate.Scripting – Lua エンジン & モジュール └─ Moongate.Server/Http – 埋め込み ASP.NET Core ホスト tests/ – 単体テスト benchmarks/ – BenchmarkDotNet スイート docs/ – ドキュメント、計画、プロトコルノート
ソースジェネレーター(AOT)
- パケットテーブル/レジストリ生成。
と[RegisterPacketHandler]
を登録。[RegisterGameEventListener]- ファイルローダー登録 (
)。[RegisterFileLoader(order)] - メトリクススナップショットマッパー。
- スクリプトモジュールレジストリ (
)。[ScriptModule] - バージョンメタデータ。
イベントとパケットの分離
- IPacketListener – 入力パケット → ドメインユースケース。
- IGameEventBusService – ドメインイベントを発行。
- IOutboundEventListener – イベントを受けて送出パケットキューへ投入。
ゲームループは
IOutgoingPacketQueue と IOutboundPacketSender を消費。
コマンドシステム
| パス | 説明 |
|---|---|
| C# ビルトイン | 、。 |
| 動的 / Lua | 。 |
認可
- コンソール:常に Administrator。
- インゲーム:セッションの
を使用。AccountType
例(C# コマンド):
[RegisterConsoleCommand( "whoami|me", "Shows basic identity information.", CommandSourceType.Console | CommandSourceType.InGame, AccountType.Regular)] public sealed class WhoAmICommand : ICommandExecutor { public Task ExecuteCommandAsync(CommandSystemContext ctx) => ctx.Print("You are connected."); }
Lua スクリプト
が実行、定数、コールバックを管理。LuaScriptEngineService
でモジュール登録。[ScriptModule]- スクリプトは
に配置し、moongate_data/scripts/**
は起動時に生成。.luarc.json
例(コールバック):
function on_player_connected(p) log.info("Player connected") end
視覚効果(Lua)
local npc = mobile.get(0x00000030) if npc then npc:SetEffect(0x3728, 10, 10, 0, 0, 2023) end effect.send_to_player(0x00000022, 3613, 2585, 0, 0x3728, 10, 10, 0, 0, 5023)
アイテム ScriptId ディスパッチ
| フック | Lua 関数 |
|---|---|
| single_click | |
| double_click | |
アイテムテンプレート例:
{ "type":"item", "id":"healing_potion", "name":"a healing potion", "itemId":"0x0F0C", "scriptId":"items.healing-potion" }
Lua テーブル
items_healing_potion は on_click, on_double_click を含むことができる。
ガンプ(Gumps)
- ファイルベース:レイアウトテーブル (
)。moongate_data/scripts/gumps/*.lua - ランタイムビルダー:
/gump.create()
。gump.send(...)
例ファイル:
return { ui = { ... }, handlers = { open_next = function(ctx) log.info("Button clicked") end } }
永続化
- スナップショット (
) + ジャーナル (world.snapshot.bin
)。world.journal.bin - MessagePack‑CSharp によるソース生成シリアライズ。
- 操作ごとのチェックサムで整合性保証。
- ファイルロックモード(デフォルト有効)。
起動時:スナップショットを読み込み、ジャーナルを再生。
実行中:ジャーナルへ追記;保存/停止時に新しいスナップショットを書き出し、ジャーナルをリセット。
メール
最小 SMTP スタック:
| サービス | 役割 |
|---|---|
| オーケストレーション |
| Scriban レンダリング |
| SMTP 実装 () |
テンプレートは
moongate_data/email/templates/** に配置。
設定
すべての設定は
MOONGATE_ プレフィックス付き環境変数で上書き可能。ネストプロパティはダブルアンダースコア
__ を使用。
例:
MOONGATE_HTTP__PORT=8088 MOONGATE_SPATIAL__SECTOR_ENTER_SYNC_RADIUS=3
サポートグループ:Core, HTTP, Game, Metrics, Persistence, Spatial, Scripting, Email。
Docker
./scripts/build_image.sh -t moongate-server:local docker run --rm -it \ -p 2593:2593 -p 8088:8088 \ -v /path/host/moongate-root:/app \ -v /path/host/uo-client:/uo:ro \ --name moongate moongate-server:local
で実行すると-it
プロンプトが表示。moongate>- フロントエンドは
からビルドされ、HTTP 経由で配信。ui/
ベンチマーク
ローカル実行例:
./scripts/run_benchmarks.sh --filter '*'
主要指標(サンプル):
| ベンチマーク | 平均 | 割り当て |
|---|---|---|
| PacketParsingBenchmark.ParseLoginSeedPacket | 94.82 ns | 664 B |
| SpatialWorldServiceBenchmark.AddOrUpdateMobiles (500) | 75.939 µs | 74.56 KB |
完全レポートは
BenchmarkDotNet.Artifacts/results/ にあります。
ストレステスト
dotnet run --project tools/Moongate.Stress \ --host 127.0.0.1 --port 2593 \ --http http://localhost:8088 \ --clients 100 --duration 300 --ramp-up-per-second 10
SLO:
- ログイン成功率 ≥ 99%
- 予期せぬ切断なし
- 移動 ACK p95 < 200 ms
コントリビューション
- リポジトリをフォーク。
- フィーチャーブランチ作成。
を実行し、すべてのテストがパスすることを確認。dotnet test- 明確な説明付きでプルリクエストを送信。
すべてのコードはプロジェクトのコーディング規約に従い、適切なテストを含める必要があります。
ライセンス
GNU General Public License v3.0 – 詳細は LICENSE をご覧ください。