Show HN: 10年かけて逆向きにした後ついに、DOS版『ウィングコマンド』の協力プレイが動作するようになりました

2026/11/05 3:51

Show HN: 10年かけて逆向きにした後ついに、DOS版『ウィングコマンド』の協力プレイが動作するようになりました

RSS: https://news.ycombinator.com/rss

要約▶

Japanese Translation:

オリジナルのサマリーはハイレベルな概要には適しているが、キーポイントリストに含まれているような技術的な深みは欠けている。以下は、物語の流れを保持しつつ、リストから具体的な技術的マイルストーンと年代順の文脈を取り込んだ改良版である。

改善されたサマリー:

最も重要な教訓は、2人の開発者(Daniel Rh と Patrick)が、1990 年代のシングルプレイヤー DOS ゲーム『Wing Commander』を厳密な制限(640K RAM の旧ハードウェア上)の中でスタートし、11 年間の旅程(2015–2026)を通じて完全に機能する協力型マルチプレイヤー体験へと成功裏に変容させた点である。コアファイルを変更せずにマルチプレイヤー機能を注入するためには、内部メモリ構造を分析するために DOSBox を利用し、プレイヤーの位置、速度、勝利点を制御する特定のデータアドレスを 64K データセグメント(dseg)内で特定した。コアファイルを変更せずにマルチプレイヤー機能を注入するため、「死んだ文字列」を使用して Borland オーバーレイを通じてゲーム関数を呼び出す技術や、複雑な_trampoline システムを開拓した。開発は TCP/protobuf ネットワーキングプロトコルの実装から始まり、エンティティスロットの競合を解決し、VDUフックによるインゲームテキストチャットの導入へと進化した。爆発やオートパイロットアニメーションなどの動的要素に対するサポートを洗練させた後、プロジェクトは 2026 年のアップデートで Emscripten を使用して再構築された形で完成した。この最終リリースには、ブラウザベースの WebRTC ピアツーピア接続、ボイチャット、カスタムロビーシステムが搭載されており、高価なモダンポートではなく高度なリバースエンジニアリングを通じてレガシーソフトウェアを蘇らせることができることを証明している。

本文

「Wing Commander」共同プレイ実現までの 11 ヶ年と、今さらながらの冒険

導入:想い出と目標

  • 子供時代、弟のパトリックとは**一つの機体に二人乗りする「二頭のヒドラ」**のようにではなく、仲の良い翼友として協業プレイしたいと願ってきました。
  • ブラウザで遊ぶ体験を通じて、この長年の夢を実現しました。

探求の始まり:2015 年 -2016 年

  • 2015 年 10 月:DOSbox でクラシックな『Wing Commander』を遊んでいた際、メモリがビル・ゲイツが冗談半分で語った640Kに収まることに気づきました。

    引用元の発言:「1981 年にその決定を下す際、私は今後 10 年は十分使える自由度を与えられていると感じていました。つまり、64K から 640K という変化は長らく続くものと見込まれました。しかし、そうはなりませんでした」(出典)

  • アイデア:メモリをダンプしてプレイヤーと翼友の座標(X, Y, Z)を特定し、ネットワークパケットで翼友を制御する仕組みを作ればよいと考えました。

メモリ構成の詳細

  • 主要なメモリ領域:
    • DS:13D3
      :データセグメント(64K)
    • A000
      :VGA ビデオメモリ
    • E000
      :EMS ページフレーム
    • FFFF:F
      :終了アドレス
  • 興味深いアドレスと格納内容:
    • 0x0187
      :デッドストリング(使われなくなった文字列領域)
    • 0x7728
      :ランダムシード
    • 0xA9C2
      :プレイヤー位置情報
    • 0xD248
      :ミッションツリー
    • 0x8DF8
      :通信テキスト
    • 0xCAE2
      :速度ベクトル
    • 0xFFxx
      :スタック領域
    • 0xAEB6〜B1B6・B4B6
      :右・上・前方のベクトル方向量

問題解決:メモリ差分解析とアプローチ

  • 本質:わずか 100 万バイト未満の中から、ゲームステートを格納している場所を特定する必要がありました。
  • 手法:
    1. ゲーム内の他のエンティティを全て消去して単一化。
    2. プレイヤーが止まっている状態と移動後の状態のメモリの差分を撮影。
    3. 「背景」として変化しないメモリ領域を特定。
    4. DOSbox の
      MEMDUMPBIN
      コマンドでダンプを取得し、エンティティ消滅時に位置情報を記録。

データセグメント内の差分解析結果

比較項目変動量備考
停止状態253 バイト変化なしの領域も含まれる
移動時650 バイト追加で変化する領域あり
両者共通413 バイト真正なゲームステート候補
追跡カメラビュー参照後132 バイト実効的な変化に絞った結果
  • 解析の深化:
    • データセグメント内で 35 の変更クラスタを特定し、視覚的検査で 12 カ所に絞り込みました。
    • 最終的に
      13D3:A9C2
      というアドレスに収束しました。
  • 検証:
    • DOSbox デバッガーの
      SM
      コマンドでこのアドレスに整数を書き込むと、船が前方へジャンプ移動することが確認できました。
    • 同様に
      CAE2
      アドレスでの速度変化も特定(停止時のゼロ値を持つ 32 ビット整数が 3 つ存在)。

ロータリングの謎解き:ベクトルとオーバーレイ

  • 課題:回転ベクトルの格納位置の詳細な分析が必要でした。
    • ベクトルは
      256 = 1.0
      とみなす 4 バイトのスカラー構成で、有効値は
      0〜255
      の範囲。
    • 微細な回転では単一バイトしか変化しないため、特定が困難でした。
  • 発見:開発者によるユーモアのような構造が存在していました。
    • エンティティプロパティ用に 64 スロット(
      0x00
      〜
      0x3F
      )を予約。
    • デベロッパーは
      0x3F
      を一時用途、カメラを
      0x3D
      に配置しました。
    • これにより、カメラ変数から 2 スロット離れた一時的な変数が誕生し、
      up
      や
      forward
      も隣り合う構造になりました。

回転ベクトルの位置特定

タイプアドレス (船コピー)アドレス (カメラコピー)備考
up[0]
B1B6
B492
毎フレーム更新
up[空スロット]-
B49E
-
up[一時変数]-
B4AA
スロット
0x3F
forward[0]
B4B6
-星雲背景のシフト可視化
  • 小端表現(Little-Endian):非ゼロ単位ベクトルは
    00 01 00 00
    (256=1.0)
  • 遷移確認:
    • level flight
      から
      yaw
      への遷移で
      forward[0]
      が 9 バイト変化。
    • up[0]
      が
      00 01
      から
      7E 00
      に変化した。

コード追跡とフック地点の発見

  • ID(IDA)でのバイトシーケンス検索と注釈付けを開始。
  • BPM(Break Point Monitor)で監視:
    • CS:IP == 0560:20E3
      :DOSbox フック地点
    • 呼び出し連鎖追跡:
      vector_add
      →
      physics per ship
      →
      per frame
      →
      main loop

制御機構の構築:トリムポリン設計

  • 限界の認識:「グローバルメモリへの書き込みだけで操作できる」という幻想は砕け、元のゲーム関数を流用して正確な体験を得る必要があります。
  • 手法:プログラムカウンターを正しい場所へ誘導。引数を挿入し元に戻ってくるメカニズムを実現。

スタブによる関数呼び出し(例:fireAllGuns)

  • オーバーレイ 143 (
    stub143
    ) のセグメント
    12D7
    に JMP far スタブが配置されています。
    • 12D7:0084
      →
      jmp far 2F31:0A99
      (
      do_damage
      )
    • 12D7:012E
      →
      jmp far 2F31:2978
      (
      fireGunFromShip
      )
    • 12D7:0156
      →
      jmp far 2F31:2E76
      (
      fireAllGuns
      )

