VRChat 非公式日本語ドキュメント

Data Tokens

Data Tokensはデータを保持するためのものです。各トークンは単一の変数のみを格納します。Data TokensはData DictionariesおよびData Listsで使用されます。

Data Tokensには、以下のToken Typesを含めることができます。

  • Null
  • Boolean
  • SByte
  • Byte
  • Short
  • UShort
  • Int
  • UInt
  • Long
  • ULong
  • Float
  • Double
  • String
  • Data Lists(他のDataTokensを格納)
  • Data Dictionaries(他のDataTokensを格納)
  • Object Reference(ボクシングを介してanythingを格納可能ですが、シリアル化はできません)
  • Data Errors(何が問題であったかを示す列挙型)

Properties

PropertyResult
TokenTypeこのDataTokenが保持している変数の現在のTokenTypeを返します。
IsNumberDataTokenが何らかの数値型を保持している場合はtrueを、それ以外の場合はfalseを返します。
IsNullDataToken内に含まれる値がいかなる形式であってもnullである場合にtrueを返します。数値型とbool型は決してnullにならず、TokenType.Nullは常にnullとみなされます。string型はnullであるかを確認しますが、空であるかは確認しません。参照型の場合は内部でUtilities.IsValidを使用し、退出したプレイヤーや破棄されたオブジェクトを適切に扱います。
BooleanDataTokenがboolを含んでいる場合にboolを返します。それ以外の場合は例外をスローします。
NumberDataTokenが任意の数値型を含んでいる場合、64-bitのdoubleを返します。それ以外の場合は例外をスローします。
SByteDataTokenがsbyteを含んでいる場合に8-bitの符号付きsbyteを返します。それ以外の場合は例外をスローします。
ByteDataTokenがbyteを含んでいる場合に8-bitの符号なしbyteを返します。それ以外の場合は例外をスローします。
ShortDataTokenがshort、sbyte、またはbyteを含んでいる場合に16-bitの符号付きshortを返します。それ以外の場合は例外をスローします。
UShortDataTokenがushortまたはbyteを含んでいる場合に16-bitの符号なしushortを返します。それ以外の場合は例外をスローします。
IntDataTokenがint、sbyte、byte、short、またはushortを含んでいる場合に32-bitの符号付きintを返します。それ以外の場合は例外をスローします。
UIntDataTokenがuint、byte、またはushortを含んでいる場合、32-bitのunsigned uintを返します。それ以外の場合は例外をスローします。
LongDataTokenがlong、sbyte、byte、short、ushort、またはuintを含んでいる場合、64-bitのsigned longを返します。それ以外の場合は例外をスローします。
ULongDataTokenがulong、byte、ushort、またはuintを含んでいる場合、64-bitのunsigned ulongを返します。それ以外の場合は例外をスローします。
FloatDataTokenがfloat、sbyte、byte、short、ushort、int、uint、long、またはulongを含んでいる場合、32-bitのfloatを返します。それ以外の場合は例外をスローします。
DoubleDataTokenがdoubleやその他の数値型を含んでいる場合、64-bitのdoubleを返します。それ以外の場合は例外をスローします。
StringDataTokenがstringを含んでいる場合、stringを返します。それ以外の場合は例外をスローします。
DataDictionaryDataTokenがData Dictionaryを含んでいる場合、Data Dictionaryを返します。それ以外の場合は例外をスローします。
DataListDataTokenがData Listを含んでいる場合、Data Listを返します。それ以外の場合は例外をスローします。
ReferenceDataTokenがオブジェクト参照を含んでいる場合、オブジェクト参照を返します。それ以外の場合は例外をスローします。
Errorこのトークンに関連付けられたエラーを返します。それ以外の場合は DataError.None を返します。他のプロパティとは異なり、このプロパティにアクセスしても例外がスローされることはありません。エラーではないトークンから Error にアクセスしようとした場合、単に DataError.None が返されます。

Functions

