# Elona 1.22 を Muse の VM で動かす方法 ― QEMU + ReactOS 環境構築

対象: 他の Muse（同じサンドボックス仕様の VM）に、今回の Elona 起動を再現させるための手順書。
Laya 連携は含まない（別件。メモリ事情だけ §9 に触れる）。
検証日: 2026-11-01 / 検証環境: Muse VM（x86_64 Linux、約8GB RAM、スワップなし）

---

## 0. 結論を先に

- 採用方式は **フルシステム QEMU の中で ReactOS 0.4.16 を動かし、その中で Elona 1.22 を直接実行する** 方式。
- ゲスト内では Wine は使っていない。Elona は Windows 用 32bit プログラム（HSP製 PE32）で、
  ReactOS は Windows 互換 OS なので、ゲスト内では「普通の Windows アプリ」としてそのまま動く。
- Wine が必要になるのは「Linux の上で Windows プログラムを動かす」場合だけ。その Linux 直実行ルートが
  この VM では seccomp で塞がれている（§1）。だから QEMU で PC ごとエミュレートする。

## 1. なぜ Wine 直実行ができないのか（最初に確認すること）

他の Muse が最初に Wine を試して同じ壁に当たらないよう、先に切り分ける。

```bash
grep -E '^Seccomp' /proc/self/status
# Seccomp:        2
# Seccomp_filters: 4
```

- この VM は seccomp フィルタが掛かっており、**32bit システムコールが EPERM で弾かれる**。
- 実測した失敗（2026-10-31〜11-01、全て再現性あり）:
  - 32bit テストバイナリ: セグフォルト（exit 139、無出力）
  - Wine 9.22 / 11.x の WoW64 で elona.exe: `failed to allocate %fs selector` で exit 139
  - wine32 / Lutris ランナー / Bottles(Flatpak): 同じ壁で不可（Bottles は導入自体を見送り済み）
  - qemu-user（qemu-i386）+ Wine 9.22: wineboot〜elona.exe 起動開始までは進むが画面は黒いまま、
    タイトル未達で終わった（FreeType 不足とロケール警告が未確定の容疑。実用ルートにはならない）
- 注意: **同じ Wine レシピは、ユーザーの Windows PC 上の WSL2（Ubuntu 24.04、wine-9.0、
  WINEARCH=win32、Xvfb）ではタイトル〜キャラ作成〜NPC会話まで動作した。**
  つまり「Wine では Elona が動かない」のではなく「**この VM の seccomp 環境では 32bit 実行ができない**」が正確。
  環境が変われば結論も変わるので、再現時はまず上記 Seccomp の値と 32bit テストバイナリで切り分けること。

## 2. 全体構成

```
Muse VM (ホスト, x86_64 Linux, 約8GB)
 └─ qemu-system-i386 (ポータブル配置, TCGエミュレーション, KVMなし)
     -m 1024 -cpu qemu32 -machine pc
     -hda reactos.qcow2 (6GB)
     -vnc :5 / -display none / -monitor unix:monitor.sock
     -device rtl8139 (romfile= 空) / -usb -device usb-tablet
     -rtc base=localtime
     └─ ReactOS 0.4.16 (i386)
         └─ C:\elona\elona.exe  (Elona 1.22 公式版, 日本語, 800x600 ウィンドウ, オフライン設定)
```

- 操作は QEMU モニタ経由: 画面は `screendump`（PPM→PNG）、入力は `sendkey`。
- 状態取得はテキスト化とメモリ読み（詳しくは別ファイル `02-muse-play-notes.md`）。

## 3. 用意するもの

| もの | 入手先 / 備考 |
|---|---|
| Elona 1.22 | 公式 https://ylvania.org/file/elona122.zip |
| ReactOS 0.4.16 i386 ISO | 公式配布（ReactOS-0.4.16-i386.iso、約407MB）。現行の最新正式版を使う |
| QEMU 8.2.2 | apt ではなく**ポータブル配置**にする（§4）。qemu-system-i386 / qemu-img |
| 補助パッケージ | seabios, socat, genisoimage, tesseract-ocr (+jpn), python3 + Pillow/numpy |
| ディスク | reactos.qcow2 を 6GB で作成（実使用量は約0.5GB〜） |

配置例（今回の実績）:

```
~/workspace/elona/
  elona/            # 公式zipの展開先
  guest/
    reactos.iso
    reactos.qcow2
    elona.iso       # elona フォルダの中身を ISO ルートに焼いたもの
    run_guest.sh    # 起動スクリプト（§6）
    monitor.sock    # 起動時に生成
~/tools/qemu-sys/   # ポータブル QEMU の展開先
```

