
2026/03/19 4:01
**Show HN:** 長時間戦略ゲーム「FreeCiv」を友人とプレイする
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
要約
本書は、Freeciv Longturn サーバー(Freeciv 3.2.3)を Fly.io 上でデプロイし運用する方法を説明しています。単一の Docker コンテナがポート 5556 で
を実行し、BusyBox HTTP プロキシがfreeciv-serverからライブステータスページを提供します。/tmp/server-input
永続データはに保存され、圧縮されたゲームセーブファイル(/data/saves)、SQLite 認証 DB(lt-game-*.sav.gz、freeciv.sqliteとfcdb.confで設定)および JSON ファイル(database.lua、status.json、history.json、attendance.json、diplomacy.json)が含まれます。gazette.json
コアスクリプトは次の通りです:
でサーバーを起動します。entrypoint.sh → start.sh は 23 時間のターン、10 時間のユニット待機時間、および ALLIED 勝利条件を設定します。longturn.serv は cron により 5 分ごとに実行され、クライアントが描画するステータス JSON(ランキング、チャート、外交、カウントダウン、ガゼット)を生成します。generate_status_json.sh- メールユーティリティ(新ターン開始の
、2 時間締切のturn_notify.sh)はturn_reminder.shで制御されます。email_enabled.settings- プレイヤー管理は
により行われ、SQLite 認証 DB とサンプルmanage_players.shを使用します。players.conf- その他ヘルパー:
(締切の上書き)、fix_turn_timer.sh(金額調整)、change_gold.sh(OpenAI 搭載新聞生成)、generate_gazette.sh(国リストページ生成)。generate_nations.sh
サーバーは再起動時にセーブファイルから値を読み取り、残り時間を再計算することでターンタイマーを保持します。phase_seconds
デプロイは Fly.io の CLI、Dockerfile、および保存用永続ボリュームをマウントした設定で行い、シークレットには SES SMTP 資格情報と OpenAI API キーが保管されます。fly.toml
代表的な操作は:、コンテナへの SSH 接入、強制セーブ、ステータス JSON 再生成、金額変更、締切上書き、メールトグル、アプリ再起動などです。fly deploy
この改訂要約はリストの主要ポイントをすべて網羅しつつ、主旨を明確に保ち、曖昧な表現を避けています。
本文
Freeciv Longturn Server
自己ホスト型の Freeciv 3.2.3 マルチプレイヤーサーバーで、長時間ターン(23 時間)を想定しています。
Fly.io 上で動作し、メール通知・ライブステータスページ・AI が生成する新聞機能があります。
- ライブデモ: https://freeciv.andrewmcgrath.info
- 現在 16 人が参加しているアクティブゲームが稼働中です。ライブランキングやターンカウントダウン、ヒストリーチャート、外交追跡、AI が作成した戦時新聞などはステータスページでご確認いただけます。
Longturn とは?
Longturn は Freeciv のマルチプレイヤー形式の一つで、1 ターンが数分ではなく約 23 時間続きます。
プレイヤーは毎日ログインし、行動を決定したら Turn Done をクリックして生活に戻ります。
全員がターン終了(またはタイマー切れ)すると次のターンへ移行します。
アーキテクチャ概要
┌─────────────────────────────────────────────────┐ │ Fly.io コンテナ │ │ │ │ entrypoint.sh │ │ ├── busybox crond (ステータスページ更新) │ │ └── start.sh │ │ ├── freeciv-server (ポート 5556) │ │ ├── busybox httpd (ポート 8080 → 80/443) │ │ ├── FIFO コマンドライター │ │ ├── Turn change watcher │ │ ├── Auto‑saver (5 分ごと) │ │ └── Turn reminder checker │ │ │ │ /data/saves (永続ボリューム) │ │ ├── lt-game-*.sav.gz – セーブファイル │ │ ├── freeciv.sqlite – プレイヤー認証DB │ │ ├── status.json – ライブゲーム状態 │ │ ├── history.json – ターンごとの統計 │ │ ├── attendance.json – 欠席したターン │ │ ├── diplomacy.json – 関係性 │ │ └── gazette.json – AI 新聞記事 │ └─────────────────────────────────────────────────┘
サーバーは FIFO パイプ (
/tmp/server-input) を介して通信します。スクリプトはこのパイプに書き込むことで実行中の Freeciv サーバーへコマンドを送ります。
スクリプト
| スクリプト | 目的 |
|---|---|
| entrypoint.sh | コンテナ起動時のエントリーポイント。crond を開始し、権限を下げて を実行します。 |
| start.sh | メインオーケストレーター。Freeciv サーバー、FIFO パイプ、自動セーブ、ターンウォッチャー、リマインダー・ループ、HTTP サーバーを起動し、再開時のタイマー継続ロジックも処理します。 |
| longturn.serv | ゲーム設定:23 時間ターン、10 時間 unitwaittime、同盟勝利のみ、プレイヤーリストなど。 |
ステータスページ
| スクリプト | 目的 |
|---|---|
| generate_status_json.sh | セーブファイルからゲーム状態を抽出し JSON に変換します。cron(5 分ごと)とターン変更時に実行され、・・・ を生成します。 |
| www/index.html | クライアント側ステータスページ。JSON を取得してランキング、チャート(Chart.js)、外交、カウントダウンタイマー、新聞記事を描画します。 |
| www/cgi-bin/health | ヘルスチェックエンドポイント。 が 7 分以上古い場合は 503 を返します。監視ツールで利用。 |
通知
| スクリプト | 目的 |
|---|---|
| turn_notify.sh | 新しいターン開始時に全プレイヤーへ HTML メールを送信。ランキング表、新聞記事、締切情報が含まれます。 |
| turn_reminder.sh | 60 秒ごとに実行。締切の 2 時間前までに「Turn Done」をクリックしていないプレイヤーへリマインドメールを送ります。 |
| turn_notify.lua | Freeciv のシグナルハンドラで、ターン変更時に をトリガーします。 |
プレイヤー管理
| スクリプト | 目的 |
|---|---|
| manage_players.sh | SQLite 認証 DB にプレイヤーアカウントを作成し、ウェルカムメールを送信、プレイヤー一覧を表示します。 |
| fcdb.conf / database.lua | SQLite 認証 DB の設定と初期化。 |
ユーティリティ
| スクリプト | 目的 |
|---|---|
| fix_turn_timer.sh | ターン締切を特定の時刻(例:)にオーバーライドします。次ターンでは通常の 23 時間タイムアウトに戻ります。 |
| change_gold.sh | Lua コマンドでプレイヤーの金額を調整 ()。 |
| generate_gazette.sh | OpenAI を呼び出し「The Civ Chronicle」を生成。各ターンごとに時代に合った不正確な戦時新聞記事を作成します。 |
| generate_nations.sh | 利用可能な全国一覧の静的 HTML ページを生成します。 |
| local_preview.sh | セーブファイルデータでローカルにステータスページをプレビューします。 |
設定ファイル
| ファイル | 目的 |
|---|---|
| email_enabled.settings | / により全メール通知を有効/無効化します。 |
| crontab | cron スケジュール。5 分ごとに を実行。 |
| fly.toml | Fly.io デプロイ設定(リージョン、VM サイズ、ポート、ボリューム)。 |
| Dockerfile | マルチステージビルド:Freeciv 3.2.3 をソースからコンパイルし、軽量ランタイムイメージを作成。 |
セットアップガイド
前提条件
- Fly.io CLI (
)flyctl - Docker(ローカルビルド/テスト用)
- AWS アカウントに SES を設定済み(メール通知用)
- OpenAI API キー(AI 新聞機能オプション)
-
クローン&設定
git clone <repo‑url> cd freeciv-server cp .env.sample .env
を編集し認証情報を入力します:.envSES_SMTP_USER=your-ses-smtp-username SES_SMTP_PASS=your-ses-smtp-password SES_SMTP_HOST=email-smtp.us-east-1.amazonaws.com OPENAI_API_KEY=your-openai-key # optional, for gazette -
ゲーム設定をカスタマイズ
を編集:longturn.servtimeout 82800 # ターン長(秒) 23 時間 unitwaittime 36000 # ダブルムーブ防止 10 時間 victories ALLIED # 勝利条件プレイヤーコマンドを末尾に追加。
-
プレイヤー追加
cp players.conf.sample players.conf
を編集:players.confPLAYERS=( "player1:pass123:player1@example.com:Australian" "player2:pass456:player2@example.com:Canadian" # … add one line per player )フォーマットは
。"username:password:email:nation"
このファイルは git‑ignore され、認証情報はローカルに残ります。
とlongturn.serv
のstart.sh
エントリに対応するaitoggle
コマンドを追加してください(create
を参照)。HOWTO-PROVISION-PLAYERS.md -
Fly.io へデプロイ
fly launch --name your-app-name fly volumes create freeciv_saves --size 1 --region your-region fly secrets set \ SES_SMTP_USER=your-ses-smtp-username \ SES_SMTP_PASS=your-ses-smtp-password \ OPENAI_API_KEY=your-openai-key fly deploy -
プレイヤーアカウント作成
./manage_players.sh create-all # すべてのアカウント + ウェルカムメール送信 # 単一プレイヤーの場合: ./manage_players.sh create username password email@example.comSQLite 認証 DB に書き込み、各プレイヤーへ接続手順付きウェルカムメールを送信します。
-
接続情報共有
プレイヤーは Freeciv 3.2.3 クライアントで次の設定を使用して接続します:- ホスト:
your-app-name.fly.dev - ポート:
5556 - ユーザー名/パスワード:作成時に指定したもの
ステータスページは
で確認できます。https://your-app-name.fly.dev - ホスト:
よくある操作
# 変更をデプロイ fly deploy # コンテナへ SSH fly ssh console --app your-app-name # 強制セーブ fly ssh console --app your-app-name -C "sh -c 'echo save > /tmp/server-input'" # ステータスページ再生成 fly ssh console --app your-app-name -C "/opt/freeciv/generate_status_json.sh" # サーバーログ確認 fly ssh console --app your-app-name -C "tail -50 /data/saves/server.log" # ターン締切を 4 AM に変更 ./fix_turn_timer.sh 4 # プレイヤーの金額を変更 ./change_gold.sh playername 100 # メール通知をオフにする # `email_enabled.settings` を "false" に編集し、再デプロイ # サーバー再起動(タイマーは継続) fly apps restart your-app-name
ゲーム状態の変更方法
ゲーム中に状態を安全に変更する最も確実な手段はセーブファイルを直接編集することです。
FIFO コマンドは約 200 文字を超えると崩れ、サーバー側で多くのコマンドが途中でブロックされます。
-
強制セーブ
fly ssh console --app your-app-name -C "sh -c 'echo save > /tmp/server-input; sleep 3'" -
ダウンロード
fly ssh console --app your-app-name -C "cat /data/saves/save-latest.sav.gz" > /tmp/save.sav.gz gzip -dc /tmp/save.sav.gz > /tmp/save.txt -
を編集(プレーンテキスト INI 形式)。/tmp/save.txt -
アップロード&再起動
gzip -c /tmp/save.txt > /tmp/save-edited.sav.gz cat /tmp/save-edited.sav.gz | base64 | fly ssh console --app your-app-name \ -C "sh -c 'base64 -d > /data/saves/save-latest.sav.gz'" fly apps restart your-app-name
再起動時のレジリエンス
サーバーは再起動やリデプロイ時にターンタイマーを保持します。
start.sh は:
- セーブファイルから
(現在のターン経過秒)を読み取ります。phase_seconds - 残り時間=
を計算し、正しい締切を再設定します。timeout - phase_seconds - プレイヤーがタイムロスしないようにします。
環境変数
| 変数 | 必須 | デフォルト | 説明 |
|---|---|---|---|
| はい | — | AWS SES SMTP ユーザー名 |
| はい | — | AWS SES SMTP パスワード |
| いいえ | | SES SMTP エンドポイント |
| いいえ | — | AI 新聞用 OpenAI API キー |
| いいえ | | サーバーのホスト名(メール/ステータスページ) |
| いいえ | | 送信者メールアドレス |
本番環境では Fly.io のシークレットとして設定します:
fly secrets set SES_SMTP_USER=... SES_SMTP_PASS=... OPENAI_API_KEY=...
プロジェクト構成
├── Dockerfile # マルチステージビルド(Freeciv コンパイル + ランタイム) ├── fly.toml # Fly.io 設定 ├── entrypoint.sh # コンテナエントリーポイント ├── start.sh # サーバー起動オーケストレーター ├── longturn.serv # ゲーム設定 ├── fcdb.conf # 認証 DB 設定 ├── database.lua # DB 初期化 ├── crontab # スケジュールタスク ├── email_enabled.settings # メール通知トグル ├── turn_notify.lua # ターン変更シグナルハンドラ ├── generate_status_json.sh # ステータスページデータパイプライン ├── generate_gazette.sh # AI 新聞生成 ├── generate_nations.sh # 国一覧ページ生成 ├── turn_notify.sh # ターン通知メール送信 ├── turn_reminder.sh # 締切リマインダーメール ├── manage_players.sh # プレイヤーアカウント管理 ├── fix_turn_timer.sh # 手動締切オーバーライド ├── change_gold.sh # 金額調整ユーティリティ ├── local_preview.sh # ローカルステータスページプレビュー ├── .env.sample # 環境変数テンプレート └── www/ ├── index.html # ステータスページ(JS 測定) ├── changelog.html # ゲーム変更履歴 └── cgi-bin/ └── health # ヘルスチェックエンドポイント
CLAUDE.md – 運用参考資料。