FunctionResult
BitcastDataToken 内の既存データを再利用し、型を変更します。C++ の reinterpret_cast や C# の BitConverter に似ています。変換先の型が変換元の型よりも小さい場合は値を切り詰め、変換先の型の方が大きい場合はゼロ拡張を行います。プリミティブ型に対してのみ機能し、コピーを返します。
ToStringトークンの内容を文字列に変換します。String プロパティへのアクセスとは異なり、この関数は基盤となる値の ToString を使用するため、常に成功します。
GetHashCodeトークンの内容のハッシュコードを返します。これは主に辞書のキーとして内部処理で使用されます。
CompareToこのトークンを別のトークンと比較します。比較対象のトークンの方が大きい場合は-1、等しい場合は0、小さい場合は1を返します。リストや辞書などのコンテナは、要素数によって比較されます。型が異なり、かつ数値型ではない2つのトークンを比較する場合は、TokenType列挙型の順序が使用されます。

DataTokenの作成

UdonSharp

UdonSharpでは、DataTokenを「暗黙的」に作成できます。つまり、関数がDataTokenを要求する際に、new DataToken(value)と記述する必要はありません。値を直接渡すだけで、自動的にDataTokenが作成されます。

DataTokenの作成
// You could do this
DataToken _explicitFloat = new DataToken(5.3f);
DataToken _explicitInt = new DataToken(5);
DataToken _explicitString = new DataToken("value");
DataToken _explicitBool = new DataToken(true);

// But this is easier and simpler
DataToken _float = 5.3f;
DataToken _Int = 5;
DataToken _String = "value";
DataToken _Bool = true;
警告

UdonSharpでDataTokenを暗黙的に作成するためにnameof()を使用しないでください。エラーが発生する可能性があります。

Udon Graph

Udon Graphでは、値を保持するDataTokenを作成するために、DataToken ImplicitノードまたはDataToken Constructorノードを使用する必要があります。
data-tokens-7GAcVrY.png

Data Tokenからの値の取得

DataTokenから値を取り出す前に、含まれている型を確実に把握する必要があります。互換性のない型を取り出そうとすると、UdonBehaviourが停止してしまうためです。含まれている型が目的の型と互換性があることを確認するには、いくつかの方法があります。

  • DataToken.TokenTypeプロパティを確認して、正確な型を取得できます。
  • Data ListやData Dictionaryから値を取得する際は、TryGetValueを使用してTokenTypeを指定できます。TokenTypeが正しくない場合、その関数はfalseを返します。
  • DataToken.IsNumberプロパティを確認して、数値かどうかを判定できます。数値である場合、Numberプロパティを安全に取り出すことができます。これは、元の型が何であれ、64-bitのdouble型にキャストされて返されます。元の型がlongulongであった場合、精度が失われる可能性があります。
  • トークンの型にかかわらず、ToStringは常に有効な選択肢であり、エラーが発生することはありません。
U#におけるDataTokenの取得
// If we know that it's a string, we can safely pull the string out of the token
if (unknownToken.TokenType == TokenType.String)
{
Debug.Log(unknownToken.String);
}

// We can use IsNumber to see if it's some type of number, even if we don't know which.
if (unknownToken.IsNumber)
{
Debug.Log(unknownToken.Number);
}

// If we're pulling a value from a container, we can use the version that does its own type check
if (dictionary.TryGetValue("key", TokenType.String, out DataToken value))
{
Debug.Log(value.String);
}

data-tokens-SqQqE5w.png

正しい型であることを確認できたら、DataToken.FloatDataToken.Boolean といった値プロパティにアクセスすることで、DataToken から値を取得できます。各型には、その特定の型を取り出すために使用できる専用のプロパティが用意されています。

扱うデータを完全に制御できている場合は、TokenType のチェックをすべて省略し、トークンから直接値を取得できます。これによりコードの記述量を減らすことができますが、外部ソースからデータが提供される場合や、データが別の型である可能性がある場合は、この方法をとらないようにしてください。

Shorthand Bracket 構文の例
dictionary["A"] = 5;
dictionary["B"] = 10;

// This makes the assumption that A and B will always contain integers.
// This is a safe assumption to make since we set them just above in a controlled environment.
// If the data is coming from an external source, we shouldn't make these assumptions!
int sum = dictionary["A"].Int + dictionary["B"].Int;

Errors

Data List や Data Dictionary に対する操作が失敗して DataToken が返される場合、エラー用のトークンが生成されます。エラー用トークンには、エラーの種類を分類する enum と、エラーの詳細を説明する文字列が含まれています。詳細な説明が不要なエラーの場合は、文字列が生成されないこともあります。