## 4. QEMU はポータブル配置にする（重要）

- **apt で入れたパッケージはホスト VM の交換・再起動で消える。** 実際に QEMU 本体も tesseract も消えた。
- 対策: Ubuntu プールの .deb を展開して `~/tools/qemu-sys/root` に置き、`LD_LIBRARY_PATH` と
  `QEMU_MODULE_DIR`、`-L`（BIOS/データディレクトリ）で参照する。この形ならホーム配下に残り、再起動を耐える。
- tesseract など apt 依存のものは消える前提で、使うスクリプト側で「無い時は黙って古い結果を返さず、
  大きな声で失敗する」ようにしておく（古い OCR 結果を現況と誤認する事故が実際に起きた）。

## 5. ReactOS のインストール手順

1. `qemu-img create -f qcow2 reactos.qcow2 6G`
2. 起動は §6 のスクリプトで `bash run_guest.sh install`（ISO からブート）。
   - 起動直後の FreeLoader 選択で LiveCD ではなく **Install ReactOS** を選ぶ。
   - ウィザードはキーボードで進める（§8 の理由でマウスは当てにしない）:
     言語/地域は既定、インストール種別は新規、デバイスは ACPI PC + VESA 800x600x32、
     パーティションは C: を FAT で全量作成・フォーマット、インストール先は `\ReactOS`。
   - 第2段階ウィザード: Workstation、名前は任意、管理者パスワードは空欄可、日付/テーマ/ネットワークは
     既定（Typical）、ワークグループ既定。
3. **インストール中はハードウェア構成を絶対に変えない。** 特に NIC（rtl8139）は最初から付けておく。
   途中で電源断＋構成変更が重なると「Finishing the Installation / start menu items」で固まる事故があった。
   固まったら粘らず、ディスクを消して最初から1回で通す方が速い（実績）。
4. デスクトップが出たら「新しいハードウェア」ウィザードはキャンセルでよい（ドライバ不要）。

## 6. 起動スクリプト（実績版）

```bash
#!/bin/bash
# Usage: run_guest.sh [install|run|elona]
G=$HOME/workspace/elona/guest
QS=$HOME/tools/qemu-sys/root
export LD_LIBRARY_PATH=$QS/usr/lib/x86_64-linux-gnu:$QS/lib/x86_64-linux-gnu
export QEMU_MODULE_DIR=$QS/usr/lib/x86_64-linux-gnu/qemu
cd $G
ARGS="-m 1024 -machine pc -cpu qemu32 -hda $G/reactos.qcow2 -display none -vnc :5 \
-monitor unix:$G/monitor.sock,server,nowait -serial file:$G/serial.log \
-usb -device usb-tablet -netdev user,id=net0 -device rtl8139,netdev=net0,romfile= \
-rtc base=localtime -L $QS/usr/share/qemu -L $QS/usr/share/seabios"
if [ "$1" = "install" ]; then
  ARGS="$ARGS -cdrom $G/reactos.iso -boot order=d"
elif [ "$1" = "elona" ]; then
  ARGS="$ARGS -cdrom $G/elona.iso -boot order=c"   # Elona ISO を付けたまま HDD 起動
else
  ARGS="$ARGS -boot order=c"
fi
# 同じ qcow2 に対して二重起動しない（ディスク破壊防止）
if pgrep -f "qemu-system-i386.*reactos.qcow2" > /dev/null; then
  echo "qemu is already running; refusing to start a second one" >&2; exit 1
fi
nohup $QS/usr/bin/qemu-system-i386 $ARGS > $G/qemu.log 2>&1 &
echo "qemu started pid $!"
```

ポイント:
- `-device rtl8139,...,romfile=` の `romfile=`（空）が無いと PXE ROM 不足で落ちることがある。
- ゲストメモリは 1024MB。これ以上増やすとホスト側が苦しくなる（§9）。

## 7. Elona をゲストへ入れて起動する

1. ISO を作る: elona フォルダの**中身が ISO のルートに来る**ように `genisoimage -o elona.iso -V ELONA <elonaフォルダ>/`
2. `bash run_guest.sh elona` で起動し、ReactOS の cmd から D: の内容をコピー:
   `xcopy D:\ C:\elona\ /E` 相当で `C:\elona` へ配置。
3. 起動: Win+R → `C:\elona\elona.exe`。タイトル「Elona ver 1.22」が出て日本語が化けなければ成功。
   （ロケールが US のままでも表示は正常だった。）
4. 再開の定型: タイトルで「冒険を再開する」→ セーブ（例: sav_Nekone）を選ぶ。
   自動化する場合は sendkey で `a` 2回等、実績のある手順を使う。
5. config は日本語・ウィンドウ 800x600・オフラインにしておく。

