0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「接続OK」と出ているのに機能だけ動かない。ログを信じて3時間溶かしかけました

0
Posted at

個人開発をしています。無料の計算ツール集 ShibaHub、補助金を検索できる 補助金ナビ を運営していて、いまは3DのゲームをSteamに出す準備をしています。

そのゲームの通信を、Steamの仕組みに載せ替える作業をしていたときの話です。

初期化は成功している。ログにも「接続OK」と出ている。なのに、肝心の機能だけがエラーで落ちる。

原因の切り分けにかなり時間を使ったので、同じ形で詰まる人のために書いておきます。ゲームの話として書いていますが、外部サービスを使うプログラム全般で起きる話です。


何が起きたか

やりたかったのは「オンラインの部屋(ロビー)を作る」という処理です。

コードはこんな流れでした。

# ① 初期化する
var res = Steam.steamInitEx(app_id, false)
if int(res.get("status", -1)) == 0:
    print("接続OK")     # ← ここは通る

# ② 部屋を作る
Steam.createLobby(FRIENDS_ONLY, 8)
# → 失敗。エラーコード 3

①は成功します。ログにもちゃんと「接続OK」と出ます。
なのに②だけが 3 というコードで失敗する。

しかも困ったことに、少し前までは同じコードで成功していました。


やった切り分け

「さっきまで動いていたものが動かない」ので、まず自分が直した箇所を疑いました。ここが遠回りの始まりでした。

  • 直前のコミットを戻して試す → やっぱり失敗する
  • 別のもっと単純なテストで試す → やっぱり失敗する

ここでようやく「自分のコードじゃないかもしれない」と考えを切り替えました。

そこで、状態を全部そのまま出すだけの小さなスクリプトを書きました。

print("isSteamRunning = ", Steam.isSteamRunning())
print("loggedOn       = ", Steam.loggedOn())
print("initResult     = ", Steam.get_steam_init_result())

結果がこれです。

isSteamRunning = true
loggedOn       = false      ← ★これ
initResult     = { "status": 0, "verbal": "" }

Steamは起動している。初期化も成功している。でもログインしていない。

エラーコード 3 は「接続がない」という意味でした。つまりコードは正しくて、土台のほうがログアウトしていたわけです。


なぜログアウトしていたのか

犯人は、その少し前に自分で実行したコマンドでした。

ゲームのビルドをSteamにアップロードするために、steamcmd というコマンドラインツールで同じアカウントにログインしていました。これが、起動中のSteamクライアントのセッションを切っていたのです。

つまり自分で自分の足を撃っていました。


学んだこと1:「初期化できた」と「使える」は別物

ここがいちばんの学びでした。外部サービスを使うとき、状態は1つではなく段階になっています。

段階 確認する方法(Steamの例) これがfalseだと
ライブラリが読めている ClassDB.class_exists("Steam") 何も始まらない
アプリが起動している isSteamRunning() 初期化が失敗する
初期化に成功した steamInitEx() の戻り値 APIが呼べない
ログインしている loggedOn() APIは呼べるが、通信する機能だけ失敗する

自分は「初期化に成功した=使える」と思い込んで、available = true という1つのフラグにまとめていました。最後の段だけが崩れている状態を表現できていなかったわけです。

直したあとはこうしました。

# 「初期化できた」だけを持つフラグ
func logged_on() -> bool:
    return available and Steam.loggedOn()

# 通信が要る機能は、こちらで判断する
func usable() -> bool:
    return logged_on()

そして、使えないときは理由を文字列で返すようにしました。

func offline_reason() -> String:
    if not available:
        return status
    if not Steam.loggedOn():
        return "ログインしていません(オフラインか、ログインが切れています)"
    return ""

「使えません」だけだと、遊ぶ人は直しようがありません。何が起きているかまで出して、初めて対処できます。


学んだこと2:ログが親切だと、かえって疑えなくなる

今回いちばん厄介だったのは、ログに「接続OK」と出ていたことでした。

これは嘘ではありません。初期化は本当に成功しています。ただその先の段階までは保証していないだけです。

でも人間は「接続OK」と書いてあるものを疑いません。だから土台ではなく、自分の書いたコードを延々と読み直すことになりました。

いま思うのは、ログの文言は「何を確認したか」まで書いたほうがいいということです。

❌ 接続OK
⭕ 初期化OK(ログイン状態は未確認)

たった1行ですが、次に詰まった人の向く方向が変わります。


学んだこと3:迷ったら「状態を全部出すだけ」のスクリプトを書く

今回いちばん効いたのは、何も直さず、状態をそのまま出すだけの小さなスクリプトでした。

デバッグをしていると、つい「ここを直したらどうなるか」を試したくなります。でもそれは原因の見当がついているときにだけ有効です。見当が外れていると、直すたびに変数が増えて、ますます分からなくなります。

  • 直す前に、いま何がどうなっているかを全部並べる
  • 出す項目は多くていい。答えが分からないから調べているので

このスクリプトは捨てずに tools/ に置いて、手順書からも呼べるようにしました。同じことは必ずまた起きます。


まとめ

  • 外部サービスの状態は段階になっている。「初期化できた」と「使える」を分けて持つ
  • 使えないときは理由まで返す。「使えません」だけでは直せない
  • ログの「OK」は、どこまでのOKなのかを書く
  • 詰まったら、直す前に状態を全部出すだけのスクリプトを書く

ちなみに今回の件、ゲーム側は「Steamが使えないときは今までのやり方に自動で切り替わる」作りにしてあったので、遊べなくなること自体は起きませんでした。土台が落ちても止まらない道を用意しておくのは、やはり効きます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?