実行フロー

  1. DOSbox が
    CS:IP
    をスタックにプッシュし、指示ポインタを上記文字列リロケート。
  2. 0x00:終止文字列。
  3. pushf; pusha
    :レジスタ状態保持。
  4. xor si,si
    :引数設定(シップ 0)。
  5. call far 12D7:0156 via stub
    :スタブ経由で関数呼び出し。
  6. pop si; popa; popf
    :cdecl で戻り値処理。
  7. retf
    :DOSbox がプッシュしたアドレスへ復旧。
  • この操作により、レーザーキャノンの発射が確認できました。
  • 2017 年 3 月:メインループの予測可能なフック地点(
    0560:20E3
    )発見。不確定部分を回避。
  • 同年 7 月:
    do_damage
    関数を特定し、セカンドプレイヤーへの呼び出しを阻止。

ネットワーク統合とネットワークプロトコル

  • 2017 年 8 月:簡素な TCP クライアント/サーバーアーキテクチャと protobuf ゲームメッセージを実装。
    • リーダーから全ての船位置、発射イベント、消滅、ダメージを配信。
    • クライアントは自身の位置や大事件(射出・着陸・死亡)を返信。

初期問題:スタック処理とオーバーレイローダー

  • 問題:Borland のオーバーレイローダーがコードページをスワップする際、自作スタブにはフレームが存在せず、ゴミ値を読み取りゲームがランダムにクラッシュしました。
  • 解決策:Borland 関数のようなスタブを作成し、
    push bp; mov bp, sp; nop (0x90); pop bp; retf
    で対応。
    • DOSbox が
      nop
      に到達した際に、ジョブキューから次のコールをインジェクトするように設定。

スロットと ID マッピングの統一

  • 2017 年 10 月:一時的オブジェクトがプレイヤーごとに異なるスロットに配置されていることを発見。
    • スロット
      0
      :プレイヤー
    • スロット
      1
      :翼友
    • スロット
      3D
      :カメラ
    • スロット
      3F
      :一時スロット
  • 対応策:一時的オブジェクトの共有領域(スロット 12〜15)を制限し、マルチプレイヤー位置の一貫性を保つように変更。
  • 2017 年 12 月:クライアントをサーバー船 ID とローカル ID のマッピング格納に変更。
    spoon
    関数の復帰強制不要化により、パケット変換が可能になり、小惑石のマルチプレイも動作。

ゲーム内容の拡張と成功

  • 2018 年:爆発、ミサイル、オートパイロットのアニメーションに注力。
  • 2019 年 6 月:ミッション勝利計算が不安定であることを発見。
    • バイナリ探索と半減法を繰り返して実際の集計位置を特定。
    • 最終的に
      13D3:D248
      の 80 バイトにミッションツリー、
      13D3:C280
      に総合勝利ポイントカウンターを見つけました。
    • これにより、数年後のドロップダウンでのミッション選択が可能になりました。

通信テキストの統合

  • 2020 年初頭:通信テキスト再生関数を特定し、ネットワーク経由でのチャット送信を実現。
    • タイピングされたチャットを翼友の VDU で表示させるシステムフック完成。
    • **「両方のパイロットがタイピングし、互いにメッセージを送る」**体験が可能に。

試行錯誤の記録とタイムライン

期間主な成果・発見
2016メモリダンプ取得・位置情報の特定
2016.9スナップショット比較ツールの開発
2016.11右/up/forward ベクトル、スロット
3D
の特定 (
256=1.0
)
2016.12-2017.3コール注入・メインループフックの確立
2017.7
do_damage
関数の特定
2017.8TCP over protobuf の実装
2017.10-12トランポリン設計、push bp、スロット制限 (
12-15
)、ID マッピング
2019.6-7バイナリ探索による D248(勝利ポイント)の発見
2019.10総合勝利ポイント・ミッション番号の特定
2020.1通信テキスト機能の実装
2020.3コミュニケーションパネルでのチャット完成
2020.10遊べる状態への到達