Error型のトークンがある場合、DataToken.Errorを使用してエラーのenumを取得し、DataToken.Stringでメッセージを取得できます。また、DataToken.ToString()を使用すれば、enumと文字列を自動的に結合した読みやすい完全なメッセージが生成されるため、単に Debug.Log(token) を呼び出すだけで済み便利です。

エラーの種類には、以下のものがあります。

意味
KeyDoesNotExistデータ辞書からキーにアクセスしようとしましたが、そのキーが存在しませんでした。
IndexOutOfRangeデータ配列のインデックスにアクセスしようとしましたが、指定したインデックスが0未満、または配列の要素数以上でした。
TypeMismatch値にアクセスしようとしましたが、その値が期待した型ではありませんでした。これは、型を指定するバージョンのTryGetValueを使用している場合にのみ発生することに注意してください。
TypeUnsupportedデータコンテナに、使用しようとしたシリアライズ形式ではサポートされていない型が含まれていました。これは、参照トークンをデータコンテナに入れ、それをJSONにシリアライズしようとした場合に発生する可能性があります。
ValueUnsupportedデータコンテナに、使用しようとしたシリアライズ形式でサポートされていない値が含まれていました。これは、NaNやInfinityの浮動小数点数をデータコンテナに格納し、それをJSONにシリアライズしようとした場合に発生することがあります。
UnableToParseシリアライズされた形式を解析できませんでした。これは、ソースとなるJSONが無効な場合に発生します。
TryGetValue with TokenType
if (dictionary.TryGetValue("key", TokenType.Float out DataToken value)) {
// If TryGetValue succeeds, we can do things with the token
Debug.Log($"Successfully retrieved value {token.Float}");
} else {
// If TryGetValue fails, the token will instead be an error
Debug.Log($"Failed to retrieve value with error {token.Error}");
}

data-tokens-zcqKePv.png

FAQ

StringとToStringの違いは何ですか?

DataToken.StringDataToken.ToString()は似ていますが、全く同じではありません。DataToken.StringはDataToken内部の文字列値に直接アクセスするものであるのに対し、DataToken.ToString()はそこに何が存在していても文字列に変換するものであるためです。

その結果、DataTokenの中身が何であっても ToString は常に有効であり、UdonBehaviourが停止することはありません。DataTokenがbool型を含んでいる場合は true または false を返し、数値型を含んでいる場合は ToString("G", CultureInfo.InvariantCulture) を使用してその数値を文字列に変換します。

一方、DataToken.Stringへのアクセスは、DataTokenが文字列を含んでいる場合にのみ有効です。もしDataTokenがfloat型を含んでいる状態で DataToken.String にアクセスしようとすると、例外が発生し、UdonBehaviourが停止します。

DataErrorは、Error enumと文字列の両方を含んでいるという点で独特です。DataErrorに対しては ToString() を使用することをお勧めします。これは、ToString() を呼び出すことで、エラー内容とエラーの理由の両方を含む一つのメッセージに結合されるためです。

トークンを介さずに直接値を取得する TryGetValue を用意してはどうでしょうか?

TryGetValueメソッドを使用して、トークンを介さずに値を直接取得できるようにすると便利です。コンテナから毎回トークンを取得し、そこからさらに個別に値へアクセスする手間がかかるため、これはもっともな疑問です。このプロセスを簡略化するためにいくつかの選択肢が検討されており、実装済みの解決策として、TryGetValueに組み込みの型チェックを含めるという方法があります。

もう一つの検討案として、T引数を使用してシステム型を指定する汎用版のTryGetValueを作成する方法がありました。UdonSharpはこのアプローチをサポートしていますが(少なくとも静的メソッド内では)、Udon自体は対応していません。さらに、この選択肢は利便性がある一方で、エラー発生時にDataTokenを介したDataErrorの返却ができなくなり、代わりにデフォルト値が返されてしまうという欠点があります。最終的に、ユーザーからエラーが隠蔽され、問題の特定が困難になるという理由から、この手法を採用しないことに決定しました。幸い、ユーザーはUdonSharpのジェネリクス、静的変数、および拡張メソッドを利用して、独自の汎用値取得ソリューションを作成することが可能です。

最終更新: