KeepWorlds

パルワールドの自動一時停止:何が止まり、何を失うのか

パルワールドのサーバーで言う自動一時停止は、別々の二つの機能を指します。留守のあいだパルを空腹にさせないのはそのうち片方だけです。仕組みと、その代わりに壊れるもの。

一日ぶりにログインしたら拠点がひどいことになっています。パルの半分は空腹、二匹は病気、箱には頼んでもいない鉱石が山積み。その間ずっと誰も接続していないのに、ワールドだけが動き続けていたわけです。この話をすると勧められるのが自動一時停止です。

ただしこの言葉は別々の二つの機能を指していて、片方は求めている結果をくれません。選ぶ前に、そこを分けておきます。

自動一時停止が指す二つのもの

料金を止めるほう。 誰も接続していない区間は課金しない方式です。料金が止まるには何かが止まっている必要があるのでワールドもたいていは一緒に止まりますが、この機能が売りにしているのは価格です。実際に効いてくるのはその先で、どう降りるのか、戻るまでどれだけかかるのか、のほうです。

ワールドを止めるほう。 ゲーム内の時間が進まなくなります。パルは食べず、作物は育たず、誰もいない拠点に襲撃も来ません。

どちらを売られているかは、二つ聞けば分かれます。一時停止中にワールドは進むのか、そしてまた遊べるようになるまで何分かかるのか。機能一覧のどの項目より、二つ目の質問のほうが実装を分けます。

誰もいないのにワールドが進む理由

専用サーバーは、ただ動き続けるプロセスです。最後の一人が抜けても休みに入らず、満員のときと同じ周期でワールドを計算し続けます。拠点のパルは働き続けて空腹になり、作物は育ち、誰も守っていない拠点にも襲撃イベントはそのまま来ます。

ゲーム内でワールドを開く方式(一人が開いて残りが入る形)から移ってきたなら、ここで習慣がずれます。あちらはワールドがその人のゲームの中にあるので、その人が終了すればワールドも止まります。専用サーバーはわざと逆に作られた仕組みです。いつでも入れるように起動しているということは、誰も入らない時間帯にも同じだけ起動しているということだからです。二つの方式がワールドをどこに置くのかはパルワールドのマルチプレイ方式の比較にあります。

自動一時停止は実際にどう動いているのか

出回っている自動一時停止の多くは、OS のシグナル二行が本体です。

kill -STOP <pid>   # その場で凍らせる
kill -CONT <pid>   # 続きから動かす

SIGSTOP はパルワールドのコマンドではなく、ゲームはそんなことが起きたことすら知りません。カーネルがそのプロセスに CPU を割り当てなくなるだけです。メモリも開いたファイルも UDP ポートも握ったまま、実行だけしない状態になります。SIGCONT を受けると凍った当の命令から再開し、サーバーは時間が経ったことを知らないまま続きを実行します。

すでにご存じの二つの状態の間に置くと、こうなります。

凍結停止稼働中
プロセスある(実行はしない)ない実行中
メモリ握ったまま解放使用中
ゲームポートカーネルが保持、パケットは並ぶ閉じる応答中
ワールド内の時間止まる止まる進む
戻るまで数秒起動+ワールド読み込み

この二行を安全に使うには、周りにあと三つ必要です。

  1. 凍らせる前に強制セーブ。 SIGSTOP は捕まえることも、ブロックすることも、無視することもできません。確実な代わりに、サーバーに後始末の猶予を一瞬も与えないということです。メモリにあってディスクに降りていないものは、メモリに残ったままになります。その状態で電源が落ちれば、その分は消えます。
  2. 誰かがネットワークを見張る必要があります。 凍ったプロセスは接続に応答できないので、人が来たことにも気づけません。別の何かがインターフェースに張り付いて、入ってきたパケットを見て SIGCONT を送る役をします。ゲームサーバーの隣に root で動くパケットスニファを一つ置く、ということです。
  3. 一覧に残す役も要ります。 サーバーがゲーム側のバックエンドに送っていた合図も一緒に止まるので、凍ったサーバーはコミュニティサーバー一覧から消えます。残しておくには、別の何かがそのサーバーのふりをしてバックエンドと通信し続けるしかありません。そのサーバーの認証情報と、送っていた内容をそのまま使って。