プロジェクトの復活:lobbylink と現代技術による再構築

  • 課題:友人との共有が困難(古いコピー探し、DOSbox 変種コンパイル、IP 共有など)。
  • 解決策:
    • WebRTC の普及と堅牢な emscripten サポートを活用。
    • lobbylink システムを開発し、プロジェクトを復活・共有可能にしました。

lobbylink の概要

  • 実装:https://github.com/danielrh/lobbylink(golang ベース)。
  • 依存:Websocket ライブラリのみ。
  • 機能:
    • ピアツーピア WebRTC 接続を調整。
    • 小さなサーバー上で動作し、共有ルームコードを通じてプレイヤーが接続。
    • 静的なオリジンリストを持つため、任意のブラウザやクライアントソフトでも接続可能。
    • サーバー側で coturn を実行し、TURN クレデンシャルを発行するため、制限的なファイアウォール背後からの接続もサポート。

接続フロー

  1. join:ルームコード入力。
  2. joined:プレイヤー 0 が接続(ICE サーバー情報取得)。
  3. player-joined:他プレイヤーの加入通知。
  4. データチャネルオープン:ゲームパケット・音声通信開始。

ブラウザでの遊び方

  1. GOG の Wing Commander インストーラーを zip 展開し、emscripten データファイルとして使用。
  2. https://fireflyk64.github.io/dosbox/ にアクセス。
  3. ゲームファイルをドラッグ&ドロップ。
  4. ルームコードを入力して接続。

最終的な拡張:音声チャット

  • LLM を活用し、オプションで第 2 の WebRTC ピア接続を使ってリアルタイム音声通信を追加。
  • これにより、「一緒に飛行し、共に笑い合う」体験が実現しました。

同じ日のほかのニュース

一覧に戻る →

2026/11/05 5:45

ホワイトハウスのネットワークで住宅用プロキシが検出

## Japanese Translation: 当社の Residential Proxy Observatory を率いた最近のセキュリティ調査により、大統領執行局(ホワイトハウスのネットワーク)に登録されている AS2650 は、2026 年 10 月 5 日から 11 月 3 日まで、住宅用プロキシのエグレス活動ホストしていることが確認されました。エニュメレーションパイプラインでは、30 日のうち 26 日にわたり 6 つのアドレスから発せられた 236 の別個のエグレスが特定され、28 の異なる住宅用プロキシサービスが観測されました。Spur および Synthient という検知サービスとのクロスチェックにより、これらのアドレスが公共 IP コンテキストページを通じて住宅用プロキシエグレスであることがそれぞれ独立して確認されました。 活動は東部標準時の午後 5 時から真夜中にかけてピークに達しており、これは感染した個人端末がプロキシ SDK を使用していることを示唆しており、公共の Wi-Fi の使用とは異なります。セキュリティが不十分なプロキシ SDK は、ネットワーク内でのラテラルムーブメントを可能にします。この事件は、以前の類似した住宅用プロキシネットワークを通じて数百万台の Android 機器を感染させた Kimwolf ボットネットによって参照されたようなリスクの巨大な規模を浮き彫りにしています。 ホワイトハウスのネットワーク以外にも、セントヘレナ・アセンションおよびトリスタンダクーニャ(スターリンクおよびSure セントヘレナを介した 32,000 回以上の観測を持つ 413 のアドレス)、南極大陸(クラウドフレア WARP を通じたマクマード基地への 3 つの観測)、ピトケアン、ノーフォーク島、スバルバル、フォークランド諸島、チャゴス諸島、トケラウ、サウスジョージアなど、遠隔地でも住宅用プロキシが観測されました。Layer3 Intel はこの世界的な住宅用プロキシおよび匿名化インフラストラクチャを追跡しており、脅威アクターは遠隔または孤立したネットワーク上にあっても隠れる場所がないことを示しています。 侵入を記録するログは当局のために確保されており、関連する機関からの要請により当社の連絡先ページを通じて入手可能です。これらのログは、責任あるアクターの特定と感染の全範囲の評価を可能にします。究極的には、この事件は、個々のエンドポイントが適切にセキュリティ対策されていな場合に、高プロファイルな政府ネットワークも侵入に脆弱であることが示され、全世界でのトラフィックの再方向付けを通じて機密通信のプライバシーとセキュリティに対して直接的な脅威をもたらしていることを実証しています。

2026/11/05 4:50

昆虫はLEDの光に集まってくるわけではない

## Japanese Translation: 白熱灯からLED照明への切り替えは昆虫の引き寄せを劇的に減少させ、昆虫個体数の減少に対する新たな希望を提供しています。昆虫は月光(紫外線(UV)および赤外線波長を含む太陽光の反射光)を利用して航行しますが、人工的な光で紫外線を透過するものには混乱し、上空に向いた姿勢から円を描く飛行や逆さまになるような行動を示します。白熱灯はこの紫外線豊富な光を放出しますが、LED は電気エネルギーのほとんどを可視光(400–700 nm)に変換するため、コバチやヤブカメムシといった飛翔種に対してははるかに魅力的ではありません。 この移行を支える証拠として、2016 年のブリストル大学の研究では白熱灯、省エネ蛍光灯(CFL)、寒色系LED、暖色系LEDを比較し、LED全体が昆虫を引き寄せる数が著しく少ないこと、かつ寒色系と暖色系のLEDの間には有意差がないことを発見しました。具体的には、ハエ目(Diptera)のコバチやクレンカメムシ属(Culicoides)のヤブカメムシがLEDに引き寄せられる個体数が少ないことが確認されました。実例としては、ガイドのロランド・ルム氏によるWINGS バラクロスの旅行で報告された事例があり、家庭では屋外用ダイニング照明を白熱灯からLED に切り替えた後、トカゲの個体群が消失することに気づいたとあります。これは、爬虫類が昆虫という食物源を失ったためです。 夜間の紫外線豊富な人工光は、昆虫個体数の減少の主要な要因の一つと考えられています。このUV曝露を最小限に抑えることで、野生動物の航行への擾乱を軽減し、昆虫媒介疾患に関連するリスクを低減させ、人間の開発と自然の野生生物循環の安全な共存を促進することができます。(記事掲載日:2026 年 11 月 3 日;写真は 2006 年 7 月に撮影されたガソリンスタンド照明に群がる昆虫の様子)

2026/11/05 3:53

Ripple-65B Preview:米国で開示されたオープンウェイトモデルによるエージェント型コーディングにおける最上位性能

## Japanese Translation: このテキストは、先進的な AI モデルの構築において、段階的にトレーニング手法を最適化する方が、強力で生僻な計算資源に依存する蛮力アプローチよりもはるかに効率的であると論じています。この戦略では、単純な規模化よりも反復的な改良を優先することで、TerminalBench 2.1 でトップティアの性能スコア 80.5 を達成しました。これには「ロールアウト」と呼ばれる試行錯誤のステップがわずか 140 万回しか必要であり、先導的だった前技術(Reflection Beam)が要していたものの約 70 分の 1です。この効率性の源は、高価な外部データの購入を排除し、品質フィルタリングとカバレッジ指標を活用した高品質な内部環境に焦点を当てるカスタム synthetic データパイプラインにあります。 技術的には、このアプローチは堅牢な有教師学習用微調整(SFT)チェックポイントから始まり、高品質な長期間視野を持つ合成環境内において、切り捨て重要性サンプリング、スコア中心化、および線形長罰則を含む混合 RL レシピを採用しています。主要な利点はその適応的な性質であり、モデルが改良につれてトレーニング担当者が自動的により困難なタスクを追加することで進捗を維持しつつ資源の浪費を防ぎます。究極的には、この手法は先進的なモデルのトレーニングにおける財務的および計算機的障壁を大幅に低減させ、巨大量のデータクラスターや過剰な計算力への投資を少なくしてでも優越的な結果を得ることを可能にします。