土屋つかさの技術ブログは今か無しか

土屋つかさが主にプログラミングについて語るブログです。

#UEFN #Verse 3/28の"Ask Epic: Verse"で面白かった回答ピックアップ(その2)

Ask Epic 翻訳祭り第2回です。今回は「これは島クリエイトやるなら把握して置いた方がよさげ」という物をピックアップしています。

HTTPリクエストAPIの採用予定は無い(マジか!)

https://forums.unrealengine.com/t/ask-epic-verse-march-28-10-00-am-et/1765393/57?u=t.tutiya

Q:Fortnite外のAPIにアクセスするために、VerseにHTTPを組み込む予定はありますか? ユーザーデータをFortnite外のサービスと組み合わせられたらとてもクールだと思います。これが実現した場合、その認証プロセスはどのような物になり、悪質なユーザーを排除するためにどのような対策が講じられますか? OpenIDトークンのようなIDトークンプロセスが用意されるのでしょうか?

A:(HTTPリクエスト対応の)予定はありません。私たちは、Verseをオープン・メタバースに力を与える言語だと捉えており、そのため、様々な開発者によるVerseのコードが、安全な方法でインタラクトできる言語として成長させていくつもりです。ですから、それ(HTTPリクエスト対応)を永久に認めないとは言いませんが、(前提として)私たちのFortniteゲーマーやもっと多くの人たちのために、Verseを安全かつセキュアな物にしていくという大きな要求があります。

土屋解説

 個人的に今回のAsk Epicで一番インパクトのあった回答です。回答の文章にも力が入っているので、公式スタッフ側でも重要な質問だと捉えたのだと思います。

 HTTPリクエストというのは、大雑把に言うとインターネット経由で任意のサーバーとデータを送受信する機能の事です。

 現在の島クリエイトでは、パブリッシュ時に含まれたデータのみをリソースとして参照できます。これはつまり、ゲーム実行時においては画像データ1枚ですら、ローカルからアップする事も、ネット上から拾ってくる事もできないということです。これはリソースデータの運用に強い制限が掛かった状況だと言えます。

 もしHTTPリクエストが使えるようになれば現在の制約が大幅に緩和されます。というか、独自のサーバー間通信が可能になる訳ですから、リソースデータどころではなく実質的になんでも出来るようになります。ただしこれを許可した場合、当然ながら安全面セキュア面での対策がとても重要になります。この課題について質問側も回答側も言及している事からもその重要性がわかります。

 残念ながら、少なくとも現時点(≒fortnite上でのUGC環境におけるVerse)では、HTTPリクエスト機能の採用予定は無いというのが公式回答となりました。まあ、冷静に考えればそりゃそうだよねという印象ではありますが、この機能の採用を前提にUEFN/Verseの検証を進めていた商業チームも多くいた筈で、ショックが大きかったんじゃないかと思います。

 なお、ここで言及されている「オープン・メタバース」が意味する物については、以前土屋が作成したプレゼン資料が参考になるかと思います。

zenn.dev

実時間を取得したい

https://forums.unrealengine.com/t/ask-epic-verse-march-28-10-00-am-et/1765393/51?u=t.tutiya

Q:Verseを介して、フォートナイトでの体験を実世界時間と連動させる方法はありますか?

A:私自身は(実装予定有無を)把握していませんが、それがAPIとして有用である事は分かります。開発チームの尻を叩いておきます。

土屋解説

 質問の主旨は「Verseで現在時刻を取得する方法はあるか」と言い換えられます。実は現時点ではゲーム開始からの経過時間を取る事はできますが、現在時刻を取得するAPIはありません(!)。

 ただ、全地球規模で24時間稼働しているFortniteにおいて、どのロケールの時刻を取得するのかという問題もあり(グリニッジ天文時を渡されても困るし)、国際化対応(これもまだ無い)が先だと思われます。

mapへのsetが失敗コンテキスト内しか記述できない問題(1)

https://forums.unrealengine.com/t/ask-epic-verse-march-28-10-00-am-et/1765393/45?u=t.tutiya

Q:mapの追加/更新が失敗許容式になるのは何故ですか? どのような状況において失敗するのでしょうか? また、失敗した場合はどのように対応/処理すれば良いですか?

A:これ(失敗許容式扱いになること)は、現在のコンパイラの欠点です。mapに対する 特定のキー*1による値の「完全な割当」は常に成功します。(このような場合、)if{...}を使えば失敗する可能性を回避できます。

土屋解説

 mapへの参照は、存在しない要素にアクセスする可能性があるので失敗許容式です(これはわかる)。ところが、追加や更新の場合は常に成功する筈です。しかしmapへのsetは参照の場合と同じく、失敗コンテキスト内でしか記述出来ません(これがわからない)。これは何故なのかという質問。

 回答としては「mapへのsetを失敗コンテキスト内でしか記述出来ないのはミス」「mapの追加/更新は常に成功する」という物でした。ただしポイントは、常に成功するのは「完全な割当(A complete assignment of the value. )」の場合であるという事。この「完全な割当」については後述します。

 気になるのが「現在のコンパイラのミス*2」とう表現。「バグ」と明言してないので、これは仕様のままになるのかも……? 「"["~"]"が付与された識別子は失敗コンテキスト内でしか書けない」というのがVerse言語のコンセプトだった場合、治らない可能性があります。

 この「mapへのset問題」については過去何回か書いてるのでこちらも参照してください。

zenn.dev

someiyoshino.info

