Lingara Lingara Dokumentation Ratgeber API Bibliotheken Apps Erstellen Einbetten Web-App
Sprache: Deutsch

Unreal

Diese Seite ist aus dem Englischen übersetzt. Wenn die beiden voneinander abweichen, ist die englische Seite maßgeblich. Englische Seite lesen

Das Lingara-Plugin für Unreal Engine 5 ist ein Game-Instance-Subsystem über der C-Schnittstelle des Spieler-Kerns. Es läuft auf den fünf Plattformen, die die Spieler-Kits unterstützen: Windows, macOS, Linux, Android und iOS. Konsolen werden noch nicht unterstützt.

Das Plugin installieren

Jedes Release enthält für jede unterstützte Engine-Version ein Zip des Plugins mit dem Namen LingaraEmbed-<semver>-UE5.<m>.zip. Entpacken Sie das für Ihre Engine passende in den Ordner Plugins/ Ihres Projekts und aktivieren Sie das Plugin dann im Editor. Mehr ist nicht zu installieren.

Tokens von Ihrem Server erhalten

Das Plugin hält nie ein Secret. Wenn es ein Token braucht, sendet es OnTokenNeeded. Beantworten Sie das mit einem POST an die Token-Route Ihres eigenen Servers, der mit einem Server-Kit ausstellt und mit dem Token und seinem Ablaufzeitpunkt antwortet, und übergeben Sie dann beides an ProvideToken. Kann Ihr Server nicht antworten, rufen Sie TokenUnavailable auf, damit die Aufrufe, die auf ein Token warten, sofort fehlschlagen, statt in ein Timeout zu laufen.

Die Events binden, die Sie verwenden

Der Kern führt seine Netzwerk-I/O in einem eigenen Thread aus. Das Subsystem leert sie in seinem eigenen Tick, höchstens MaxEventsPerTick Events pro Frame (eine Projekteinstellung), und sendet jedes über einen Delegate. Binden Sie die Delegates, die Ihr Spiel braucht, wenn das Spiel beginnt, und starten Sie dann das Subsystem:

  • OnTokenNeeded, wenn ein Token gebraucht wird;
  • OnNpcTurn, für jedes Stück einer gestreamten Antwort (siehe NPC-Dialoge);
  • OnPractice, für jede Übungsaktualisierung (siehe Übungsergebnisse);
  • OnError, wenn ein Aufruf fehlschlägt.

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);
}