バグのせいです。
6/9 解決済み: 末尾に追記
こんばんはお疲れさまです。
この度多大なる迷惑を現在も継続しておかけしておりますあの入り口について、現状どのような感じかお伝えしようと思います。
仕組み
PassageTeleportというUdonがあの機構全体を管理しています。基本的にはdisableの状態です。
bool open; // 開こうとしてるときのみ true float openTime; // 開き始めてからの時間 bool closing; // 閉じる遷移のときのみ true float closeTime; // 閉じ始めてからの時間 bool sleep; // テレポート直後は一度区画から出るまで処理を貫通 public void Update() { if (player == null) return; Vector3 playerPos = player.GetPosition(); if (open) { openTime += Time.deltaTime * 0.5f; if (side0) { // (ドア0のアニメーション) if (insideClose0.Contains(playerPos) && !sleep) { open = false; closing = true; closeTime = 0; } else { if ((openTime > 5.0f || sleep) && !outsideClose0.Contains(playerPos)) { open = false; closing = true; closeTime = 0; } } } else { // (ドア1のアニメーション) if (insideClose1.Contains(playerPos) && !sleep) { open = false; closing = true; closeTime = 0; } else { if ((openTime > 5.0f || sleep) && !outsideClose1.Contains(playerPos)) { open = false; closing = true; closeTime = 0; } } } } if (closing) { closeTime += Time.deltaTime * 0.5f; if (side0) { // (ドア0のアニメーション) } else { // (ドア1のアニメーション) } if (closeTime > 1f) { closing = false; enabled = false; } } if (!open && !closing && !sleep) { if (bounds0.Contains(playerPos)) { Teleport0to1(playerPos); } else if (bounds1.Contains(playerPos)) { Teleport1to0(playerPos); } } else { if (sleep && !open && !closing) { if (!bounds0.Contains(playerPos) && !bounds1.Contains(playerPos)) { sleep = false; } } } }
概ねこんな感じになっています。最悪ですね。
ただまぁconsistencyとしてはいくらかわかりやすい部分があって。closing = true
のとき、一定時間経つと closing = false
になるはずなんですよ。
何故なら closeTime
はだんだん増加していくはずで、closing = true
に成るとき同時に closeTime = 0
になるから、そして closeTime > 1
のとき closing = false
になるからです。
だから扉が途中で止まるはずないんですよ。
調査報告
enabled = false
は怪しいよなぁ、とは思って、enabled
への代入を Update
末尾に行うようにしたんですが、変わりませんでした。
仮説としては「Update内でenabledをfalseにすると、Udonの実行時間チェックとかのコンテキストスイッチによって以降不活性化する」みたいなことを考えていたんですが、これは「enabledじゃないのにメソッドが呼べる」ことに反するのできっと違います。
ちなみに enabled = false
にして直後 10000 回のループを回すテストをしてみましたが、ちゃんとラグは発生するけど別に途中で止まったりはしませんでした。
不思議なのは、一度死ぬとあのボタンが一切動かなくなることです。
public void Open0() { if (open || closing) return; open = true; openTime = 0; side0 = true; }
ボタンを押す方のUdonではPassageTeleportのenableをしているので、Open0
がちゃんと最後まで呼ばれていれば次の瞬間扉は初期位置に戻るはずです。
つまり open || closing
が成立してそうな雰囲気がします。
そして「閉じかけの扉」については open
は成立しません。つまり「閉じかけで固まる状態」は、 closing = true
ではないかと推測されます。
しかしこれは先の話と矛盾します。何故進行しないのか。
そうすると残る不審箇所は Time.deltaTime
しかないのです。はて。
あと強いて言うなら、上の記述では省略したんですが、何故か Open0
と Open1
の呼び出し時についでに player = Networking.LocalPlayer
をやっているらしいです。
それが何故か null
になって Update
が走らなくなるのはありうるのかな…とは思いましたが、別にボタンを押してないのに急に扉が途中で止まるのはやっぱり変だと思うのです。
結論
ちなみにこの不具合、人数が多くないとなかなか発現しません。まぁ。
なんだろう。なんなんでしょうね。ほんとご迷惑おかけしております。
enabled
が死んだときの対策として EmergencyButton
を追加したんですが、でも普通に enabled = true
っぽいので多分効果は出てないのです。これ。
player
か、Time.deltaTime
か…。前者説はありそうだけどじゃあなんで Networking.LocalPlayer
が気まぐれで null
になるんかっていう話なんだよな…
もうちょっと調査はしようと思います。そしてまぁ最悪ケースの為のセーフティは入れようと思います、よろしくおねがいします。
お急ぎのところ、ご迷惑をおかけしています。
追記。
RunEvent will clear incorrect event parameter names
— phi16 (@phi16_) 2021年6月8日
これじゃん~~~~~~~~~~~~~~~~~~~~~~~~~~は~~~~~~~~~~~~~~~~~~~~~
つまり発動条件は「扉を開いて閉じきるまでにプレイヤーがjoinすること」ということになる
— phi16 (@phi16_) 2021年6月8日
そら再現せんわ
— phi16 (@phi16_) 2021年6月8日
以上です。ありがとうございました。