ハクソク

世界を動かす技術を、日本語で。

Show HN: Moongate – .NET 10でのLuaスクリプトを使用した「Ultima Online」サーバーエミュレーター

概要

Moongate v2は、.NET 10で構築された最新のUltima Onlineサーバープロジェクト
クリーンでモジュール化されたアーキテクチャと強力なパケットツールを実現
テストカバレッジや決定論的なゲームループ処理を重視
コラボレーターやコードレビュー協力者を積極的に募集
GitHubやDiscord、Matrixでの参加を歓迎

Moongate v2 概要と特徴

  • Moongate v2は、.NET 10ベースの最新Ultima Onlineサーバーエミュレーター
  • クリーンかつモジュール化されたアーキテクチャ設計
  • パケットツーリング強化、ゲームループの決定論的処理
  • 実用的なテストカバレッジ確保を目指す
  • NativeAOT対応による単一ネイティブバイナリ化
  • Luaスクリプティングによる柔軟なゲームロジック拡張
  • React製管理UI埋め込みHTTP管理APIを提供
  • 自動ドア生成(ModernUO/RunUO同等アルゴリズム)

コラボレーター募集

  • GitHub Issue/Discussionで参加表明・相談が可能
  • DiscordMatrix Roomでディスカッション参加歓迎
  • コードレビューや設計議論への協力を特に希望
    • Issues: https://github.com/moongate-community/moongatev2/issues
    • Discussions: https://github.com/moongate-community/moongatev2/discussions
    • Matrix: https://matrix.to/#/#moongate:matrix.org

既存サーバープロジェクトとの関係

  • ModernUO, RunUO, ServUO等のクローンではなく、独自路線
  • これらのプロジェクトから多大なインスピレーションと技術的知見を得ている
  • POLServer, ModernUOの貢献者・チームへの特別な感謝
  • 一部データセット(デコレーション、ロケーション、サイン)はModernUOからインポート・適用

プロジェクト目標

  • 保守性・正確性・開発速度を重視したUOサーバー基盤の構築
  • ネットワーク層とゲームループの明確な境界とスレッドセーフ実装
  • 型安全なパケット定義ソース生成による自動登録
  • **AOT(Ahead-Of-Time)**対応を意識しつつ、ローカル開発の快適さも両立

主な実装済み機能

  • TCPサーバー起動・接続ライフサイクル管理
  • パケットフレーミング/パース(固定・可変長両対応)
  • 属性ベースパケットマッピングとソース生成
  • ネットワーク→ゲームループ間のメッセージバス設計
  • ドメインイベントバスによるイベント駆動設計
  • セッション分離(トランスポートとプロトコル/ゲームプレイ)
  • コア挙動・パケット基盤のユニットテスト
  • Luaランタイム(コマンド、関数バインディング、.luarc生成)
  • 埋め込みHTTPホストによる管理エンドポイント・OpenAPIドキュメント
  • スナップショット+ジャーナル型永続化(MessagePackソース生成)
  • SpectreベースのカラーログUIとインタラクティブコンソール
  • タイマー・ゲームループスケジューリングとメトリクス
  • リージョン・セクター管理(ModernUO基準、JSON多態ロード対応)
  • メール送信機能(Scribanテンプレート+SMTP)
  • A*パスファインディング(Lua移動プリミティブで利用)
  • ライトサイクル管理とLuaコマンド連携
  • Luaコマンドスクリプト(moongate_data/scripts/commands/gm 配下)

最近の開発トピック

  • 永続化シリアライズをMemoryPack→MessagePack-CSharpに移行(AOT安定化)
  • アウトバウンドパケット送信の専用ネットワークスレッド分離
  • 空間・ゲームループの高速化(割当最適化)
  • ライトサイクルロジックの独立サービス化
  • 新GMコマンドスクリプト追加(.eclipse, .set_world_light, .teleports等)

空間チャンク戦略

  • セクター/チャンクベースのワールドストリーミングアプローチ
  • 16x16セクター単位でデータをインデックスし、遅延ロード
  • プレイヤーログインやセクター移動時にスナップショット送信
  • 未使用エリアはアンロードしメモリ効率向上
  • 予測可能なメモリ増加・CPU負荷低減・スケーラビリティ向上
  • Minecraft的チャンクストリーミングに近い実装哲学

ワールド生成パイプライン

  • IWorldGeneratorベースのパイプライン設計
  • DoorGeneratorBuilderによるドア自動生成(ModernUO方式)
  • Lua+DoorServiceでドアの開閉をライブ制御
  • .spawn_doorsコマンドで手動ドア生成も可能