どれも発売元が用意した機能ではありません。公式 REST API にあるのは /save/shutdown/stop/announce、キックと BAN で、一時停止はありません(エンドポイント一覧)。上のすべてはゲームの外側から、そんなことが起きていると知らないゲームに対してやっていることで、ゲームのアップデート一つで三段階のどこでも足場が変わり得ます。

自宅の機械なら妥当な取引です。あちらの目的は電気代ですから。ただ、運用を人に預けているサーバーでは、別の方法でも得られる結果のために、上の三つとその壊れ方まで一緒に買うことになります。

もっと単純なやり方:止めてしまう

「一時停止」で望まれているのは、ほとんどの場合 遊んでいない間はワールドも動かないでほしい です。サーバーを止めれば、それがそのまま手に入ります。仕掛けは何も要りません。ワールドはディスクに降り、実行されるものがない以上ゲーム内の時間は進みようがなく、起動し直せばそのセーブから続きます。

安全に止める順番は、定時再起動で使うものと同じです。

PW='a-long-password'
API='http://127.0.0.1:8212/v1/api'
# 1. まだ残っている人にカウントダウンで予告
curl -s -u "admin:$PW" -X POST "$API/announce" \
     -H 'Content-Type: application/json' \
     -d '{"message":"60秒後にサーバーを停止します。安全な場所へ"}'
# 2. ワールドをディスクへ強制セーブ
curl -s -u "admin:$PW" -X POST "$API/save"
# 3. 60秒のカウントダウン後に安全な停止処理
curl -s -u "admin:$PW" -X POST "$API/shutdown" \
     -H 'Content-Type: application/json' \
     -d '{"waittime":60,"message":"60秒後にサーバーを停止します"}'

セーブを停止より先に置くのは、公式のリファレンスが停止時にセーブするかどうかを明言していないからです。同じ順番が REST API ガイド定時再起動のレシピにもあります。

代償のほうも隠す必要はありません。戻るのに起動とワールド読み込みの分だけかかります。一瞬ではありません。夜に集まって遊ぶ仲間内なら、先に来た人が起動してお茶を淹れに行けば済みます。予告なしにいつでも人が来るサーバーなら、その一分こそが凍らせる方式を選ぶ理由です。

止めるほうを自動化する

手で止めるので足りるのは、夜に集まる仲間内の場合です。勝手にやってほしいなら、自動化するのは止めるほうで、凍らせるほうではありません。サーバーに今何人いるかを聞いて、その答えで動くタイマーがあれば済みます。systemd のタイマーか cron で5分おきに回します。

#!/bin/bash
set -o pipefail
PW='a-long-password'
API='http://127.0.0.1:8212/v1/api'
STATE=/var/lib/palworld-empty-rounds
MAX=6   # 6回 x 5分 = 30分無人

n=$(curl -sf -u "admin:$PW" "$API/metrics" | jq -r '.currentplayernum') || exit 0
case "$n" in ''|*[!0-9]*) exit 0 ;; esac   # 数値でなければ何もしない
[ "$n" -gt 0 ] && { rm -f "$STATE"; exit 0; }

rounds=$(( $(cat "$STATE" 2>/dev/null || echo 0) + 1 ))
echo "$rounds" > "$STATE"
[ "$rounds" -lt "$MAX" ] && exit 0

curl -s -u "admin:$PW" -X POST "$API/save"
curl -s -u "admin:$PW" -X POST "$API/shutdown" \
     -H 'Content-Type: application/json' \
     -d '{"waittime":10,"message":"接続者がいないためサーバーを停止します"}'
rm -f "$STATE"

二か所が効いていて、一つ目がそのまま落とし穴です。失敗した問い合わせは空のサーバーではありません。 ところがパイプが返すのは curl ではなく jq の終了コードで、jq は死んだエンドポイントに null と答えて平然と終わります。pipefail と数値チェックが無ければ、その null が「0 より大きくない」になり、ポートが一度つまずいただけで十人入っているサーバーが落ちます。二つ目は、カウンタを sleep ループではなくファイルに置いてあること。再起動が数えかけのカウントを残しません。

