00 — Orientation

全体像

このエンジンを形づくる判断は、ほぼ次の5つです。残りの仕組みは、いずれかの判断から自然に導かれます。

obje

物理ボディは1種類

ユニット、飛翔体、背景物、切断された手足まで、重力・弾性・終端速度・生命力・耐性を持つ同じ64バイトの物体タグを参照します。

1 / 30 s

時間も空間も整数

毎秒30ティック、位置は1 World Unitの1/512、比率は16.16または8.8固定小数点。ゲームプレイに浮動小数点は入りません。

prgr

効果も飛翔体

爆発、血飛沫、軌跡は独立した粒子系ではなく、さらに飛翔体を生む再帰的な飛翔体グループです。

seed

乱数シードがチェックサム

各クライアントは現在の乱数シードを比較します。ほぼすべての分岐が同じLCGを消費するため、シードは差異の履歴を圧縮した指紋になります。

reco

状態ではなく命令を送る

ネットワークを流れるのは、ユニットを動かす7種類の動詞だけです。保存フィルムは映像ではなく、初期シードから試合を再実行するレシピです。

文書で確認 Bungie/Project Magmaの資料、出荷されたエディタ文書、逆解析された構造体定義で裏づけられる項目。

推論 パッチノートと観察された挙動を組み合わせた、妥当だが直接の証言がない解釈。

未解決 到達できた資料から確定できず、推測で埋めない項目。


01 — Data model

タググラフ

Myth II のコンテンツは、コンテナ内に置かれた4文字コードのタグ群です。ロード時にIDで解決され、ゲームプレイは「どのタグがどれを指すか」で組み立てられます。

驚くのは間接参照の深さです。マップ上に置かれる unit タグはわずか8バイトで、モンスターと色への参照しかありません。プレイヤーが「ユニット」と考える性質は mons に、物理的な性質はさらに下の obje にあります。

Myth IIのタグ参照グラフ unitがmonsを参照し、monsの攻撃がprojを生み、projがprgrへ爆発し、prgrが再びprojを生む。mons、proj、scenは共通のobje物理タグを参照する。 unit8 bytes mons1024 bytes proj256 bytes prgr飛翔体グループ 参照 attacks[4] 爆発 N個のprojを生成(再帰) coll .256スプライト + シーケンス 時間 scen obje64 bytes · 物理 object_tag object_tag object_tag
兵士、矢、岩は同じ種類のボディ。 重力・弾性・終端速度・生命力・ダメージ耐性は共通の obje にあります。飛翔体がグループへ爆発し、そのグループが新しい飛翔体を生む再帰が、爆発と流血表現の中心です。
  • mons に生命力はありません。 体力は obje.vitality_lower_bound + vitality_delta で個体ごとに決まり、同じ兵種でも完全に同じ体力にはなりません。
  • モンスター自身はダメージ値を持ちません。 攻撃力は、攻撃が生成する飛翔体の性質です。戦士を再調整するには「矢」を編集します。

02 — Numeric substrate

整数の基盤

ゲームプレイに使う量はすべてスケールされた整数です。これはMacとPCを同じロックステップで動かすための根本条件でした。IEEE浮動小数点が現れるのは霧や残響など表示側の量だけです。文書で確認

固定小数点のスケール
除数表すもの主な用途
World512World Unit位置、速度、半径、重力、反動
Fixed65,53616.16吸収率、怯み、狂戦士化、ミス率
ShortFixed2568.8生命力、ダメージ、弾性、マナ、耐性
Percent65,535確率爆発頻度、軌跡頻度
Time30全継続時間をティックで保存
Angle65,536 / 360向き。1周で自然に桁あふれする

下限 + デルタ

生命力、速度、弾薬、寿命、出現数などのランダム範囲は、すべて X_lower_boundX_delta の組で表します。ゼロでないデルタは真の幅より1大きく保存され、「乱数なし」と「幅0」を区別します。乱数はシード付きLCGから整数で得られるため、自然なばらつきとビット単位の決定性が両立します。


03 — mons

モンスター

1,024バイトの mons タグは、AIと戦闘システムがユニットに尋ねる質問の一覧のようなものです。

warning_distance

警告を聞く距離

味方の「助けを求める声」に気づく距離。標準的な歩兵で約4 WU。

critical_distance

存在検出の距離

敵の存在を察知し、現在の目標が死んだとき次を探す半径。約8 WU。

pathfinding_radius

空間バブル

味方との最小間隔。歩兵では約0.30 WUで、局所的な混雑回避に使われます。

terrain_costs[16]

地形コスト

地形ごとの経路選好。負の値は通行不能。移動速度係数とは別に保持します。

absorbed_fraction

攻撃吸収

名前に反して、ダメージの一部を減らす率ではなく、攻撃全体を無効化する確率と解釈されています。

combined_power

脅威の指標

AIが目標の優先度を決めるための総合的な戦力値。

アニメーションがゲームプレイを決める

攻撃時間は攻撃定義に直接保存されません。ビュー当たりのフレーム数 × 1フレームのティック数が下限になり、そこへ回復時間が加わります。振りのアニメーションを長くすれば、そのままDPSが下がります。

さらに、ブロック能力の専用フラグはありません。sequence_indexes[5] > -1、つまりブロック用シーケンスを持つこと自体が能力判定です。ここではアニメーションデータが、そのままゲームプレイデータです。文書で確認


04 — Combat

ダメージ

ダメージは飛翔体に埋め込まれた16バイトの構造体です。種類、振る舞いフラグ、下限とデルタ、半径、拡大率、ダメージから速度へ変換する係数を持ちます。

damage → damage_to_velocity → propelled_system_shock → damage_to_propulsion → obje.gravity → obje.elasticity

距離に応じた減衰曲線はありません。 代わりに rate_of_expansion があり、爆発は静的な球ではなく、時間とともに広がる球面として扱われます。遠いユニットが近いユニットより1〜2ティック遅れて被弾する挙動と整合します。推論

回復も独立した治療系ではなくダメージ種類の一つです。投射、反動、重力、跳ね返りは決定論的なシミュレーションに含まれます。いわゆるラグドールではなく、死体は1点の物体として専用アニメーションを再生しながら地形上を跳ねます。

血と破片も飛翔体グループ

死亡・爆発・燃焼時のタグは、ランダムな数と位置で破片飛翔体を生むグループを指します。身体部位も物理を持つ飛翔体で、投射物の上限数に数えられ、理論上はダメージさえ運べます。血は地形の色マップを破壊的に書き換え、火はメッシュセルの状態ビットとして伝播します。


05 — Attacks

弾道

各モンスターは最大4つの64バイト攻撃定義を持ちます。攻撃側が照準・タイミング・経験値補正を持ち、参照先の飛翔体がダメージと飛行を持ちます。

  • LEADS_TARGET — 移動目標を先読みする。
  • IS_INDIRECT — 迫撃弾のような弧を使う。
  • IS_FIXED_PITCH — 射出角を固定し、必要速度を解く。
  • AIMED_AT_TARGETS_FEET — 範囲攻撃を目標の足元へ向ける。
  • AVOIDS_FRIENDLY_UNITS — 弾道が味方を横切るか調べる。

エンジン自身が「firing solution」という語を使い、重力を受ける飛翔体方程式を解いています。経験を積むと recovery_timeinitial_velocity_error が減り、兵士はより速く、より正確に攻撃します。


06 — mesh

世界と衝突

マップは一般的なポリゴン集合でもナビメッシュでもなく、規則的な高さ場です。正方形セルを2つの三角形へ分割し、セルごとに高さ、法線、フラグ、2種類の地形コード、媒体の高さ、モデル番号を持ちます。

Tier 1

高さ場

すべての地面接触。1セルを2三角形にし、三角形ごとに4ビットの地形コードを持ちます。

Tier 2

スプライト円柱

ユニットと飛翔体の交差判定。スプライト画素で記述した半径・高さをロード時にWorld Unitへ変換します。

Tier 3

ポリゴンモデル

壁、門、巨大な固体など少数の例外。本物の頂点と境界を使う、より高価で不具合の多かった経路です。

terrain nibble

変化する通行可能性

スクリプトが地形の4ビット値を書き換えられるため、橋の崩落や門の開放は移動可能性そのものの編集です。

3段階の衝突表現高さ場、円柱、ポリゴンモデルという3つの衝突層を示す。 Tier 1 · 高さ場 円柱Tier 2 · スプライト境界 Tier 3 · ポリゴン
一般的な3D衝突系はありません。地面・小さな物体・例外的な大きな固体を、それぞれ別の表現で処理します。

07 — Movement & AI

移動とAI

経路探索は二段階です。まず動的障害物を無視し、静的な地形コストだけでA*経路を作ります。その経路が障害物へ当たると、左右の迂回を再帰的に試し、元のA*経路から最も小さく外れる方を選びます。文書で確認

この分割は決定性に有利ですが、密集したユニットが詰まりやすい理由でもあります。pathfinding_radius は局所的な二者間の分離しか表さず、群衆全体を組み替えるモデルを持ちません。

警戒は視覚だけでなく社会的に伝わる

warning_distance は、味方の助けを求める声を聞く距離です。警報は全員へ一度に届くのではなく、隣から隣へ連鎖します。

警報が隊列を連鎖する図敵がBを攻撃し、Bの警告範囲でCが気づき、Cの範囲でDが気づく。Eは範囲外で気づかない。 B C D E 助けを求める声Cが中継未警戒
隊列は波のように目を覚まします。孤立したユニットなら、短い距離に味方がいても静かに倒せる可能性があります。

編隊もハードコードではなく form タグです。行間、ずらし、箱形、包囲半径などのパラメータから、各クライアントが同じ配置を決定論的に展開します。移動命令は配置済み座標ではなく編隊番号と最終方位を運びます。


08 — reco

命令ストリーム

フィルム形式は状態の記録ではなく命令の文法です。各命令は8バイトのヘッダー(サイズ、動詞、プレイヤー番号、絶対ティック)とペイロードからなります。

GENERAL · MOVEMENT · TARGET · ATTACK_LOCATION PICK_UP · RENAME · ROTATION

ユニットを操作する動詞は7つだけ。 これが戦術語彙のすべてです。停止、散開、後退、特殊能力などの差はフラグで表されます。

SELECT命令はありません。 選択UIはローカルだけで働き、各命令が16ビットのユニットID一覧を直接持ちます。範囲選択、種類選択、追加選択はネットワークへ送られません。

命令は一般にはキューされません。 新しい命令が現在の命令を置き換えます。例外は単一の MOVEMENT ペイロード内にあるウェイポイント配列です。

マップスクリプトも、人間と同じ動詞を発行します。 専用のAI制御路を持たないため、スクリプトとプレイヤー制御が自然に合成されます。


09 — Determinism

決定論

ネットワーク形態はクライアント/サーバですが、シミュレーションは決定論的ロックステップです。ホストは状態の権威ではなく、命令を中継してターンを裁定します。

乱数シードがチェックサム

世界全体をハッシュしません。各プレイヤーの32ビット乱数シードを定期的に比較します。異なる回数だけ乱数を引いたり、異なる値を生成器へ渡したりすれば、シードはすぐ分岐し、再び一致しません。

seed′ = (1664525 × seed + 1013904223) mod 2³² result = (seed′ >> 16) & 0xFFFF
決定論的ロックステップ2つのクライアントがホストへ命令を送り、同じ命令列を受けて各自が同じティックを計算し、シードを比較する。 クライアントA命令を発行 クライアントB命令を発行 ホスト中継 · ターン境界 Sim A · tick N整数状態 · seed A Sim B · tick N整数状態 · seed B SYNC · シード比較不一致 → OOS
ネットワークを流れるのは命令だけ。 ユニットID 47が全機で同じ対象を指すことが前提です。不一致が起きても、送り直す状態が存在しないためロールバックも再同期もありません。

Mac/PC差をどう見つけたか

x86とPowerPCで除算結果の有効桁が異なり、クロスプラットフォーム対戦だけが同期を失いました。Project Magmaは全 myth_random() 呼び出しを、ファイル名と行番号を記録するデバッグ版へ置換し、両機のログを比較しました。最初に違った乱数呼び出しが、正確なティックとソース行を同時に示しました。

保存フィルムがバージョン間で壊れやすいのも同じ理由です。フィルムは映像でなく再実行レシピなので、ゲームロジックが変われば同じ命令列でも違う世界へ進みます。


10 — Loathing

マップスクリプト

Bungieは開発途中でJavaベースの言語を断念しました。最終的に出荷されたのは言語というよりトリガーグラフです。

アクションは64バイトのヘッダー配列と、型付きパラメータ列としてメッシュタグに入ります。各ノードは成功・失敗・実行・有効化・無効化・抑制・前提不足などのイベントで他ノードを有効/無効にします。ACTION_IDENTIFIER はどこへでも向けられるため、構造は木ではなくグラフです。

イベント → Action A → 成功 → Action B ↘ 失敗 → Action C FIELD_NAME → 別アクションのフィールドを書き換える

約68種類のアクションの半数は、近接、嫌がらせ、包囲、敗走、分隊、軍団、警備などのユニットAI編成に使われます。エディタのアクション一覧とヘルプもタグから生成されるため、エンジンへ新しい種類を追加するとき、エディタ本体を再ビルドする必要がありません。


11 — Limits

未解決点

Myth II のソースコードは公開されていません。利用できる根拠は、Bungieのエディタ文書と事後分析、Project Magmaの変更履歴、バイナリタグ構造のコミュニティ解析です。残る空白を、推測で埋めないことも重要です。

  • 未解決 ネットワーク1ターン当たりのティック数と入力遅延。
  • 未解決 1ティック内の更新順序。
  • 未解決 描画側がティック間を補間するかどうか。
  • 未解決 12種類のダメージから9個の耐性スロットへの対応。
  • 未解決 phys(ローカル物理)と wind タグの完全な配置。

有力な次の資料は、The Tainにあるbungie.netメタサーバの公開ソース、RoadのMap Action Script Guide草稿、MythingOak wikiのタグ資料です。


12 — Provenance

出典

  1. Bungie: Myth: The Fallen Lords 事後分析 — 地形メッシュ、二段階経路探索、決定論的ネットワーク、地形へ書き込む血、Fear/Loathing。
  2. Project Magma: Myth II 1.5/1.5.1 事後分析 — 30 Hzティック、固定小数点化、シード比較、乱数ログによる診断。
  3. jwheare/mythextract — タグ、メッシュ、コレクション、記録形式の逆解析パーサー。
  4. Fear documentation v1.8.5Loathing documentation v1.8.5 — Bungieのエディタ資料。
  5. Project Magma リリースノート — 衝突、経路探索、フィルム互換性、飛翔体上限の変更。
  6. The Tain ソースコード・アーカイブ — 公開されたbungie.netメタサーバコードを含む。
  7. MythingOak — Category:Tags — コミュニティによるタグ資料。