UOプロトコル対応状況

  • 現状対応済み
    • ログイン/認証、キャラクター、移動、アイテム操作、チャット/スピーチ、ターゲティング、ステータス、Ping、ツールチップ等
  • サブコマンド対応
    • パーティ、ステータスロック、ターゲットアイテム/スキル/スペル
  • アウトバウンドパケット
    • セッション管理、ワールド同期、移動・時間、環境効果、UI/スピーチ等
  • 部分実装
    • プロトコルモデルのカバレッジは広いが、実際のゲームプレイフローへの接続は一部のみ
    • アイテム関連は基本動作のみ、トレードや経済は拡張中
    • Lua統合済みだが、ゲームシステムのスクリプト化は今後強化
  • 未実装(主要領域)
    • 戦闘ループ、スキルシステム、NPC AI、ベンダー、経済、ハウジング、ボート、天候、完全なUOプロトコルカバレッジ等

永続化

  • スナップショット+ジャーナル型ファイル永続化
    • world.snapshot.bin(完全チェックポイント)
    • world.journal.bin(増分操作記録)
  • MessagePack-CSharpによる高速・コンパクトなバイナリシリアライズ
  • ファイルロック・スレッドセーフリポジトリ
  • 起動時にスナップショット+ジャーナル再生
  • AOT安定化のため永続化基盤を刷新
  • クエリAPI(ZLinqによるスナップショット投影・フィルタリング)

メール送信(SMTP)

  • IEmailServiceによる一元オーケストレーション
  • Scribanテンプレート+SMTP実装
  • NoOpEmailSenderでメール無効化時も安全
  • テンプレート・変数管理と外部連携

なぜModernUO/RunUOを使わないのか

  • 既存プロジェクトは成熟かつ実績十分
  • 独自設計思想(ネットワーク/ドメイン厳密分離、イベント駆動ゲームループ、継承中心アイテム階層の排除、Luaによる高速反復開発)を追求したかったため

参加・貢献方法

  • GitHubでソースコード・ドキュメント公開
    • https://github.com/moongate-community/moongatev2
  • Issue/Discussion/Discord/Matrixでの参加歓迎
  • コードレビュー・設計議論・実装協力を重視

このプロジェクトはまだ初期段階ですが、堅牢な基盤将来の拡張性を重視しています。UOサーバー開発やアーキテクチャ設計に興味のある方は、ぜひご参加ください。

Hackerたちの意見

あなたのロゴ、めっちゃ好きです!完成したものの進捗を見せるYouTubeチャンネルはありますか?
ありがとう!ロゴは偶然の産物なんだ。シンプルで、元のゲームのムーンゲートみたいな感じを出したかったんだよね。動画はあんまり得意じゃないけど、今のところ動いてるのは、ログインフロー、キャラクター作成、デルタセクター同期のワールド移動、マップの静的オブジェクトから自動生成されるドア(ちゃんと開くよ)、アイテムの動作に対するLuaスクリプト、スナップショットの永続性、サーバー管理用のReact管理UIだよ。いつかREADMEに短いデモのGIFか動画を追加するかもしれないけど、今はクローンして実行するのが一番の見方だね。
PvPGNのこと、覚えてるよ。まだ存在してると思うよ。https://github.com/D2GSE/pvpgn-server
UOは「一般人」プレイヤーがいる唯一のゲームだったな。多くのプレイヤーはスケールアップできなかったり、最高の装備を手に入れられなかったりしたけど、弱いプレイヤーでも楽しめるゲームだったから、みんな続けてた。すごく強いプレイヤーは有名人みたいだったし、今のゲームとは全然違うよね。今のゲームでは、プレイヤーがみんなマーベルのスーパーヒーローみたいに見えるし。
これは本当にいい観察だね。UOには本物の経済と社会的階層があった。力は自分で手に入れるものだったからね。漁師や仕立て屋として何ヶ月も過ごしても、意味のある体験ができた。フルプレートのグランドマスター剣士と、ブリタニアの銀行で魚を売ってる人とのギャップはすごく大きかったけど、どちらも楽しんでた。今のMMOは、みんな同じアトラクションに乗るテーマパークみたいなもので(課金で勝てる)、UOは自分の選んだことから役割が生まれる生きた世界だったんだ。クエストマーカーに次に行く場所を教えてもらうんじゃなくてね。
伝説の鍛冶屋になることがゲームの本質だった。クラフターにとって、クラフトがエンドゲームの状態だったんだ。生産された装備は最大耐久、最大ダメージ、最大防御力だった。お城の家具はどこかの誰かから来なきゃいけなかった。ゲームの目的はこのファンタジー世界で生きることで、クリアすることじゃなかった。クエストもなければ、敵もいない。ただ善と悪、そしてその間の人たちがいるだけ。スタジオがこれを心に留めて、またこんなものを作ってくれたらいいな。マインクラフトはこのサンドボックスの性質で爆発的に人気になったけど、プレイヤーにはシャベルとバケツを渡さないとね。
Haven and Hearthには「スプルースキャップ」と「隠者」がいるよね。このゲームのエリートは、グループで働くこと、孤立したプレイヤーに対して暴力を使うこと、自動化を使うことを厭わない人たちから生まれるんだ。15年間MMORPGには時間を費やしてないけど、普通のプレイヤーが憧れるような「排他的」なギルドはまだあるんじゃない?
UOは俺にとって最高のオンラインゲームだった。他のゲームはその影に隠れてる感じ。自由度が一番高くて、ゲーム化されてないところが魅力だった。EverquestやWorld of Warcraftも好きだけど、あれは俺には「生々しさ」が足りなかった。The Realmは、俺の中でのベストMMOのダークホースだね。(はいはい、Meridian 59やUnderlightもね)
このビジュアルに関しては共感できるな。>「現代のゲームとは全然違って、各プレイヤーがマーベルのスーパーヒーローのファンタジーバージョンみたいに見える」でも、これはほとんどのゲームに当てはまるんじゃない?>「UOは、俺が今までプレイした中で唯一「一般市民」のプレイヤーがいたゲームだった。多くのプレイヤーはスケールアップできなかったり、一流の装備を手に入れられなかった。」俺が思い浮かべてるのはPath of Exileかな。普通のプレイヤーとトップティアの間にはものすごい差があるよね。トップティアじゃなくても、熱心なプレイヤーとの違いも大きいし。ほとんどの人が一流の装備を持たないのは、ほぼ定義上そうだよね?
うん、これには本当に同意する。UOは「エンドゲームコンテンツ」を追い求めなかった。それが今のマルチプレイヤーゲームの厄介なところだと思う。デザイナーたちはみんなが最大レベルに達して、最終的にはみんな同じになることを期待してるから。
当時の俺の好みは、家に忍び込んだり、盗んだり、無防備な人を襲ったりすることだったな(特に墓地やダンジョン、鉱山で)。戦闘前に誰かのバッグから攻撃魔法の材料を盗むのは、質の高いインタラクションがたくさんあった。UOがトラメルを導入した日は悲しかったよ。
UOをプレイする喜びを追い続けるつもりだ。仕事を辞めて24時間プレイしたい!
実際そんなに難しかったの?俺はJP/KRのアジアサーバーでPK/APK/PVPギルドに入ってたから、もしかしたら自分のバブルだったかもしれないけど、7つのスキルをマックスにしてるプレイヤーは結構見かけたよ。確か、スパーリング、剣士かフェンシング、魔法、魔法抵抗だったかな。残りは覚えてないけど。今のゲームみたいにすぐに簡単にできるわけじゃないけど、お互いのサブキャラをパワーレベルさせ合って、7つのスキルをマックスにするのに2週間くらいかかったかな?ギルドハウスにクマを閉じ込めて、レスリングや他の戦闘スキルをパワーレベルさせてたんだ。
Blizzardが40人のハードコアレイドを潰す前のバニラWoWみたいだね。サーバー全体でトップギアを持ってるギルドはほんの数えるほどしかなかった。
わお!これは大したもんだね…貢献グラフ[0]を見てるけど、これ全部一人でやったの?この取り組みは、16年前にすごく才能のある開発者「aaerox」が始めたインファントリーオンラインのサーバーエミュレーターにすごく似てるよ。オリジナルのsvnコミットをSourceforgeで見つけたよ[1]。今はGitHubに移ってるけど、16年間アクティブで、君が作ったのと同じ機能がたくさんあって、15年以上にわたって12人以上の開発者が関わってるんだ。すごいね。どうやってそんなに多くのことを一人でやり遂げたのか、ぜひ教えてほしいな。[0] https://github.com/moongate-community/moongatev2/graphs/cont... [1] https://sourceforge.net/p/infserver/code/1/
そうそう、最初のmoongateの試みからほとんどのインフラを引き継いだんだ(https://github.com/moongate-community/moongate、これはひどい結果になったけど、https://github.com/tgiachi/Primaも同様に)。そこから、基盤を素早く構築するための良いスタート地点ができた。Luaスクリプトの部分は別のプロジェクト(https://github.com/tgiachi/Lilly.Engine)で既にやってたし。Codexがテストや機能の実装、テストの作成を手伝ってくれたから、少なくともいいスパーリングパターンがあるよ。データインポートの部分(FileLoadersって呼んでる)では、ModernUOのロジックを使った。アイテムの部分では、POLからアイテムをインポートするスクリプト(scripts/dfn_*.sh)を作った!褒めてくれてありがとう!俺は一度何かにハマると、それが obsession になっちゃうタイプなんだよね!
あ、言い忘れたけど、Reactでのウェブ部分は全部Codexがやったんだ。俺はフロントエンドの開発が大嫌いなんだよね!
すごくクールなプロジェクトだね。MMOのサーバーコードベースは時間が経つにつれてアーキテクチャの複雑さが増すから、ネットワークとゲームロジックのクリーンな分離から始めるのは理にかなってる。セクターごとのデルタ同期について気になるんだけど、プレイヤーがアイテムやモバイルがたくさんある忙しいエリアに入ったとき、パケットバーストをどうやって避けてるの?NativeAOTが使われてるのも面白いね。これは主にデプロイの簡素化のため?それともパフォーマンスのため?
>「セクターごとのデルタ同期について気になるんだけど、プレイヤーがアイテムやモバイルがたくさんある忙しいエリアに入ったとき、パケットバーストをどうやって避けてるの?」そこではパケットバーストを防ぐための特別な仕組みはあまりなさそうだね、賢い近接セクターのロードくらいしか。境界で作業してる。最近、似たようなプロジェクトでネットバーストを減らすためのフラスタムスポーンに取り組んでたから、次のセクターを事前に温めるための方法として何か似たようなものが使われてるのか気になってたけど、特に何も見つけられなかった。楽しくて読みやすかったよ。OPと親に感謝してる。
ありがとう!そう、主な動機の一つはまさにそれだったんだ。レガシーなUOのコードベースで、ネットワーク、永続性、ゲームロジックが深く絡み合ってた何年も後、クリーンスレートアプローチが現代の.NETでどうなるか見てみたかった。セクター同期のバーストについては、今まさに調整中なんだ。プレイヤーが新しいセクターに入ると、周囲のセクターの地面アイテムとモバイルをすべて同期する(設定可能な半径)。忙しいエリアでは、一度にたくさんのパケットが発生することになる。現在のアプローチは: - セクターに入るときの同期は、プレイヤーがすでに見ていないデルタセクターだけを送信するから、隣接セクターに移動するだけで全てを再同期するわけじゃない - プレイヤーに近いセクター(中心から1以内)は常に再同期される。UOクライアントは視覚範囲外のアイテムを静かにドロップするから(約18タイル)、プレイヤーが戻ってきたときに再送信する必要がある - アウトゴーイングパケットキューが実際の送信を処理するから、ゲームループはネットワークI/Oを待ってブロックされない。とはいえ、優先順位をつける余地は確かにある(モバイル優先、その後近くのアイテム、遠くのアイテム)し、同期を一度のバーストではなく複数のティックに分散させることもできる。これはロードマップに載ってる。NativeAOTについては、正直、両方だね。シングルバイナリのデプロイはDockerにとって素晴らしい(小さいイメージ、即時起動)けど、本当の利点は予測可能なパフォーマンス。JITのウォームアップもないし、セッション中にコンパイルのサプライズもない。一定のティックタイミングが大事なゲームサーバーでは、その変数を排除する価値がある。トレードオフとして、いくつかのランタイムの柔軟性は失うけど、ソースジェネレーターがそのギャップのほとんどを埋めてくれる(パケット登録、シリアル化など)。
これって何かの前兆かな?今週、YouTubeでMajuularの動画をいくつか見たばかりなんだ(めっちゃおすすめ!)ウルティマシリーズ、特に『ウルティマ アンダーワールド:ザ・スティジアン・アビス』や『ウルティマVII』『ウルティマVIII』についてのやつ。そしたら、昨夜GOGでアンダーワールドとVIIを買っちゃった。90年代に素晴らしいものを見逃した気がしてね(あと『システムショック』と『クルセイダー・ノー・リモース』も手に入れないと)。兄貴と俺はIXが出たときに買ったけど、バグだらけで諦めちゃったから、ちゃんとしたウルティマは体験してないんだ。でも、兄貴とその友達はUOにハマってた。友達は当時「SirDarkSpell」って名前のグリーファーで、ちょっと有名になったらしい。これって2000年頃だったかな?二人ともこのプロジェクトの話を聞いたら喜ぶと思うよ。どっちもUOの思い出があるからね。とにかく、週末はスティジアン・アビスに没頭しようかな…
ウルティマ アンダーワールドは最高のゲームだね。
すごい!いい仕事してるね!俺はここ5年くらい、隙間時間にウルティマ3.5風のMORPGを作ってるんだ。Go、Postgres、フロントエンドにReactを使ってる。トップビューのタイルグラフィックスで、昔ながらのキーボード操作/コマンド。まだまだ不完全だけど、いつかShow HNをやりたいな。君からインスピレーションをもらって、世界をセクターに分ける必要があると思ってる。今はPCとNPCが増えすぎてn^2のスケーリング問題が出てるんだ。
すごい仕事だね!これ、めっちゃ懐かしい気持ちになるよ。ずっと前(UOが現役だった頃)、C++のUOエミュレーター「UOX3」を維持してたんだ。最初から開発したわけじゃなくて、大きな機能を作ったわけでもないけど、コードベースのメンテナンスを引き継いで、パッチを適用したりリリースを管理したり、コミュニティを運営したりしてた。元の作者が離れたから、俺がそのコミュニティで結構目立ってたみたいで、リーダーを任されたんだ。あと、カナダの人が金やハードウェア、帯域を使ってUOXをベースにしたプライベートサーバーを運営するのを手伝ったこともある。どちらも素晴らしい経験で、たくさん学んだよ。振り返ると、Originがあまり訴訟を起こさなかったことや、FBIが俺の家に「ハッキング」しに来なかったことに感謝してる。
それを聞いて嬉しいよ!実はUOX3はMoongateのインスピレーションの一つなんだ。サーバーアーキテクチャやスクリプトのアプローチが本当に面白くて、プロジェクトで探求しているアイデアにも影響を与えてる。UOX3のようなプロジェクトは、ウルティマオンラインエミュレーターの歴史において大きな部分を占めてるから、維持に関わっていた人から話を聞けて嬉しいよ。
ねえ、Moongateアーキテクチャについての解説読んだよ。DIにSource Generatorsを使って、Luaで動作を切り離すって、C#を再コンパイルしなくて済むなんて素晴らしいセットアップだね。厳格なドメイン分離が重要だと思う。君の「何が足りない?」リストにNPC AIが含まれてるのを見たよ。俺はAIエージェントのワークフローを作ってるんだ。伝統的で退屈な有限状態機械をNPCに使う代わりに、君のLuaスクリプトにLLMマイクロサービスを組み込むのはどうかな?重要なNPCに実際の文脈メモリーとダイナミックな対話を与えられるかもしれない。プレイヤーが商人に物理的にタイプして、価格交渉したり、噂を聞いたりしたら、NPCはウルティマの lore に基づいた返答を生成して、正しいLuaイベント(アイテムを渡したり、ドアを開けたり)をトリガーするんだ。君がパケットレイヤーとLua環境をしっかり整えてるから、統合はすごくクリーンになると思う。もし興味があれば、AIロジックをマッピングするのを手伝いたいな。
興味ある!GitHubで連絡して!
すごく面白いアイデアだね。NPCと話すことで世界が変わるシステムがあったら、さらに興味深いと思う。たとえば、噂を聞くことでNPCが説明するシナリオが実際に作られるっていうのは、わかりやすい方法かもしれないね。
すごくいいね!昔、UOエミュレーターコミュニティに参加してたけど、主にSphereServerで活動してたんだ。ここでコメントを見てると、UOに影響を受けてプログラミングを始めた人がたくさんいるのが面白いね!最近のLLMの進展は、今のMMORPGでも非常に面白くて楽しいNPCのやり取りを生み出すと思う。小さなプレイヤーコミュニティサーバーでも、NPCとの複雑なインタラクションを進行中のストーリーラインに組み込むことができるから、長期的に見ても viable だと思うよ。
> SphereServerの懐かしい思い出!まだNASのどこかにSphereServerのソースがあるはず。高校の初めに、グループでコーディングしたり、Linuxサーバーを運営したりする初めての経験だったんだ。