難しいほうの半分はこのスクリプトにありません。戻すほうです。 ここにあるどれもサーバーを起こし直せません。止まったマシンには、頼みを聞く耳がそもそも無いからです。選択肢は、通信を見張る別のマシンか、そのマシンにシェルを持つボットか、誰かが systemctl start と打つか。止めるのは cron 一行、起こすのは判断、というこの非対称こそが凍らせる方式の存在理由であり、その方式が root でパケットスニファを回さざるを得ない理由でもあります。

どちらも要らないかもしれません

気になっているのが「ワールドが進んだこと」全体ではなく、その一部なら、設定ファイルで直接そこに届きます。一時停止と違って、遊んでいる間にも効きます。

設定何が変わるか
PalStomachDecreaceRateパルが空腹になる速さ。下げておけば一晩空けても餌箱が空になりません(綴りが違うのはゲーム側です)
bEnableInvaderEnemy拠点の襲撃イベント。オフなら誰も守れない拠点に襲撃が来ません
WorkSpeedRate拠点のパルの作業速度。「留守の間に進みすぎた」のもう半分です

既定値と、性能を削る項目まで含めた全体はパルワールドのサーバー設定まとめにあります。

よくある質問

誰も接続していなくてもパルワールドのサーバーはワールドを動かし続けますか?

はい。専用サーバーは接続の有無に関わらずワールドを計算するので、誰もいないサーバーでもパルは食べ続け、作物は育ち、襲撃も来ます。止める方法はプロセスを凍らせるか、サーバーを停止するかの二つだけです。

自動一時停止はパルワールドの標準機能ですか?

いいえ。専用サーバーに一時停止コマンドはなく、公式 REST API にもそのエンドポイントはありません。自動一時停止として売られているものは、すべてゲームの外側でやっていることです。OS のシグナルでプロセスを凍らせるか、サーバーを止めて必要なときに起動し直すか、どちらかになります。

誰もいないときにパルワールドのサーバーを自動で止められますか?

はい。/metrics で人数を確認し、無人のまま既定の回数を過ぎたら /save/shutdown を呼ぶタイマーで、十五行ほどです。起こし直すほうは同じやり方では自動化できません。止まったサーバーには、頼みを聞く耳が無いからです。

パルワールドのサーバーを停止すると進行は失われますか?

先にセーブしていれば失われません。カウントダウンで予告し、POST /save を通してから停止すれば、ディスク上のワールドは最新で、起動し直せばそこから続きます。失われるのは書き込みの最中にプロセスが切れたときで、停電や、セーブなしの /stop がそれに当たります。

サーバーを止めればパルは空腹にならずに済みますか?

止まっている間はそうです。空腹を含め、ワールドの何も進みません。ただし遊んでいる時間については何も変えません。戻るたびに餌箱が空なのが問題なら、PalStomachDecreaceRate のほうが何も止めずに解決します。

レンタルサーバーではどこにあるか

KeepWorldsパルワールド専用サーバーでは、サーバーの停止と起動はコンソールマイサーバーから入ったサーバー詳細のボタン一つです。そのボタンの裏で起きているのが、上に書いた予告 → セーブ → 停止の順番です。まずゲーム内にサーバーアナウンスが流れ、カウントダウンが終わってから強制セーブが入り、そのあとで静かになります。これが安全な停止処理で、「とりあえず止めておく」を賭けではなく習慣にしてくれる部分です。

その隣に二つあります。バックアップが定期的に走って直近のものが残るので(完全なバックアップに入るもの)、止めた時点の状態は、停止そのものが失敗していても戻せます。そして毎日の定時再起動が同じページのスイッチと時刻として置いてあります。長く起動しっぱなしのサーバーに溜まるメモリの話は定時再起動にまとめてあります。

コンソールのバックアップ履歴。止めた時点の状態もここに残ります

ここに無いのは自動の待機停止です。接続人数を見張って代わりに止めてくれる仕組みはありません。誰かがボタンを押します。金曜と土曜に集まる仲間内なら、週に二回押す代わりに、その間ワールドは歳を取りません。逆にそもそも降ろしたくないなら、起動し続けるための三つの仕組みをパルワールドのサーバーを24時間動かし続けるにまとめてあります。

他の言語で読む

自分で運用しない方法もあります

ゲームとプランを選ぶだけで、専有マシン上にサーバーが立ち上がります。バックアップ、アップデート、期限のお知らせはこちらで対応いたします。

プランを見る