Unreal
このページは英語から翻訳されています。内容に相違がある場合は、英語のページが正しい内容です。 英語のページを読む
Unreal Engine 5 向けの Lingara プラグインは、プレイヤーコアの C インターフェース上に構築されたゲームインスタンスサブシステムです。プレイヤーキットがサポートする 5 つのプラットフォーム、Windows、macOS、Linux、Android、iOS で動作します。家庭用ゲーム機はまだサポートされていません。
プラグインをインストールする
各リリースには、サポートされるエンジンバージョンごとのプラグインの zip が含まれ、LingaraEmbed-<semver>-UE5.<m>.zip という名前が付いています。お使いのエンジン用のものをプロジェクトの Plugins/ フォルダーに展開し、エディターでプラグインを有効にします。ほかにインストールするものはありません。
サーバーからトークンを取得する
プラグインはシークレットを保持しません。トークンが必要になると、プラグインは OnTokenNeeded をブロードキャストします。あなた自身のサーバーのトークンルートに POST して応答してください。サーバーは サーバーキット で発行し、トークンとその有効期限を返すので、その両方を ProvideToken に渡します。サーバーが応答できない場合は TokenUnavailable を呼び出してください。そうすれば、トークンを待っている呼び出しはタイムアウトを待たずにただちに失敗します。
使うイベントをバインドする
コアはネットワーク I/O を専用のスレッドで実行します。サブシステムは自身の tick の中で、1 フレームあたり最大 MaxEventsPerTick 個(プロジェクト設定)のイベントを取り出し、それぞれをデリゲートでブロードキャストします。プレイ開始時にゲームに必要なデリゲートをバインドし、その後サブシステムを開始します:
OnTokenNeeded:トークンが必要なとき。OnNpcTurn:ストリーミングされる返答の断片ごと(NPC との会話 を参照)。OnPractice:練習の更新ごと(練習の結果 を参照)。OnError:呼び出しが失敗したとき。
Unreal C++
// Your own server mints the token: never put a client secret in a game.
void ALingaraEmbedSnippetActor::HandleTokenNeeded(const FLingaraTokenNeeded& Event)
{
const TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
Request->SetVerb(TEXT("POST"));
Request->SetURL(TokenUrl);
Request->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
Request->SetContentAsString(TEXT("{}"));
Request->OnProcessRequestComplete().BindUObject(this, &ALingaraEmbedSnippetActor::HandleTokenResponse);
Request->ProcessRequest();
}
void ALingaraEmbedSnippetActor::HandleTokenResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnected)
{
ELingaraCallResult Result;
FLingaraEmbedError Error;
TSharedPtr<FJsonObject> Body;
FString Token;
FString ExpiresAt;
const bool bOk = bConnected && Response.IsValid() && EHttpResponseCodes::IsOk(Response->GetResponseCode())
&& FJsonSerializer::Deserialize(TJsonReaderFactory<TCHAR>::Create(Response->GetContentAsString()), Body)
&& Body->TryGetStringField(TEXT("token"), Token) && Body->TryGetStringField(TEXT("expires_at"), ExpiresAt);
if (bOk)
{
Lingara()->ProvideToken(Token, ExpiresAt, Result, Error);
}
else
{
// Fail the waiting calls now rather than at the core's timeout.
Lingara()->TokenUnavailable(TEXT("the token endpoint failed"), Result, Error);
}
}Unreal C++
// The subsystem drains the core's queue from its own tick (at most
// MaxEventsPerTick a frame, from Project Settings): bind the events you use.
void ALingaraEmbedSnippetActor::BeginPlay()
{
Super::BeginPlay();
ULingaraEmbedSubsystem* Subsystem = Lingara();
Subsystem->OnTokenNeeded.AddDynamic(this, &ALingaraEmbedSnippetActor::HandleTokenNeeded);
Subsystem->OnNpcTurn.AddDynamic(this, &ALingaraEmbedSnippetActor::HandleNpcTurn);
Subsystem->OnPractice.AddDynamic(this, &ALingaraEmbedSnippetActor::HandlePractice);
Subsystem->OnError.AddDynamic(this, &ALingaraEmbedSnippetActor::HandleError);
FLingaraEmbedConfig Config;
Config.MaxEventsPerTick = 256;
ELingaraCallResult Result;
FLingaraEmbedError Error;
Subsystem->Start(Config, Result, Error);
}
void ALingaraEmbedSnippetActor::HandleError(const FLingaraEmbedError& Error)
{
UE_LOG(LogTemp, Warning, TEXT("Lingara %s: %s"), *Error.KindName, *Error.Message);
}