Lingara Lingara 문서 학습 가이드 API 라이브러리 앱 만들기 임베드 웹 앱
언어: 한국어

Unreal

이 페이지는 영어에서 번역되었습니다. 두 내용이 다를 경우 영어 페이지가 정확합니다. 영어 페이지 읽기

Unreal Engine 5용 Lingara 플러그인은 플레이어 코어의 C 인터페이스 위에 만든 게임 인스턴스 서브시스템입니다. 플레이어 키트가 지원하는 다섯 가지 플랫폼, 즉 Windows, macOS, Linux, Android, iOS에서 실행됩니다. 콘솔은 아직 지원하지 않습니다.

플러그인 설치하기

각 릴리스에는 지원하는 엔진 버전마다 플러그인 zip이 하나씩 들어 있으며, 이름은 LingaraEmbed-<semver>-UE5.<m>.zip입니다. 여러분의 엔진에 맞는 것을 프로젝트의 Plugins/ 폴더에 압축 해제한 다음, 에디터에서 플러그인을 활성화하세요. 그 밖에 설치할 것은 없습니다.

서버에서 토큰 받기

플러그인은 시크릿을 보관하지 않습니다. 토큰이 필요하면 플러그인은 OnTokenNeeded를 브로드캐스트합니다. 여러분 자체의 서버의 토큰 라우트로 POST해 응답하세요. 서버는 서버 키트로 발급해 토큰과 그 만료 시각으로 응답하며, 그 둘을 ProvideToken에 넘기면 됩니다. 서버가 응답할 수 없으면 TokenUnavailable을 호출하세요. 그러면 토큰을 기다리는 호출이 시간 초과를 기다리지 않고 즉시 실패합니다.

사용하는 이벤트 바인딩하기

코어는 네트워크 I/O를 자체 스레드에서 실행합니다. 서브시스템은 자체 틱에서 프레임당 최대 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);
}