mapへのsetが失敗コンテキスト内しか記述できない問題(2)

 この質問も先程の「mapへのset問題」と同じ内容なのですが、解答者が異なり、setが失敗するパターンを紹介しています。

https://forums.unrealengine.com/t/ask-epic-verse-march-28-10-00-am-et/1765393/119?u=t.tutiya

Q:mapの値を変更するのに、なぜ失敗コンテキストを使う必要があるのですか?

A:以下のコードを見て下さい。

struct1 := struct<computes>:
  Data1:int
  Data2:int
var X:[int]struct1 = map{}
set X[0].Data1 = 1 

このsetは常に失敗します。mapの特定のキーへの「完全な割当」は常に失敗しませんが、「部分的な割当」は失敗する可能性があります。

土屋解説

サンプルコードの最終行に注目してください。

# map要素への部分的な割当
set X[0].Data1 = 1 

Xはstruct1構造体を取るmapです。X[0]には値が割り当てられていません。そのためX[0].Data1はC#で言うnull参照となり失敗します。

X[0]には値が入っていないので、まずは下記のコードのようにstruct1そのものを生成して割り当てる必要があります。

# map要素への完全な割当
set X[0] = struct1{Data1 = 1, Data2 = 2}

前者が「部分的な割当(=失敗する可能性がある)」、後者が「完全な割当(=常に成功する)」になります。しかし、前者のみをコンパイルエラーにするのは微妙に思えます*3

なので、「mapへのsetは失敗する可能性がある(から、失敗コンテキスト内でのみ記述する)」は妥当な言語仕様と言えるようです(気持ち悪くはあるのだけど)。

リビジョンコントロールへのVerse対応

https://forums.unrealengine.com/t/ask-epic-verse-march-28-10-00-am-et/1765393/56?u=t.tutiya

Q:リビジョンコントロールをVSCode内に組み込む予定はありますか?(差分、コミット履歴、条件付き書式などは?)

A:はい、現在取り組んでおり、まもなくリリースされる予定です。

土屋解説

UEFNにはリビジョンコントロールシステムというバージョン管理システムが用意されています。しかしこれはリソースデータ管理が主目的で、Verseソースコードを管理するには機能が不足していました。こちらは将来的に機能拡充が行われる用です。

実行時クラッシュについて(1)

https://forums.unrealengine.com/t/ask-epic-verse-march-28-10-00-am-et/1765393/103?u=t.tutiya

Q:どこかのタイミングで、何らかのクラッシュ制御構文を持つことになるのでしょうか?(try/catchや、デバイスを再起動する手段のような物)。

A:実行時エラーは決してキャッチすることはできません(送出されたエラーはMaxVerseが採用するセマンティクスにおいては補足されますが、現時点では未実装です*4)。ただし、ユーザー定義の例外を用いたtry/catchについては議論中です。

土屋解説

 Verseには例外処理機構(try/catch)がありません。これはVerseで発生する実行時エラーはユーザーが対処出来る物ではない為です(モダンなプログラミング言語に多い仕様です)。

 ただ、現実問題として今のVerseはVMのバグで実行時エラーが発生する事があり、その対処が出来ないのは困ります。対処療法でも送出された例外を補足&破棄する事でクラッシュを回避出来るならそうしたいので、このような質問になったのかと思われます。

実行時クラッシュについて(2)

先程と同じ実行時クラッシュについて。実は質問者も解答者も先程と同じで、実質的に続きの内容になります。

https://forums.unrealengine.com/t/ask-epic-verse-march-28-10-00-am-et/1765393/107?u=t.tutiya

Q:Verseのクラッシュが、OnBeginから呼び出されたコールスタック全体にクラッシュを引き起こすのはなぜですか?(戻り値のtaskを保持していないコルーチンが生成されてしまう事すらあります*5

A:Verseの実行時エラーは、Verse内から検出できるようには意図されていません。無理をすれば検出できるでしょうが、それに頼るべきではありません。(コード上の)どの地点においても、実行が停止する(≒実行時エラーが発生する)よりも前に、エラーが起きる可能性を検出できるのですから。

土屋解説

 質問も回答も翻訳に自信が無いので、気になる方は原文を確認してください。

 質問の意図は、先の回答の「実行時エラーはVerse内では補足出来ない」に対する反論で「OnBeginまで巻き戻ってデバイスがまるごと全部クラッシュするのは困るのでtry/catchで実行時エラーを補足させてくれ」という物です。

 それに対する回答は(土屋の訳が合っているなら)「実行時エラーが起きる事自体が問題なので、実行時エラーが起きる前にそれを見つけて回避してください」という物でした。これはVerseの失敗コンテキストの持つコンセプトに沿っているため、間違っていません(もっとVMが安定すれば、の話ですが)。

 とはいえ、現実問題として、デバイスが実行時エラーによりクラッシュしてゲームが進行出来なくなる状況が発生しているんだから、try/catchを入れるか、デバイスを再起動する機能を追加してくれと言いたくなる気持ちもわかります。

終わりに

今回はここまで。多分多くの人が知りたい情報はここまでで、以降はどんどんマニアックな質問になっていきます。

宣伝

Verse言語の言語仕様解説同人誌をPDFで頒布しています。よろしければどうぞ。

s-games.booth.pm


*1:a particular key. キーとして許されている値を指していると思われる

*2:a current shortcoming of the compiler.

*3:要素が存在するなら合法なので、そもそもコンパイルエラーに出来ない気もする

*4:平坦に訳せなかったので原文も参照して下さい

*5:コルーチンが生きているままクラッシュするとそのインスタンスがゾンビサーバーになってしまうようです