Lingara Lingara Documentatie Gidsen API Bibliotheken Apps Bouwen Insluiten Webapp
Taal: Nederlands

Unreal

Deze pagina is vertaald uit het Engels. Als de twee verschillen, is de Engelse pagina juist. Lees de Engelse pagina

De Lingara-plugin voor Unreal Engine 5 is een game-instance-subsystem bovenop de C-interface van de spelerkern. Hij draait op de vijf platforms die de spelerkits ondersteunen: Windows, macOS, Linux, Android en iOS. Consoles worden nog niet ondersteund.

De plugin installeren

Elke release bevat voor elke ondersteunde engineversie een zip van de plugin, met de naam LingaraEmbed-<semver>-UE5.<m>.zip. Pak die voor je engine uit in de map Plugins/ van je project en schakel de plugin daarna in de editor in. Verder hoef je niets te installeren.

Tokens van je server krijgen

De plugin bewaart nooit een secret. Als hij een token nodig heeft, zendt hij OnTokenNeeded uit. Beantwoord dat met een POST naar de tokenroute van je eigen server, die het token uitgeeft met een serverkit en antwoordt met het token en de vervaltijd, en geef ze daarna allebei aan ProvideToken. Als je server niet kan antwoorden, roep dan TokenUnavailable aan, zodat de aanroepen die op een token wachten meteen mislukken in plaats van te verlopen.

De events binden die je gebruikt

De kern voert zijn netwerk-I/O uit op een eigen thread. Het subsystem haalt die leeg vanuit zijn eigen tick, maximaal MaxEventsPerTick events per frame (een projectinstelling), en zendt elk uit via een delegate. Bind de delegates die je game nodig heeft wanneer het spelen begint, en start daarna het subsystem:

  • OnTokenNeeded, wanneer een token nodig is;
  • OnNpcTurn, voor elk stuk van een gestreamd antwoord (zie NPC-dialoog);
  • OnPractice, voor elke oefenupdate (zie oefenresultaten);
  • OnError, wanneer een aanroep mislukt.

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