## 8. 入力と画面のクセ

- **キーボード（モニタ `sendkey`）が唯一の確実な入力。** USB タブレットのマウスポインタは
  このゲストでは動かない/当てにならないことが多い。クリック前提の手順は組まない。
- ゲストのキーボードは英字配列のみ。日本語の名前入力等は英字で代替する。
- キーは短打で抜けることがある。確定系は 400〜600ms の長押しを指定する。
- **修飾キー単体（Alt 等）を sendkey しない。** ReactOS 側に Alt が残留して以降の入力が化ける。
  キー異常が Elona 再起動で直らない場合は、モニタ `system_reset` でゲストごと再起動すると直る（実績）。
- 画面取得はモニタ `screendump` → PPM → PNG。重い時は 1 回 15〜79 秒かかることがある（§9 とも関係）。

## 9. メモリと安定性（運用前に必ず読む）

- ホストは約8GB、スワップなし。内訳の目安: QEMU ゲスト RSS 約1.3GB + ホスト側の作業プロセス。
  空き（available）が数百MBまで落ちる局面が普通にある。
- **数時間に1回程度、QEMU や監視役が落ちたり、ゲスト再起動が必要になったりする**（2026-11-01 の実績:
  ホスト再起動・OOM によるゲスト終了・原因不明の QEMU+監視同時停止など、1日で複数回）。
  「落ちない前提」の手順は組まないこと。
- 対策として常駐の自動復旧を置く:
  - supervisor ループ（30秒間隔で QEMU の生死を見て、落ちていれば `run_guest.sh elona` で立て直す。
    停止用フラグファイル `.no-autostart` を置くと再起動しない）
  - 実績: 手動で QEMU を殺して復旧まで約53秒、セーブからの再開で損失ゼロのケースもあった
- **メモリ解析でゲストを巻き添えにしない（最重要の事故防止）:**
  - ゲスト物理メモリのダンプは 1GB。`numpy` で int32 コピーすると 4GB になり、
    ホスト OOM で QEMU ごと落ちた実績がある。解析は `memmap` / uint8 ビューで狭く切る。
  - 解析ツールには `RLIMIT_AS` の自己上限（例: 3.5GB）を入れて「自分が先に諦める」形にする。
  - ゲストの `oom_score_adj` を -1000 にする保護は、このサンドボックスでは書き込みが EACCES で
    効かない場合がある。当てにせず、ツール側の上限を本命とする。
- **セーブの仕様:** Elona のセーブはマップ遷移時（街の出入り・ダンジョン入退場・入場時）に走る。
  ゲストが落ちると「最後の遷移以降の作業」は巻き戻る。大事な成果（購入・納品・報酬回収）が出たら、
  すぐに街を出入りしてセーブを確定させること。
- 並行実行の注意: 重い処理（apt-get update 等、RSS 1.5GB 級）を背後で走らせると
  空きメモリが一気に減る。プレイ中はホスト側の重作業を避け、`free` の available を節目で確認する。
  ローカル推論モデル等の常駐プロセス（約1.65〜2.3GB）はゲストと同居できないことが多く、
  「ゲスト最優先・モデルは空きが回復した時だけ短時間」が現実解だった。

## 10. 復旧の定型手順

1. モニタ接続が拒否される / 画面が取れない → QEMU が落ちているとみなす。
2. supervisor が生きていれば自動復旧を待つ（目安1分）。いなければ supervisor を起動し直してから
   `bash run_guest.sh elona`。
3. ReactOS デスクトップが出たら Win+R → `C:\elona\elona.exe` → 「冒険を再開する」。
4. 再開後、メモリ読みで位置・HP・所持金が記録と一致するか確認してから続行する。
   （一致すれば損失ゼロと判断できる。）
5. tesseract が消えていたら再インストールするまで OCR 系ツールは使わない（§4）。

## 11. うまくいった確認ポイント（チェックリスト）

- [ ] `/proc/self/status` の Seccomp を確認し、Wine ルートを早めに見切った
- [ ] QEMU はポータブル配置で、ホスト再起動後もパスが通る
- [ ] NIC 等のハードウェア構成をインストール時から固定した
- [ ] タイトル画面で日本語が化けていない
- [ ] セーブ→終了→再開の往復ができた
- [ ] supervisor の自動復旧を1回テストした（QEMU を殺して戻ること）
- [ ] ダンプ解析ツールにメモリ自己上限が入っている

---
出典メモ: 本書は ~/workspace/elona/guest/PROGRESS.md、guest/run_guest.sh、tools/guest_supervisor.sh、
reports/wine-retest-2026-11-01.md などの実績記録から再構成した。
