From 1ddc860ce86acbe34e7ac80cdfc95e74532dd87e Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Tue, 23 Apr 2024 22:33:57 -0400 Subject: [PATCH 01/45] initial swap of types --- .../InworldAIClient/InworldAIClient.Build.cs | 1 + .../InworldAIClient/Private/InworldClient.cpp | 207 ++++++------ .../InworldAIClient/Public/InworldClient.h | 134 +++++--- .../InworldAIClient/Public/InworldPackets.h | 19 ++ .../Private/InworldApi.cpp | 314 +++--------------- .../Private/InworldCharacter.cpp | 49 +++ .../Private/InworldCharacterComponent.cpp | 120 ++----- .../InworldCharacterPlaybackTrigger.cpp | 3 +- .../InworldGameplayDebuggerCategory.cpp | 45 ++- .../Private/InworldPlayer.cpp | 24 ++ .../InworldPlayerAudioCaptureComponent.cpp | 56 +--- .../Private/InworldPlayerComponent.cpp | 188 +++-------- .../InworldPlayerTargetingComponent.cpp | 66 ++-- .../Private/InworldSession.cpp | 219 ++++++++++++ .../InworldAIIntegration/Public/InworldApi.h | 99 +----- .../Public/InworldCharacter.h | 63 ++++ .../Public/InworldCharacterComponent.h | 36 +- .../Public/InworldComponentInterface.h | 36 -- .../Public/InworldPlayer.h | 67 ++++ .../InworldPlayerAudioCaptureComponent.h | 13 +- .../Public/InworldPlayerComponent.h | 41 ++- .../Public/InworldPlayerTargetingComponent.h | 9 +- .../Public/InworldSession.h | 167 ++++++++++ ...nworldAINDK.cpp => InworldAINDKModule.cpp} | 2 +- .../{InworldAINDK.h => InworldAINDKModule.h} | 11 + 25 files changed, 1064 insertions(+), 925 deletions(-) create mode 100644 InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp create mode 100644 InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp create mode 100644 InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp create mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h delete mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldComponentInterface.h create mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h create mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldSession.h rename InworldAI/Source/InworldAINDK/Private/{InworldAINDK.cpp => InworldAINDKModule.cpp} (98%) rename InworldAI/Source/InworldAINDK/Public/{InworldAINDK.h => InworldAINDKModule.h} (69%) diff --git a/InworldAI/Source/InworldAIClient/InworldAIClient.Build.cs b/InworldAI/Source/InworldAIClient/InworldAIClient.Build.cs index 20f354fd..8ac9e161 100644 --- a/InworldAI/Source/InworldAIClient/InworldAIClient.Build.cs +++ b/InworldAI/Source/InworldAIClient/InworldAIClient.Build.cs @@ -31,6 +31,7 @@ public InworldAIClient(ReadOnlyTargetRules Target) : base(Target) "CoreUObject", "Engine", "Projects", + "InworldAINDK", "InworldAINDKLibrary", }); } diff --git a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp index 11960a8a..188246ff 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp @@ -13,6 +13,7 @@ #include "SocketSubsystem.h" #include "IPAddress.h" +#include "InworldAINDKModule.h" #include "InworldUtils.h" #include "InworldPacketTranslator.h" @@ -50,13 +51,17 @@ static TAutoConsoleVariable CVarSoundDumpPath( TEXT("Specifiy path for audio input dump file") ); -FInworldClient::FOnAudioDumperCVarChanged FInworldClient::OnAudioDumperCVarChanged; +UInworldClient::FOnAudioDumperCVarChanged UInworldClient::OnAudioDumperCVarChanged; -FAutoConsoleVariableSink FInworldClient::CVarSink(FConsoleCommandDelegate::CreateStatic(&FInworldClient::OnCVarsChanged)); +FAutoConsoleVariableSink UInworldClient::CVarSink(FConsoleCommandDelegate::CreateStatic(&UInworldClient::OnCVarsChanged)); #endif -void FInworldClient::Init() +UInworldClient::UInworldClient() + : Super() { + // Ensure dependencies are loaded + FInworldAINDKModule::Get(); + FString ClientVer; TSharedPtr InworldAIPlugin = IPluginManager::Get().FindPlugin("InworldAI"); if (ensure(InworldAIPlugin.IsValid())) @@ -68,7 +73,7 @@ void FInworldClient::Init() Inworld::SdkInfo Sdk; Sdk.Type = TCHAR_TO_UTF8(*ClientId); Sdk.Version = TCHAR_TO_UTF8(*ClientVer); - + FString OSVersion, OSSubversion; FPlatformMisc::GetOSVersions(OSVersion, OSSubversion); FString OSFullVersion = FString::Printf(TEXT("%s %s"), *OSVersion, *OSSubversion); @@ -83,57 +88,60 @@ void FInworldClient::Init() return; } - AsyncTask(ENamedThreads::GameThread, [this, ConnectionState]() - { - OnConnectionStateChanged.ExecuteIfBound(static_cast(ConnectionState)); - }); + AsyncTask(ENamedThreads::GameThread, [this, ConnectionState]() + { + OnConnectionStateChangedDelegateNative.Broadcast(static_cast(ConnectionState)); + OnConnectionStateChangedDelegate.Broadcast(static_cast(ConnectionState)); + }); }, [this](std::shared_ptr Packet) { AsyncTask(ENamedThreads::GameThread, [this, Packet]() - { - InworldPacketTranslator PacketTranslator; - Packet->Accept(PacketTranslator); - TSharedPtr ReceivedPacket = PacketTranslator.GetPacket(); - if (ReceivedPacket.IsValid()) { - OnInworldPacketReceived.ExecuteIfBound(ReceivedPacket); - } - }); + InworldPacketTranslator PacketTranslator; + Packet->Accept(PacketTranslator); + TSharedPtr ReceivedPacket = PacketTranslator.GetPacket(); + if (ReceivedPacket.IsValid()) + { + OnPacketReceivedDelegateNative.Broadcast(ReceivedPacket); + OnPacketReceivedDelegate.Broadcast(ReceivedPacket); + } + }); } ); - Inworld::GetClient()->SetPerceivedLatencyTrackerCallback([this](const std::string& InteractionId, uint32_t LatancyMs) + Inworld::GetClient()->SetPerceivedLatencyTrackerCallback([this](const std::string& InteractionId, uint32_t LatencyMs) { - OnPerceivedLatency.ExecuteIfBound(UTF8_TO_TCHAR(InteractionId.c_str()), LatancyMs); + OnPerceivedLatencyDelegateNative.Broadcast(UTF8_TO_TCHAR(InteractionId.c_str()), LatencyMs); + OnPerceivedLatencyDelegate.Broadcast(UTF8_TO_TCHAR(InteractionId.c_str()), LatencyMs); } ); #if !UE_BUILD_SHIPPING auto OnAudioDumperCVarChangedCallback = [this](bool bEnable, FString Path) - { - const auto DumpPath = CVarSoundDumpPath.GetValueOnGameThread(); - if (!FPaths::DirectoryExists(FPaths::GetPath(DumpPath))) { - UE_LOG(LogInworldAIClient, Error, TEXT("Audio dump path is invalid: %s."), *DumpPath); - Inworld::GetClient()->SetAudioDumpEnabled(false, ""); - return; - } - const std::string StdPath = TCHAR_TO_UTF8(*DumpPath); - Inworld::GetClient()->SetAudioDumpEnabled(false, StdPath); + const auto DumpPath = CVarSoundDumpPath.GetValueOnGameThread(); + if (!FPaths::DirectoryExists(FPaths::GetPath(DumpPath))) + { + UE_LOG(LogInworldAIClient, Error, TEXT("Audio dump path is invalid: %s."), *DumpPath); + Inworld::GetClient()->SetAudioDumpEnabled(false, ""); + return; + } + const std::string StdPath = TCHAR_TO_UTF8(*DumpPath); + Inworld::GetClient()->SetAudioDumpEnabled(false, StdPath); - if (bEnable) - { - UE_LOG(LogInworldAIClient, Log, TEXT("Audio dump path: %s."), *DumpPath); - Inworld::GetClient()->SetAudioDumpEnabled(true, StdPath); - } - }; + if (bEnable) + { + UE_LOG(LogInworldAIClient, Log, TEXT("Audio dump path: %s."), *DumpPath); + Inworld::GetClient()->SetAudioDumpEnabled(true, StdPath); + } + }; OnAudioDumperCVarChangedHandle = OnAudioDumperCVarChanged.AddLambda(OnAudioDumperCVarChangedCallback); OnAudioDumperCVarChangedCallback(CVarEnableSoundDump.GetValueOnGameThread(), CVarSoundDumpPath.GetValueOnGameThread()); #endif } -void FInworldClient::Destroy() +UInworldClient::~UInworldClient() { bIsBeingDestroyed = true; #if !UE_BUILD_SHIPPING @@ -199,27 +207,27 @@ static void ConvertPlayerProfile(const FInworldPlayerProfile& PlayerProfile, Inw } } -void FInworldClient::Start(const FString& SceneName, const FInworldPlayerProfile& PlayerProfile, const FInworldCapabilitySet& Capabilities, const FInworldAuth& Auth, const FInworldSessionToken& SessionToken, const FInworldSave& Save, const FInworldEnvironment& Environment) +void UInworldClient::StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet) { Inworld::ClientOptions Options; Options.ServerUrl = TCHAR_TO_UTF8(*(!Environment.TargetUrl.IsEmpty() ? Environment.TargetUrl : DefaultTargetUrl)); // Use first segment of scene for resource // 'workspaces/sample-workspace' TArray Split; - SceneName.ParseIntoArray(Split, TEXT("/")); + SceneId.ParseIntoArray(Split, TEXT("/")); if (Split.Num() >= 2) { Options.Resource = TCHAR_TO_UTF8(*FString(Split[0] + "/" + Split[1])); } - Options.SceneName = TCHAR_TO_UTF8(*SceneName); + Options.SceneName = TCHAR_TO_UTF8(*SceneId); Options.Base64 = TCHAR_TO_UTF8(*Auth.Base64Signature); Options.ApiKey = TCHAR_TO_UTF8(*Auth.ApiKey); Options.ApiSecret = TCHAR_TO_UTF8(*Auth.ApiSecret); - Options.ProjectName = TCHAR_TO_UTF8(*PlayerProfile.ProjectName); + Options.ProjectName = TCHAR_TO_UTF8(FApp::GetProjectName()); ConvertPlayerProfile(PlayerProfile, Options.UserConfig); - ConvertCapabilities(Capabilities, Options.Capabilities); + ConvertCapabilities(CapabilitySet, Options.Capabilities); Inworld::SessionInfo Info; Info.Token = TCHAR_TO_UTF8(*SessionToken.Token); @@ -227,47 +235,48 @@ void FInworldClient::Start(const FString& SceneName, const FInworldPlayerProfile Info.SessionId = TCHAR_TO_UTF8(*SessionToken.SessionId); if (Save.Data.Num() != 0) - { - Info.SessionSavedState.resize(Save.Data.Num()); - FMemory::Memcpy((uint8*)Info.SessionSavedState.data(), (uint8*)Save.Data.GetData(), Info.SessionSavedState.size()); - } + { + Info.SessionSavedState.resize(Save.Data.Num()); + FMemory::Memcpy((uint8*)Info.SessionSavedState.data(), (uint8*)Save.Data.GetData(), Info.SessionSavedState.size()); + } Inworld::GetClient()->StartClient(Options, Info); } -void FInworldClient::Stop() +void UInworldClient::StopSession() { Inworld::GetClient()->StopClient(); } -void FInworldClient::Pause() +void UInworldClient::PauseSession() { Inworld::GetClient()->PauseClient(); } -void FInworldClient::Resume() +void UInworldClient::ResumeSession() { Inworld::GetClient()->ResumeClient(); } -void FInworldClient::SaveSession() +void UInworldClient::SaveSession(FOnInworldSessionSavedCallback Callback) { - Inworld::GetClient()->SaveSessionStateAsync([this](std::string Data, bool bSuccess) + Inworld::GetClient()->SaveSessionStateAsync([Callback](std::string Data, bool bSuccess) { - AsyncTask(ENamedThreads::GameThread, [this, Data, bSuccess]() { - FInworldSave Save; - if (!bSuccess) + FInworldSave Save; + if (bSuccess) + { + Save.Data.SetNumUninitialized(Data.size()); + FMemory::Memcpy(Save.Data.GetData(), (uint8*)Data.data(), Save.Data.Num()); + } + AsyncTask(ENamedThreads::GameThread, [Callback, Save, bSuccess]() { - UE_LOG(LogInworldAIClient, Error, TEXT("Couldn't generate user id.")); - OnSessionSaved.ExecuteIfBound(Save, false); - return; + if (!bSuccess) + { + UE_LOG(LogInworldAIClient, Error, TEXT("Failed to save.")); + } + Callback.ExecuteIfBound(Save, bSuccess); } - - Save.Data.SetNumUninitialized(Data.size()); - FMemory::Memcpy((uint8*)Save.Data.GetData(), (uint8*)Data.data(), Save.Data.Num()); - - OnSessionSaved.ExecuteIfBound(Save, true); - }); + ); }); } @@ -281,54 +290,54 @@ std::vector ToStd(const TArray& Array) return Vec; } -void FInworldClient::LoadCharacters(const TArray& Names) +void UInworldClient::LoadCharacters(const TArray& Ids) { - Inworld::GetClient()->LoadCharacters(ToStd(Names)); + Inworld::GetClient()->LoadCharacters(ToStd(Ids)); } -void FInworldClient::UnloadCharacters(const TArray& Names) +void UInworldClient::UnloadCharacters(const TArray& Ids) { - Inworld::GetClient()->UnloadCharacters(ToStd(Names)); + Inworld::GetClient()->UnloadCharacters(ToStd(Ids)); } -void FInworldClient::LoadSavedState(const TArray& SavedState) +void UInworldClient::LoadSavedState(const FInworldSave& Save) { - std::string Data((char*)SavedState.GetData(), SavedState.Num()); + std::string Data((char*)Save.Data.GetData(), Save.Data.Num()); Inworld::GetClient()->LoadSavedState(Data); } -void FInworldClient::LoadCapabilities(const FInworldCapabilitySet& Capabilities) +void UInworldClient::LoadCapabilities(const FInworldCapabilitySet& CapabilitySet) { - Inworld::Capabilities Cpb; - ConvertCapabilities(Capabilities, Cpb); - Inworld::GetClient()->LoadCapabilities(Cpb); + Inworld::Capabilities Capabilities; + ConvertCapabilities(CapabilitySet, Capabilities); + Inworld::GetClient()->LoadCapabilities(Capabilities); } -void FInworldClient::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) +void UInworldClient::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { Inworld::UserConfiguration UserConfig; ConvertPlayerProfile(PlayerProfile, UserConfig); Inworld::GetClient()->LoadUserConfiguration(UserConfig); } -EInworldConnectionState FInworldClient::GetConnectionState() const +EInworldConnectionState UInworldClient::GetConnectionState() const { return Inworld::GetClient() ? static_cast(Inworld::GetClient()->GetConnectionState()) : EInworldConnectionState::Disconnected; } -void FInworldClient::GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const +void UInworldClient::GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const { std::string OutError; Inworld::GetClient()->GetConnectionError(OutError, OutErrorCode); OutErrorMessage = UTF8_TO_TCHAR(OutError.c_str()); } -FString FInworldClient::GetSessionId() const +FString UInworldClient::GetSessionId() const { - return UTF8_TO_TCHAR(Inworld::GetSessionId().c_str()); + return UTF8_TO_TCHAR(Inworld::GetClient()->GetSessionInfo().SessionId.c_str()); } -TSharedPtr FInworldClient::SendTextMessage(const TArray& AgentIds, const FString& Text) +FInworldWrappedPacket UInworldClient::SendTextMessage(const TArray& AgentIds, const FString& Text) { auto Packet = Inworld::GetClient()->SendTextMessage(ToStd(AgentIds), TCHAR_TO_UTF8(*Text)); InworldPacketTranslator PacketTranslator; @@ -336,43 +345,27 @@ TSharedPtr FInworldClient::SendTextMessage(const TArray return PacketTranslator.GetPacket(); } -void FInworldClient::SendSoundMessage(const TArray& AgentIds, class USoundWave* Sound) +void UInworldClient::BroadcastSoundMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData) { - std::string data; - if (Inworld::Utils::SoundWaveToString(Sound, data)) + if (OutputData.Num() > 0) { - Inworld::GetClient()->SendSoundMessage(ToStd(AgentIds), data); + std::string inputdata((char*)InputData.GetData(), InputData.Num()); + Inworld::GetClient()->SendSoundMessage(ToStd(AgentIds), inputdata); } -} - -void FInworldClient::SendSoundDataMessage(const TArray& AgentIds, const TArray& Data) -{ - std::string data((char*)Data.GetData(), Data.Num()); - Inworld::GetClient()->SendSoundMessage(ToStd(AgentIds), data); -} - -void FInworldClient::SendSoundMessageWithEAC(const TArray& AgentIds, class USoundWave* Input, class USoundWave* Output) -{ - std::vector inputdata, outputdata; - if (Inworld::Utils::SoundWaveToVec(Input, inputdata) && Inworld::Utils::SoundWaveToVec(Output, outputdata)) + else { + std::vector inputdata((int16*)InputData.GetData(), ((int16*)InputData.GetData()) + (InputData.Num() / 2)); + std::vector outputdata((int16*)OutputData.GetData(), ((int16*)OutputData.GetData()) + (OutputData.Num() / 2)); Inworld::GetClient()->SendSoundMessageWithAEC(ToStd(AgentIds), inputdata, outputdata); } } -void FInworldClient::SendSoundDataMessageWithEAC(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData) -{ - std::vector inputdata((int16*)InputData.GetData(), ((int16*)InputData.GetData()) + (InputData.Num() / 2)); - std::vector outputdata((int16*)OutputData.GetData(), ((int16*)OutputData.GetData()) + (OutputData.Num() / 2)); - Inworld::GetClient()->SendSoundMessageWithAEC(ToStd(AgentIds), inputdata, outputdata); -} - -void FInworldClient::StartAudioSession(const TArray& AgentIds) +void UInworldClient::BroadcastAudioSessionStart(const TArray& AgentIds) { Inworld::GetClient()->StartAudioSession(ToStd(AgentIds)); } -void FInworldClient::StopAudioSession(const TArray& AgentIds) +void UInworldClient::BroadcastAudioSessionStop(const TArray& AgentIds) { Inworld::GetClient()->StopAudioSession(ToStd(AgentIds)); } @@ -387,22 +380,22 @@ std::unordered_map ToStd(const TMap& return StdMap; } -void FInworldClient::SendCustomEvent(const TArray& AgentIds, const FString& Name, const TMap& Params) +void UInworldClient::BroadcastTrigger(const TArray& AgentIds, const FString& Name, const TMap& Params) { Inworld::GetClient()->SendCustomEvent(ToStd(AgentIds), TCHAR_TO_UTF8(*Name), ToStd(Params)); } -void FInworldClient::SendChangeSceneEvent(const FString& SceneName) +void UInworldClient::SendChangeSceneEvent(const FString& SceneName) { Inworld::GetClient()->LoadScene(TCHAR_TO_UTF8(*SceneName)); } -void FInworldClient::SendNarrationEvent(const FString& AgentId, const FString& Content) +void UInworldClient::SendNarrationEvent(const FString& AgentId, const FString& Content) { Inworld::GetClient()->SendNarrationEvent(TCHAR_TO_UTF8(*AgentId), TCHAR_TO_UTF8(*Content)); } -void FInworldClient::CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds) +void UInworldClient::CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds) { std::vector utteranceIds; utteranceIds.reserve(UtteranceIds.Num()); @@ -415,7 +408,7 @@ void FInworldClient::CancelResponse(const FString& AgentId, const FString& Inter } #if !UE_BUILD_SHIPPING -void FInworldClient::OnCVarsChanged() +void UInworldClient::OnCVarsChanged() { static bool GEnableSoundDump = CVarEnableSoundDump.GetValueOnGameThread(); static FString GSoundDumpPath = CVarSoundDumpPath.GetValueOnGameThread(); @@ -430,4 +423,4 @@ void FInworldClient::OnCVarsChanged() OnAudioDumperCVarChanged.Broadcast(GEnableSoundDump, GSoundDumpPath); } } -#endif +#endif \ No newline at end of file diff --git a/InworldAI/Source/InworldAIClient/Public/InworldClient.h b/InworldAI/Source/InworldAIClient/Public/InworldClient.h index f24186ed..da0a0960 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldClient.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldClient.h @@ -16,68 +16,115 @@ #include "InworldClient.generated.h" -DECLARE_DELEGATE_OneParam(FOnInworldSceneLoaded, TArray); -DECLARE_DELEGATE_TwoParams(FOnInworldSessionSaved, FInworldSave, bool); -DECLARE_DELEGATE_TwoParams(FOnInworldLatency, FString, int32) -DECLARE_DELEGATE_OneParam(FOnInworldConnectionStateChanged, EInworldConnectionState); -DECLARE_DELEGATE_OneParam(FOnInworldPacketReceived, TSharedPtr); - -USTRUCT() -struct INWORLDAICLIENT_API FInworldClient -{ -public: - GENERATED_BODY() +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldPacketReceived, const FInworldWrappedPacket&, WrappedPacket); +DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInworldPacketReceivedCallback, const FInworldWrappedPacket&, WrappedPacket); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPacketReceivedNative, const FInworldWrappedPacket& /*WrappedPacket*/); - void Init(); - void Destroy(); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldConnectionStateChanged, EInworldConnectionState, ConnectionState); +DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInworldConnectionStateChangedCallback, EInworldConnectionState, ConnectionState); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldConnectionStateChangedNative, EInworldConnectionState /*ConnectionState*/); - void Start(const FString& SceneName, const FInworldPlayerProfile& PlayerProfile, const FInworldCapabilitySet& Capabilities, const FInworldAuth& Auth, const FInworldSessionToken& SessionToken, const FInworldSave& Save, const FInworldEnvironment& Environment); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInworldPerceivedLatency, FString, InteractionId, int32, LatencyMs); +DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnInworldPerceivedLatencyCallback, FString, InteractionId, int32, LatencyMs); +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnInworldPerceivedLatencyNative, FString /*InteractionId*/, int32 /*ms*/); - void Stop(); +DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnInworldSessionSavedCallback, FInworldSave, Save, bool, bSuccess); - void Pause(); - void Resume(); +UCLASS(BlueprintType) +class INWORLDAICLIENT_API UInworldClient : public UObject +{ +public: + GENERATED_BODY() - void SaveSession(); + UInworldClient(); + ~UInworldClient(); - void LoadCharacters(const TArray& Names); - void UnloadCharacters(const TArray& Names); - void LoadSavedState(const TArray& SavedState); - void LoadCapabilities(const FInworldCapabilitySet& Capabilities); - void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile); - - EInworldConnectionState GetConnectionState() const; - void GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const; + UFUNCTION(BlueprintCallable, Category = "Inworld|Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) + void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save = FInworldSave(), const FInworldSessionToken& SessionToken = FInworldSessionToken(), const FInworldCapabilitySet& CapabilitySet = FInworldCapabilitySet()); + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void StopSession(); + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void PauseSession(); + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void ResumeSession(); + UFUNCTION(BlueprintPure, Category = "Inworld|Session") FString GetSessionId() const; - TSharedPtr SendTextMessage(const TArray& AgentIds, const FString& Text); - - void SendSoundMessage(const TArray& AgentIds, class USoundWave* Sound); - void SendSoundDataMessage(const TArray& AgentIds, const TArray& Data); + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void SaveSession(FOnInworldSessionSavedCallback Callback); + + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void LoadCharacter(const FString& Id) { LoadCharacters({ Id }); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void LoadCharacters(const TArray& Ids); + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void UnloadCharacter(const FString& Id) { UnloadCharacters({ Id }); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void UnloadCharacters(const TArray& Ids); + + UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + void LoadSavedState(const FInworldSave& Save); + UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + void LoadCapabilities(const FInworldCapabilitySet& CapabilitySet); + UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile); - void SendSoundMessageWithEAC(const TArray& AgentIds, class USoundWave* Input, class USoundWave* Output); - void SendSoundDataMessageWithEAC(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData); + UFUNCTION(BlueprintCallable, Category = "Message|Text") + FInworldWrappedPacket SendTextMessage(const TArray& AgentIds, const FString& Text); + + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void SendSoundMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData) { BroadcastSoundMessage({AgentId}, InputData, OutputData); } + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void BroadcastSoundMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void SendAudioSessionStart(const FString& AgentId) { BroadcastAudioSessionStart({ AgentId }); } + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void BroadcastAudioSessionStart(const TArray& AgentIds); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void SendAudioSessionStop(const FString& AgentId) { BroadcastAudioSessionStop({ AgentId }); } + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void BroadcastAudioSessionStop(const TArray& AgentIds); + + UFUNCTION(BlueprintCallable, Category = "Message|Narration") + void SendNarrationEvent(const FString& AgentId, const FString& Content); - void StartAudioSession(const TArray& AgentIds); - void StopAudioSession(const TArray& AgentIds); + UFUNCTION(BlueprintCallable, Category = "Message|Trigger") + void SendTrigger(FString AgentId, const FString& Name, const TMap& Params) { BroadcastTrigger({AgentId}, Name, Params); } + UFUNCTION(BlueprintCallable, Category = "Message|Trigger") + void BroadcastTrigger(const TArray& AgentIds, const FString& Name, const TMap& Params); - void SendCustomEvent(const TArray& AgentIds, const FString& Name, const TMap& Params); + UFUNCTION(BlueprintCallable, Category = "Message|Mutation") void SendChangeSceneEvent(const FString& SceneName); - void SendNarrationEvent(const FString& AgentId, const FString& Content); - + UFUNCTION(BlueprintCallable, Category = "Message|Mutation") void CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds); - FOnInworldSessionSaved OnSessionSaved; + UPROPERTY(BlueprintAssignable, Category = "Packet") + FOnInworldPacketReceived OnPacketReceivedDelegate; + FOnInworldPacketReceivedNative& OnPacketReceived() { return OnPacketReceivedDelegateNative; } + + UFUNCTION(BlueprintPure, Category = "Connection") + EInworldConnectionState GetConnectionState() const; + UFUNCTION(BlueprintPure, Category = "Connection") + void GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const; + + UPROPERTY(BlueprintAssignable, Category = "Connection") + FOnInworldConnectionStateChanged OnConnectionStateChangedDelegate; + FOnInworldConnectionStateChangedNative& OnConnectionStateChanged() { return OnConnectionStateChangedDelegateNative; } - FOnInworldLatency OnPerceivedLatency; - - FOnInworldConnectionStateChanged OnConnectionStateChanged; + UPROPERTY(BlueprintAssignable, Category = "Connection") + FOnInworldPerceivedLatency OnPerceivedLatencyDelegate; + FOnInworldPerceivedLatencyNative& OnPerceivedLatency() { return OnPerceivedLatencyDelegateNative; } - FOnInworldPacketReceived OnInworldPacketReceived; + // Used for internal Inworld SDK testing - not documented, do not use. + UFUNCTION(BlueprintCallable, Category = "Inworld Development") + void SetEnvironment(const FInworldEnvironment& InEnvironment) { Environment = InEnvironment; } private: + FOnInworldPacketReceivedNative OnPacketReceivedDelegateNative; + FOnInworldConnectionStateChangedNative OnConnectionStateChangedDelegateNative; + FOnInworldPerceivedLatencyNative OnPerceivedLatencyDelegateNative; bool bIsBeingDestroyed = false; @@ -89,4 +136,5 @@ struct INWORLDAICLIENT_API FInworldClient static void OnCVarsChanged(); #endif -}; + FInworldEnvironment Environment; +}; \ No newline at end of file diff --git a/InworldAI/Source/InworldAIClient/Public/InworldPackets.h b/InworldAI/Source/InworldAIClient/Public/InworldPackets.h index 5ec2703a..d6a6122b 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldPackets.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldPackets.h @@ -164,6 +164,25 @@ class InworldPacketVisitor virtual void Visit(const FInworldRelationEvent& Event) { } }; +struct FInworldPacket; + +USTRUCT(BlueprintType) +struct INWORLDAICLIENT_API FInworldWrappedPacket +{ + GENERATED_BODY() +public: + FInworldWrappedPacket() + : Packet(nullptr) + {} + + FInworldWrappedPacket(TSharedPtr InPacket) + : Packet(InPacket) + {} + + TSharedPtr Packet = {}; + +}; + USTRUCT() struct INWORLDAICLIENT_API FInworldPacket { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index d4229a2d..0d4ed858 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -9,8 +9,8 @@ #include "InworldApi.h" #include "InworldAIIntegrationModule.h" -#include "InworldComponentInterface.h" #include "InworldPackets.h" +#include "InworldCharacter.h" #include #include #include "TimerManager.h" @@ -22,9 +22,8 @@ TEXT("Enable/Disable logging all packets going from server") ); UInworldApiSubsystem::UInworldApiSubsystem() - : UWorldSubsystem() -{ -} + : Super() +{} void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) { @@ -48,8 +47,6 @@ void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& FInworldPlayerProfile PlayerProfile; PlayerProfile.Name = PlayerName; - FInworldCapabilitySet Capabilities; - FInworldAuth Auth; Auth.ApiKey = ApiKey; Auth.ApiSecret = ApiSecret; @@ -63,7 +60,7 @@ void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& Environment.AuthUrl = AuthUrlOverride; Environment.TargetUrl = TargetUrlOverride; - Client->Start(SceneName, PlayerProfile, Capabilities, Auth, SessionToken, FInworldSave(), Environment); + InworldSession->InworldClient->StartSession(SceneName, PlayerProfile, Auth, FInworldSave(), SessionToken); } void UInworldApiSubsystem::StartSession_V2(const FString& SceneName, const FInworldPlayerProfile& PlayerProfile, const FInworldCapabilitySet& Capabilities, const FInworldAuth& Auth, const FInworldSessionToken& SessionToken, const FInworldEnvironment& Environment, FString UniqueUserIdOverride, FInworldSave SavedSessionState) @@ -85,195 +82,78 @@ void UInworldApiSubsystem::StartSession_V2(const FString& SceneName, const FInwo UE_LOG(LogInworldAIIntegration, Warning, TEXT("Start Session, please provide unique PlayerProfile.ProjectName for possible troubleshooting")); } - Client->Start(SceneName, PlayerProfile, Capabilities, Auth, SessionToken, SavedSessionState, Environment); + InworldSession->InworldClient->StartSession(SceneName, PlayerProfile, Auth, SavedSessionState, SessionToken, Capabilities); } void UInworldApiSubsystem::PauseSession() { - Client->Pause(); + InworldSession->InworldClient->PauseSession(); } void UInworldApiSubsystem::ResumeSession() { - Client->Resume(); + InworldSession->InworldClient->PauseSession(); } void UInworldApiSubsystem::StopSession() { - UnpossessAgents(); - - Client->Stop(); + InworldSession->InworldClient->StopSession(); } -void UInworldApiSubsystem::SaveSession(FOnSaveReady Delegate) +void UInworldApiSubsystem::SaveSession(FOnInworldSessionSavedCallback Callback) { - Client->OnSessionSaved.BindLambda([this, Delegate](const FInworldSave& Save, bool bSuccess) - { - Delegate.ExecuteIfBound(Save, bSuccess); - Client->OnSessionSaved.Unbind(); - } - ); - Client->SaveSession(); + InworldSession->InworldClient->SaveSession(Callback); } -void UInworldApiSubsystem::SetResponseLatencyTrackerDelegate(FResponseLatencyTrackerDelegate Delegate) +void UInworldApiSubsystem::SetResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate) { - Client->OnPerceivedLatency.BindLambda([this, Delegate](FString InteractionId, int32 LatancyMs) - { - Delegate.ExecuteIfBound(InteractionId, LatancyMs); - }); + InworldSession->InworldClient->OnPerceivedLatencyDelegate.Add(Delegate); } -void UInworldApiSubsystem::ClearResponseLatencyTrackerDelegate() +void UInworldApiSubsystem::ClearResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate) { - Client->OnPerceivedLatency.Unbind(); + InworldSession->InworldClient->OnPerceivedLatencyDelegate.Remove(Delegate); } void UInworldApiSubsystem::LoadCharacters(const TArray& Names) { - Client->LoadCharacters(Names); -} - -void UInworldApiSubsystem::UnloadCharacters(const TArray& Names) -{ - Client->UnloadCharacters(Names); -} - -void UInworldApiSubsystem::LoadSavedState(const TArray& SavedState) -{ - Client->LoadSavedState(SavedState); -} - -void UInworldApiSubsystem::LoadCapabilities(const FInworldCapabilitySet& Capabilities) -{ - Client->LoadCapabilities(Capabilities); -} - -void UInworldApiSubsystem::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) -{ - Client->LoadPlayerProfile(PlayerProfile); -} - -void UInworldApiSubsystem::PossessAgents(const TArray& AgentInfos) -{ - for (const auto& AgentInfo : AgentInfos) + TArray Characters; + for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) { - FString BrainName = AgentInfo.BrainName; - AgentInfoByBrain.Add(BrainName, AgentInfo); - if (CharacterComponentByBrainName.Contains(BrainName)) - { - auto Component = CharacterComponentByBrainName[BrainName]; - if (!Component->IsPossessing()) - { - CharacterComponentByAgentId.Add(AgentInfo.AgentId, Component); - Component->Possess(AgentInfo); - CharacterComponentByAgentId.Add(Component->GetAgentId(), Component); - } - } - else if (BrainName != FString("__DUMMY__")) + if (Names.Contains(Character->GetBrainName())) { - UE_LOG(LogInworldAIIntegration, Warning, TEXT("No component found for BrainName: %s"), *BrainName); + Characters.Add(Character); } } - - TArray BrainsToLoad; - for (const auto& CharacterComponent : CharacterComponentRegistry) - { - auto BrainName = CharacterComponent->GetBrainName(); - if (!AgentInfoByBrain.Contains(BrainName)) - { - BrainsToLoad.Add(BrainName); - } - } - - if (BrainsToLoad.Num() > 0) - { - Client->LoadCharacters(BrainsToLoad); - } - - bCharactersInitialized = true; - OnCharactersInitialized.Broadcast(bCharactersInitialized); + InworldSession->LoadCharacters(Characters); } -void UInworldApiSubsystem::UnpossessAgents() -{ - if (!bCharactersInitialized) - { - return; - } - - auto ComponentsToUnpossess = CharacterComponentRegistry; - for (auto* Component : ComponentsToUnpossess) - { - Component->Unpossess(); - } - CharacterComponentByAgentId.Empty(); - AgentInfoByBrain.Empty(); - bCharactersInitialized = false; - OnCharactersInitialized.Broadcast(bCharactersInitialized); -} - -void UInworldApiSubsystem::RegisterCharacterComponent(Inworld::ICharacterComponent* Component) +void UInworldApiSubsystem::UnloadCharacters(const TArray& Names) { - FString BrainName = Component->GetBrainName(); - if (!ensureMsgf(!CharacterComponentByBrainName.Contains(BrainName), TEXT("UInworldApiSubsystem::RegisterCharacterComponent: Component already registered for Brain: %s!"), *BrainName)) + TArray Characters; + for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) { - return; - } - - CharacterComponentRegistry.Add(Component); - CharacterComponentByBrainName.Add(BrainName, Component); - - if (bCharactersInitialized) - { - if (AgentInfoByBrain.Contains(BrainName)) + if (Names.Contains(Character->GetBrainName())) { - auto AgentInfo = AgentInfoByBrain[BrainName]; - CharacterComponentByAgentId.Add(AgentInfo.AgentId, Component); - Component->Possess(AgentInfo); - } - else - { - Client->LoadCharacters({ BrainName }); + Characters.Add(Character); } } + InworldSession->UnloadCharacters(Characters); } -void UInworldApiSubsystem::UnregisterCharacterComponent(Inworld::ICharacterComponent* Component) +void UInworldApiSubsystem::LoadSavedState(const FInworldSave& SavedState) { - auto BrainName = Component->GetBrainName(); - if (!ensureMsgf(CharacterComponentByBrainName.Contains(BrainName) && CharacterComponentByBrainName[BrainName] == Component, TEXT("UInworldApiSubsystem::UnregisterCharacterComponent: Component mismatch for Brain: %s!"), *BrainName)) - { - return; - } - - Component->Unpossess(); - CharacterComponentByAgentId.Remove(Component->GetAgentId()); - CharacterComponentByBrainName.Remove(BrainName); - CharacterComponentRegistry.Remove(Component); + InworldSession->InworldClient->LoadSavedState(SavedState); } -bool UInworldApiSubsystem::IsCharacterComponentRegistered(Inworld::ICharacterComponent* Component) +void UInworldApiSubsystem::LoadCapabilities(const FInworldCapabilitySet& Capabilities) { - return CharacterComponentRegistry.Contains(Component); + InworldSession->InworldClient->LoadCapabilities(Capabilities); } -void UInworldApiSubsystem::UpdateCharacterComponentRegistrationOnClient(Inworld::ICharacterComponent* Component, const FString& NewAgentId, const FString& OldAgentId) +void UInworldApiSubsystem::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { - if (CharacterComponentByAgentId.Contains(OldAgentId) && CharacterComponentByAgentId[OldAgentId] == Component) - { - CharacterComponentByAgentId.Remove(OldAgentId); - } - - if (NewAgentId.IsEmpty()) - { - CharacterComponentRegistry.Remove(Component); - } - else - { - CharacterComponentByAgentId.Add(NewAgentId, Component); - CharacterComponentRegistry.AddUnique(Component); - } + InworldSession->InworldClient->LoadPlayerProfile(PlayerProfile); } void UInworldApiSubsystem::SendTextMessage(const FString& AgentId, const FString& Text) @@ -288,18 +168,7 @@ void UInworldApiSubsystem::SendTextMessageMultiAgent(const TArray& Agen return; } - TSharedPtr Packet = Client->SendTextMessage(AgentIds, Text); - if (Packet.IsValid()) - { - for (auto& AgentId : AgentIds) - { - auto* AgentComponentPtr = CharacterComponentByAgentId.Find(AgentId); - if (AgentComponentPtr) - { - (*AgentComponentPtr)->HandlePacket(Packet); - } - } - } + InworldSession->InworldClient->SendTextMessage(AgentIds, Text).Packet; } void UInworldApiSubsystem::SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params) @@ -314,7 +183,7 @@ void UInworldApiSubsystem::SendTriggerMultiAgent(const TArray& AgentIds return; } - Client->SendCustomEvent(AgentIds, Name, Params); + InworldSession->InworldClient->BroadcastTrigger(AgentIds, Name, Params); } void UInworldApiSubsystem::SendNarrationEvent(const FString& AgentId, const FString& Content) @@ -324,62 +193,17 @@ void UInworldApiSubsystem::SendNarrationEvent(const FString& AgentId, const FStr return; } - Client->SendNarrationEvent(AgentId, Content); -} - -void UInworldApiSubsystem::SendAudioMessage(const FString& AgentId, USoundWave* SoundWave) -{ - SendAudioMessage(TArray{ AgentId }, SoundWave); -} - -void UInworldApiSubsystem::SendAudioMessage(const TArray& AgentIds, USoundWave* SoundWave) -{ - if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) - { - return; - } - - Client->SendSoundMessage(AgentIds, SoundWave); -} - -void UInworldApiSubsystem::SendAudioDataMessage(const FString& AgentId, const TArray& Data) -{ - SendAudioDataMessage(TArray{ AgentId }, Data); -} - -void UInworldApiSubsystem::SendAudioDataMessage(const TArray& AgentIds, const TArray& Data) -{ - if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIdss must be valid!"))) - { - return; - } - - Client->SendSoundDataMessage(AgentIds, Data); -} - -void UInworldApiSubsystem::SendAudioMessageWithAEC(const FString& AgentId, USoundWave* InputWave, USoundWave* OutputWave) -{ - if (!ensureMsgf(!AgentId.IsEmpty(), TEXT("AgentId must be valid!"))) - { - return; - } - - Client->SendSoundMessageWithEAC({ AgentId }, InputWave, OutputWave); + InworldSession->InworldClient->SendNarrationEvent(AgentId, Content); } -void UInworldApiSubsystem::SendAudioDataMessageWithAEC(const FString& AgentId, const TArray& InputData, const TArray& OutputData) -{ - SendAudioDataMessageWithAEC(TArray{ AgentId }, InputData, OutputData); -} - -void UInworldApiSubsystem::SendAudioDataMessageWithAEC(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData) +void UInworldApiSubsystem::SendAudioMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData) { if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) { return; } - Client->SendSoundDataMessageWithEAC(AgentIds, InputData, OutputData); + InworldSession->InworldClient->BroadcastSoundMessage(AgentIds, InputData, OutputData); } bool UInworldApiSubsystem::StartAudioSession(const FString& AgentId, const AActor* Owner) @@ -401,7 +225,7 @@ bool UInworldApiSubsystem::StartAudioSessionMultiAgent(const TArray& Ag AudioSessionOwner = Owner; - Client->StartAudioSession(AgentIds); + InworldSession->InworldClient->BroadcastAudioSessionStart(AgentIds); return true; } @@ -419,27 +243,17 @@ void UInworldApiSubsystem::StopAudioSessionMultiAgent(const TArray& Age AudioSessionOwner = nullptr; - Client->StopAudioSession(AgentIds); + InworldSession->InworldClient->BroadcastAudioSessionStop(AgentIds); } void UInworldApiSubsystem::ChangeScene(const FString& SceneId) { - UnpossessAgents(); - Client->SendChangeSceneEvent(SceneId); + InworldSession->InworldClient->SendChangeSceneEvent(SceneId); } void UInworldApiSubsystem::GetConnectionError(FString& Message, int32& Code) { - Client->GetConnectionError(Message, Code); -} - -Inworld::ICharacterComponent* UInworldApiSubsystem::GetCharacterComponentByAgentId(const FString& AgentId) const -{ - if (CharacterComponentByAgentId.Contains(AgentId)) - { - return CharacterComponentByAgentId[AgentId]; - } - return nullptr; + InworldSession->InworldClient->GetConnectionError(Message, Code); } void UInworldApiSubsystem::CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds) @@ -449,7 +263,7 @@ void UInworldApiSubsystem::CancelResponse(const FString& AgentId, const FString& return; } - Client->CancelResponse(AgentId, InteractionId, UtteranceIds); + InworldSession->InworldClient->CancelResponse(AgentId, InteractionId, UtteranceIds); } void UInworldApiSubsystem::StartAudioReplication() @@ -473,51 +287,20 @@ void UInworldApiSubsystem::Initialize(FSubsystemCollectionBase& Collection) { return; } - - Client = MakeShared(); - - Client->OnConnectionStateChanged.BindLambda([this](EInworldConnectionState ConnectionState) + InworldSession = NewObject(this, TEXT("InworldSession")); + InworldSession->OnCharactersInitialized().AddLambda( + [this](bool bCharactersInitialized) -> void { - OnConnectionStateChanged.Broadcast(ConnectionState); - - if (ConnectionState == EInworldConnectionState::Connected) - { - CurrentRetryConnectionTime = 1.f; - } - - if (ConnectionState == EInworldConnectionState::Disconnected) - { - if (CurrentRetryConnectionTime == 0.f) - { - ResumeSession(); - } - else - { - GetWorld()->GetTimerManager().SetTimer(RetryConnectionTimerHandle, this, &UInworldApiSubsystem::ResumeSession, CurrentRetryConnectionTime); - } - CurrentRetryConnectionTime += FMath::Min(CurrentRetryConnectionTime + RetryConnectionIntervalTime, MaxRetryConnectionTime); - } - } - ); - - Client->OnInworldPacketReceived.BindLambda([this](TSharedPtr Packet) - { - DispatchPacket(Packet); + OnCharactersInitialized.Broadcast(bCharactersInitialized); } ); - - Client->Init(); } void UInworldApiSubsystem::Deinitialize() { Super::Deinitialize(); - if (Client) - { - Client->Destroy(); - } + InworldSession = nullptr; AudioSessionOwner = nullptr; - Client.Reset(); } #if ENGINE_MAJOR_VERSION > 4 @@ -532,6 +315,7 @@ void UInworldApiSubsystem::OnWorldBeginPlay(UWorld& InWorld) } #endif +/* void UInworldApiSubsystem::DispatchPacket(TSharedPtr InworldPacket) { auto* SourceComponentPtr = CharacterComponentByAgentId.Find(InworldPacket->Routing.Source.Name); @@ -578,6 +362,7 @@ void UInworldApiSubsystem::Visit(const FInworldLoadCharactersEvent& Event) { PossessAgents(Event.AgentInfos); } +*/ void UInworldApiSubsystem::ReplicateAudioEventFromServer(FInworldAudioDataEvent& Packet) { @@ -589,5 +374,6 @@ void UInworldApiSubsystem::ReplicateAudioEventFromServer(FInworldAudioDataEvent& void UInworldApiSubsystem::HandleAudioEventOnClient(TSharedPtr Packet) { - DispatchPacket(Packet); + //TODO: FIX + //DispatchPacket(Packet); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp new file mode 100644 index 00000000..a96592f6 --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -0,0 +1,49 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + + +#include "InworldCharacter.h" +#include "InworldSession.h" + +TScriptInterface UInworldCharacter::GetInworldCharacterOwner() +{ + if (!ensureMsgf(GetOuter()->Implements(), TEXT("UInworldCharacter outer must implement IInworldCharacterOwnerInterface!"))) + { + return nullptr; + } + return TScriptInterface(GetOuter()); +} + +void UInworldCharacter::SetBrainName(const FString& BrainName) +{ + UInworldSession* Session = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + if (!AgentInfo.BrainName.IsEmpty()) + { + if (Session != nullptr) + { + Session->UnregisterCharacter(this); + } + } + AgentInfo.BrainName = BrainName; + if (!BrainName.IsEmpty()) + { + if (Session != nullptr) + { + Session->RegisterCharacter(this); + } + } +} + +void UInworldCharacter::Possess(const FInworldAgentInfo& InAgentInfo) +{ + AgentInfo = InAgentInfo; +} + +void UInworldCharacter::Unpossess() +{ + AgentInfo = {}; +} diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 2002375b..58a21bdc 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -17,7 +17,8 @@ #include UInworldCharacterComponent::UInworldCharacterComponent() - : MessageQueue(MakeShared(this)) + : Super() + , MessageQueue(MakeShared(this)) { PrimaryComponentTick.bCanEverTick = true; bWantsInitializeComponent = true; @@ -27,6 +28,8 @@ void UInworldCharacterComponent::InitializeComponent() { Super::InitializeComponent(); + InworldCharacter = NewObject(this, "InworldCharacter"); + #if WITH_EDITOR if (GetWorld() == nullptr || !GetWorld()->IsPlayInEditor()) { @@ -52,6 +55,8 @@ void UInworldCharacterComponent::UninitializeComponent() { Super::UninitializeComponent(); + InworldCharacter = nullptr; + #if WITH_EDITOR if (GetWorld() == nullptr || !GetWorld()->IsPlayInEditor()) { @@ -71,7 +76,7 @@ void UInworldCharacterComponent::BeginPlay() SetIsReplicated(true); - InworldSubsystem = GetWorld()->GetSubsystem(); + InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); if (GetNetMode() != NM_Client) { @@ -94,10 +99,11 @@ void UInworldCharacterComponent::EndPlay(EEndPlayReason::Type Reason) if (GetNetMode() == NM_Client) { - if (InworldSubsystem.IsValid()) + //TODO: FIX + //if (InworldSubsystem.IsValid()) { - FString NewAgentId = FString(); - InworldSubsystem->UpdateCharacterComponentRegistrationOnClient(this, NewAgentId, AgentId); + //FString NewAgentId = FString(); + //InworldSubsystem->UpdateCharacterComponentRegistrationOnClient(this, NewAgentId, AgentId); } } else @@ -139,45 +145,9 @@ void UInworldCharacterComponent::GetLifetimeReplicatedProps(TArrayIsPlayInEditor()) - { - BrainName = Name; - return; - } -#endif - if (GetNetMode() == NM_Client) - { - return; - } - - if (!ensure(InworldSubsystem.IsValid())) - { - return; - } - - Unregister(); - BrainName = Name; - Register(); + InworldCharacter->SetBrainName(BrainName); } UInworldCharacterPlayback* UInworldCharacterComponent::GetPlayback(TSubclassOf Class) const @@ -200,11 +170,6 @@ void UInworldCharacterComponent::HandlePacket(TSharedPtr Packet) } } -Inworld::IPlayerComponent* UInworldCharacterComponent::GetTargetPlayer() -{ - return TargetPlayer; -} - bool UInworldCharacterComponent::StartPlayerInteraction(UInworldPlayerComponent* Player) { if (TargetPlayer != nullptr) @@ -244,58 +209,35 @@ void UInworldCharacterComponent::CancelCurrentInteraction() const FString CurrentInteractionId = CurrentMessage->InteractionId; TArray CanceledUtterances = MessageQueue->CancelInteraction(CurrentInteractionId); - if (CanceledUtterances.Num() > 0 && !AgentId.IsEmpty()) + if (CanceledUtterances.Num() > 0) { - InworldSubsystem->CancelResponse(AgentId, CurrentInteractionId, CanceledUtterances); + InworldSession->CancelResponse(InworldCharacter, CurrentInteractionId, CanceledUtterances); } } void UInworldCharacterComponent::SendTextMessage(const FString& Text) const { - if (ensure(!AgentId.IsEmpty())) - { - InworldSubsystem->SendTextMessage(AgentId, Text); - } + InworldSession->SendTextMessage(InworldCharacter, Text); } void UInworldCharacterComponent::SendTrigger(const FString& Name, const TMap& Params) const { - if (ensure(!AgentId.IsEmpty())) - { - InworldSubsystem->SendTrigger(AgentId, Name, Params); - } -} - -void UInworldCharacterComponent::SendAudioMessage(USoundWave* SoundWave) const -{ - if (ensure(!AgentId.IsEmpty())) - { - InworldSubsystem->SendAudioMessage(AgentId, SoundWave); - } + InworldSession->SendTrigger(InworldCharacter, Name, Params); } void UInworldCharacterComponent::SendNarrationEvent(const FString& Content) { - if (ensure(!AgentId.IsEmpty())) - { - InworldSubsystem->SendNarrationEvent(AgentId, Content); - } + InworldSession->SendNarrationEvent(InworldCharacter, Content); } void UInworldCharacterComponent::StartAudioSession(const AActor* Owner) const { - if (ensure(!AgentId.IsEmpty())) - { - InworldSubsystem->StartAudioSession(AgentId, Owner); - } + InworldSession->SendAudioSessionStart(InworldCharacter); } void UInworldCharacterComponent::StopAudioSession() const { - if (ensure(!AgentId.IsEmpty())) - { - InworldSubsystem->StopAudioSession(AgentId); - } + InworldSession->SendAudioSessionStop(InworldCharacter); } bool UInworldCharacterComponent::Register() @@ -305,34 +247,19 @@ bool UInworldCharacterComponent::Register() return false; } - if (!ensure(InworldSubsystem.IsValid())) - { - return false; - } - - if (InworldSubsystem->IsCharacterComponentRegistered(this)) - { - return false; - } - - InworldSubsystem->RegisterCharacterComponent(this); + InworldCharacter->SetBrainName(BrainName); return true; } bool UInworldCharacterComponent::Unregister() { - if (!ensure(InworldSubsystem.IsValid())) - { - return false; - } - - if (!InworldSubsystem->IsCharacterComponentRegistered(this)) + if (BrainName.IsEmpty()) { return false; } - InworldSubsystem->UnregisterCharacterComponent(this); + InworldCharacter->SetBrainName({}); return true; } @@ -480,7 +407,8 @@ void UInworldCharacterComponent::OnRep_AgentId(FString OldAgentId) OnUnpossessed.Broadcast(); } - InworldApi->UpdateCharacterComponentRegistrationOnClient(this, AgentId, OldAgentId); + //TODO: FIX + //InworldApi->UpdateCharacterComponentRegistrationOnClient(this, AgentId, OldAgentId); } void UInworldCharacterComponent::Multicast_VisitSilence_Implementation(const FInworldSilenceEvent& Event) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp index b91f05df..3f2773fa 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp @@ -23,7 +23,8 @@ void UInworldCharacterPlaybackTrigger::OnCharacterInteractionEnd_Implementation( { for (auto& Trigger : PendingTriggers[Message.InteractionId]) { - OwnerActor->GetWorld()->GetSubsystem()->NotifyCustomTrigger(Trigger.Name); + //TODO: FIX + //OwnerActor->GetWorld()->GetSubsystem()->NotifyCustomTrigger(Trigger.Name); } } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp index 67cb37ff..5301d87f 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp @@ -41,45 +41,40 @@ void FInworldGameplayDebuggerCategory::CollectData(APlayerController* OwnerPC, A } DataPack.bInworldApiExists = true; - DataPack.SessionStatus = static_cast(InworldApi->Client->GetConnectionState()); - InworldApi->Client->GetConnectionError(DataPack.SessionError, DataPack.ErrorCode); - DataPack.SessionId = InworldApi->Client->GetSessionId(); + DataPack.SessionStatus = static_cast(InworldApi->GetInworldSession()->GetConnectionState()); + InworldApi->GetInworldSession()->GetConnectionError(DataPack.SessionError, DataPack.ErrorCode); + DataPack.SessionId = InworldApi->GetInworldSession()->GetSessionId(); - for (auto* Component : InworldApi->GetCharacterComponents()) + for (UInworldCharacter* Character : InworldApi->GetInworldSession()->GetRegisteredCharacters()) { - auto* Comp = static_cast(Component); - if (!Comp) - { - continue; - } - auto& Data = DataPack.CharData.Emplace_GetRef(); - auto* Actor = Comp->GetComponentOwner(); - Data.OverheadLocation = Actor->GetActorLocation() + FVector(0, 0, Actor->GetSimpleCollisionHalfHeight()); - Data.bIsInteracting = Comp->IsInteractingWithPlayer(); - Data.GivenName = Comp->GetGivenName(); - Data.AgentId = Comp->GetAgentId(); - Data.CurrentMessage = Comp->GetCurrentMessage() ? Comp->GetCurrentMessage()->ToDebugString() : TEXT(""); - Data.MessageQueueEntries = Comp->MessageQueue->PendingMessageEntries.Num(); - Data.EmotionalBehavior = static_cast(Comp->GetEmotionalBehavior()); - Data.EmotionStrength = static_cast(Comp->GetEmotionStrength()); - Data.bPendingRepAudioEvent = !Comp->PendingRepAudioEvents.IsEmpty(); + //TODO: FIX + //Data.OverheadLocation = Actor->GetActorLocation() + FVector(0, 0, Actor->GetSimpleCollisionHalfHeight()); + //Data.bIsInteracting = Comp->IsInteractingWithPlayer(); + Data.GivenName = Character->GetGivenName(); + Data.AgentId = Character->GetAgentId(); + //Data.CurrentMessage = Comp->GetCurrentMessage() ? Comp->GetCurrentMessage()->ToDebugString() : TEXT(""); + //Data.MessageQueueEntries = Comp->MessageQueue->PendingMessageEntries.Num(); + //Data.EmotionalBehavior = static_cast(Comp->GetEmotionalBehavior()); + //Data.EmotionStrength = static_cast(Comp->GetEmotionStrength()); + //Data.bPendingRepAudioEvent = !Comp->PendingRepAudioEvents.IsEmpty(); } for (TObjectIterator Itr; Itr; ++Itr) { + //TODO: FIX auto* AudioComp = *Itr; - auto* PlayerComp = AudioComp->PlayerComponent.Get(); + //auto* PlayerComp = AudioComp->PlayerComponent.Get(); - if (!PlayerComp) + //if (!PlayerComp) { - continue; + //continue; } auto& Data = DataPack.PlayerData.Emplace_GetRef(); //TODO: support multi agent - Data.TargetCharacterAgentId = (PlayerComp->Targets.Num() == 0) ? "" : PlayerComp->Targets[0].AgentId; - Data.bServerCapturingVoice = AudioComp->bServerCapturingVoice; + //Data.TargetCharacterAgentId = (PlayerComp->Targets.Num() == 0) ? "" : PlayerComp->Targets[0].AgentId; + //Data.bServerCapturingVoice = AudioComp->bServerCapturingVoice; } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp new file mode 100644 index 00000000..cc7288a8 --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -0,0 +1,24 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + + +#include "InworldPlayer.h" +#include "InworldSession.h" + +TScriptInterface UInworldPlayer::GetInworldPlayerOwner() +{ + if (!ensureMsgf(GetOuter()->Implements(), TEXT("UInworldPlayer outer must implement IInworldPlayerOwnerInterface!"))) + { + return nullptr; + } + return TScriptInterface(GetOuter()); +} +/* +void UInworldPlayer::SendTextMessageToTargets(const FString& Message) +{ + GetInworldPlayerOwner()->GetInworldSession()->BroadcastTextMessage(GetTargetInworldCharacters(), Message); +}*/ \ No newline at end of file diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index 5b2ffb0d..a6e4ba62 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -163,16 +163,7 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() if (GetOwnerRole() == ROLE_Authority) { - InworldSubsystem = GetWorld()->GetSubsystem(); - - InworldSubsystem->OnConnectionStateChanged.AddDynamic(this, &UInworldPlayerAudioCaptureComponent::OnInworldConnectionStateChanged); - - PlayerComponent = Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass())); - if (ensureMsgf(PlayerComponent.IsValid(), TEXT("UInworldPlayerAudioCaptureComponent::BeginPlay: add InworldPlayerComponent."))) - { - PlayerTargetSetHandle = PlayerComponent->OnTargetSet.AddUObject(this, &UInworldPlayerAudioCaptureComponent::OnPlayerTargetSet); - PlayerTargetClearHandle = PlayerComponent->OnTargetClear.AddUObject(this, &UInworldPlayerAudioCaptureComponent::OnPlayerTargetClear); - } + InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))); PrimaryComponentTick.SetTickFunctionEnable(false); } @@ -223,17 +214,6 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() void UInworldPlayerAudioCaptureComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) { - if (GetOwnerRole() == ROLE_Authority) - { - InworldSubsystem->OnConnectionStateChanged.RemoveDynamic(this, &UInworldPlayerAudioCaptureComponent::OnInworldConnectionStateChanged); - } - - if (PlayerComponent.IsValid()) - { - PlayerComponent->OnTargetSet.Remove(PlayerTargetSetHandle); - PlayerComponent->OnTargetClear.Remove(PlayerTargetClearHandle); - } - if (bCapturingVoice) { StopCapture(); @@ -286,26 +266,30 @@ void UInworldPlayerAudioCaptureComponent::EvaluateVoiceCapture() const bool bIsMicHot = !bMuted; const bool bIsWorldPlaying = !GetWorld()->IsPaused(); const bool bHasTargetCharacter = PlayerAudioTarget.DesiredAgentIds.Num() != 0; - const bool bHasActiveInworldSession = InworldSubsystem.IsValid() && (InworldSubsystem->GetConnectionState() == EInworldConnectionState::Connected || InworldSubsystem->GetConnectionState() == EInworldConnectionState::Reconnecting); + const bool bHasPlayer = InworldPlayer != nullptr; + UInworldSession* InworldSession = bHasPlayer ? IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()) : nullptr; + const EInworldConnectionState ConnectionState = InworldSession != nullptr ? InworldSession->GetConnectionState() : EInworldConnectionState::Idle; + const bool bHasActiveInworldSession = ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting; - const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasTargetCharacter && bHasActiveInworldSession; + const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasTargetCharacter && bHasPlayer && bHasActiveInworldSession; + //TODO: FIX if (bShouldCaptureVoice && bServerCapturingVoice && (PlayerAudioTarget.DesiredAgentIds != PlayerAudioTarget.ActiveAgentIds)) { - InworldSubsystem->StopAudioSessionMultiAgent(PlayerAudioTarget.ActiveAgentIds); - InworldSubsystem->StartAudioSessionMultiAgent(PlayerAudioTarget.DesiredAgentIds, GetOwner()); + //InworldSubsystem->StopAudioSessionMultiAgent(PlayerAudioTarget.ActiveAgentIds); + //InworldSubsystem->StartAudioSessionMultiAgent(PlayerAudioTarget.DesiredAgentIds, GetOwner()); PlayerAudioTarget.ActiveAgentIds = PlayerAudioTarget.DesiredAgentIds; } else if (bShouldCaptureVoice != bServerCapturingVoice) { if (bShouldCaptureVoice) { - InworldSubsystem->StartAudioSessionMultiAgent(PlayerAudioTarget.DesiredAgentIds, GetOwner()); + //InworldSubsystem->StartAudioSessionMultiAgent(PlayerAudioTarget.DesiredAgentIds, GetOwner()); PlayerAudioTarget.ActiveAgentIds = PlayerAudioTarget.DesiredAgentIds; } else { - InworldSubsystem->StopAudioSessionMultiAgent(PlayerAudioTarget.ActiveAgentIds); + //InworldSubsystem->StopAudioSessionMultiAgent(PlayerAudioTarget.ActiveAgentIds); PlayerAudioTarget.ActiveAgentIds.Empty(); } @@ -319,11 +303,6 @@ void UInworldPlayerAudioCaptureComponent::EvaluateVoiceCapture() } } -void UInworldPlayerAudioCaptureComponent::OnInworldConnectionStateChanged(EInworldConnectionState ConnectionState) -{ - EvaluateVoiceCapture(); -} - void UInworldPlayerAudioCaptureComponent::ServerSetMuted_Implementation(bool bInMuted) { bMuted = bInMuted; @@ -422,16 +401,10 @@ void UInworldPlayerAudioCaptureComponent::StopCapture() void UInworldPlayerAudioCaptureComponent::Server_ProcessVoiceCaptureChunk_Implementation(FPlayerVoiceCaptureInfoRep PlayerVoiceCaptureInfo) { + //TODO: FIX if (PlayerAudioTarget.ActiveAgentIds.Num() != 0) { - if (bEnableAEC) - { - InworldSubsystem->SendAudioDataMessageWithAEC(PlayerAudioTarget.ActiveAgentIds, PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); - } - else - { - InworldSubsystem->SendAudioDataMessage(PlayerAudioTarget.ActiveAgentIds, PlayerVoiceCaptureInfo.MicSoundData); - } + //InworldSubsystem->SendAudioMessage(PlayerAudioTarget.ActiveAgentIds, PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); } } @@ -440,7 +413,7 @@ bool UInworldPlayerAudioCaptureComponent::IsLocallyControlled() const auto* Controller = Cast(GetOwner()->GetInstigatorController()); return Controller && Controller->IsLocalController(); } - +/* void UInworldPlayerAudioCaptureComponent::OnPlayerTargetSet(UInworldCharacterComponent* Target) { if (PlayerAudioTarget.DesiredAgentIds.Contains(Target->GetAgentId())) @@ -460,6 +433,7 @@ void UInworldPlayerAudioCaptureComponent::OnPlayerTargetClear(UInworldCharacterC PlayerAudioTarget.DesiredAgentIds.RemoveSingle(Target->GetAgentId()); EvaluateVoiceCapture(); } +*/ void UInworldPlayerAudioCaptureComponent::Rep_ServerCapturingVoice() { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index 228c2b9a..bcf9ba40 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -12,206 +12,120 @@ #include #include +UInworldPlayerComponent::UInworldPlayerComponent() + : Super() +{ + bWantsInitializeComponent = true; +} + +void UInworldPlayerComponent::InitializeComponent() +{ + Super::InitializeComponent(); + + InworldPlayer = NewObject(this, "InworldPlayer"); +} + +void UInworldPlayerComponent::UninitializeComponent() +{ + Super::UninitializeComponent(); + + InworldPlayer = nullptr; +} + void UInworldPlayerComponent::BeginPlay() { Super::BeginPlay(); - SetIsReplicated(true); + InworldPlayer = NewObject(this); + + InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); - InworldSubsystem = GetWorld()->GetSubsystem(); + SetIsReplicated(true); } void UInworldPlayerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) { + InworldPlayer = nullptr; + Super::EndPlay(EndPlayReason); } void UInworldPlayerComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); - - DOREPLIFETIME(UInworldPlayerComponent, Targets); } -TArray UInworldPlayerComponent::GetTargetInworldCharacters() +UInworldCharacterComponent* UInworldPlayerComponent::GetTargetInworldCharacter() { - if (!InworldSubsystem.IsValid()) + TArray TargetCharacters = GetTargetInworldCharacters(); + if (TargetCharacters.Num() > 0) { - return {}; + return TargetCharacters[0]; } - - TArray Result; - for (auto& Target : Targets) - { - if (!Target.AgentId.IsEmpty()) - { - Result.Add(static_cast(InworldSubsystem->GetCharacterComponentByAgentId(Target.AgentId))); - } - } - - return Result; + return nullptr; } -TArray UInworldPlayerComponent::GetTargetAgentIds() +TArray UInworldPlayerComponent::GetTargetInworldCharacters() { - TArray AgentIds; - for (auto& Target : Targets) + TArray InworldCharacterComponents; + for (UInworldCharacter* Character : InworldPlayer->GetTargetInworldCharacters()) { - AgentIds.Add(Target.AgentId); + UInworldCharacterComponent* InworldCharacterComponent = Cast(Character->GetInworldCharacterOwner().GetObject()); + if (InworldCharacterComponent) + { + InworldCharacterComponents.Add(InworldCharacterComponent); + } } - return AgentIds; + return InworldCharacterComponents; } void UInworldPlayerComponent::ContinueMultiAgentConversation() { - if (Targets.Num() > 1) + if (InworldPlayer->GetTargetInworldCharacters().Num() > 1) { - InworldSubsystem->SendTriggerMultiAgent(GetTargetAgentIds(), "inworld.conversation.next_turn", {}); + InworldSession->BroadcastTrigger(InworldPlayer->GetTargetInworldCharacters(), "inworld.conversation.next_turn", {}); } } -Inworld::ICharacterComponent* UInworldPlayerComponent::GetTargetCharacter() -{ - if (Targets.Num() == 0) - { - return nullptr; - } - - if (InworldSubsystem.IsValid() && !Targets[0].AgentId.IsEmpty()) - { - return InworldSubsystem->GetCharacterComponentByAgentId(Targets[0].AgentId); - } - - return nullptr; -} - void UInworldPlayerComponent::SetTargetInworldCharacter(UInworldCharacterComponent* Character) { - if (!ensureMsgf(Character && !Character->GetAgentId().IsEmpty(), TEXT("UInworldPlayerComponent::SetTargetCharacter: the Character must have valid AgentId"))) - { - return; - } - - if (!Character->StartPlayerInteraction(this)) - { - return; - } - - if (Targets.FindByPredicate([Character](const auto& T) { return Character->GetAgentId() == T.AgentId; }) != nullptr) - { - return; - } - - FInworldPlayerTargetCharacter Target; - Target.UnpossessedHandle = Character->OnUnpossessed.AddLambda([this, Character]() { ClearTargetInworldCharacter(Character); }); - Target.AgentId = Character->GetAgentId(); - Targets.Add(Target); - OnTargetSet.Broadcast(Character); + InworldPlayer->AddTargetInworldCharacter(Character->GetInworldCharacter()); } void UInworldPlayerComponent::ClearTargetInworldCharacter(UInworldCharacterComponent* Character) { - if (!Character) - { - return; - } - - auto* Target = Targets.FindByPredicate([Character](const auto& T) { return Character->GetAgentId() == T.AgentId; }); - if (!Target) - { - return; - } - - if (Character && Character->StopPlayerInteraction(this)) - { - Character->OnUnpossessed.Remove(Target->UnpossessedHandle); - OnTargetClear.Broadcast(Character); - } - - Targets.RemoveAt(Target - &Targets[0]); + InworldPlayer->RemoveTargetInworldCharacter(Character->GetInworldCharacter()); } void UInworldPlayerComponent::ClearAllTargetInworldCharacters() { - const int32 NumTargets = Targets.Num(); - for (int32 i = 0; i < NumTargets; i++) - { - UInworldCharacterComponent* TargetCharacter = static_cast(InworldSubsystem->GetCharacterComponentByAgentId(Targets[0].AgentId)); - ClearTargetInworldCharacter(TargetCharacter); - } + InworldPlayer->ClearAllTargetInworldCharacters(); } void UInworldPlayerComponent::SendTextMessageToTarget_Implementation(const FString& Message) { if (!Message.IsEmpty()) { - InworldSubsystem->SendTextMessageMultiAgent(GetTargetAgentIds(), Message); + InworldSession->BroadcastTextMessage(InworldPlayer->GetTargetInworldCharacters(), Message); } } -void UInworldPlayerComponent::SendTextMessage_Implementation(const FString& Message, const FString& AgentId) -{ - if (!Message.IsEmpty() && !AgentId.IsEmpty()) - { - InworldSubsystem->SendTextMessage(AgentId, Message); - } -} - void UInworldPlayerComponent::SendTriggerToTarget(const FString& Name, const TMap& Params) { - InworldSubsystem->SendTriggerMultiAgent(GetTargetAgentIds(), Name, Params); + InworldSession->BroadcastTrigger(InworldPlayer->GetTargetInworldCharacters(), Name, Params); } void UInworldPlayerComponent::StartAudioSessionWithTarget() { - InworldSubsystem->StartAudioSessionMultiAgent(GetTargetAgentIds(), GetOwner()); + InworldSession->BroadcastAudioSessionStart(InworldPlayer->GetTargetInworldCharacters()); } void UInworldPlayerComponent::StopAudioSessionWithTarget() { - for (auto& Target : Targets) - { - InworldSubsystem->StopAudioSession(Target.AgentId); - } -} - -void UInworldPlayerComponent::SendAudioMessageToTarget(USoundWave* SoundWave) -{ - InworldSubsystem->SendAudioMessage(GetTargetAgentIds(), SoundWave); -} - -void UInworldPlayerComponent::SendAudioDataMessageToTarget(const TArray& Data) -{ - InworldSubsystem->SendAudioDataMessage(GetTargetAgentIds(), Data); -} - -void UInworldPlayerComponent::SendAudioDataMessageWithAECToTarget(const TArray& InputData, const TArray& OutputData) -{ - InworldSubsystem->SendAudioDataMessageWithAEC(GetTargetAgentIds(), InputData, OutputData); + InworldSession->BroadcastAudioSessionStop(InworldPlayer->GetTargetInworldCharacters()); } -void UInworldPlayerComponent::OnRep_Targets(const TArray& OldTargets) +void UInworldPlayerComponent::SendAudioMessageToTarget(const TArray& InputData, const TArray& OutputData) { - if (!ensure(InworldSubsystem.IsValid())) - { - return; - } - - for (auto& Target : OldTargets) - { - if (Targets.FindByPredicate([&Target](const auto& T) { return T.AgentId == Target.AgentId; }) == nullptr) - { - auto* Component = static_cast(InworldSubsystem->GetCharacterComponentByAgentId(Target.AgentId)); - OnTargetClear.Broadcast(Component); - } - } - - for (auto& Target : Targets) - { - if (OldTargets.FindByPredicate([&Target](const auto& T) { return T.AgentId == Target.AgentId; }) == nullptr) - { - auto* Component = static_cast(InworldSubsystem->GetCharacterComponentByAgentId(Target.AgentId)); - OnTargetSet.Broadcast(Component); - } - } + InworldSession->BroadcastSoundMessage(InworldPlayer->GetTargetInworldCharacters(), InputData, OutputData); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 44fb6b4f..3eb799f1 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -6,6 +6,7 @@ */ #include "InworldPlayerTargetingComponent.h" +#include "InworldPlayer.h" #include "InworldPlayerComponent.h" #include "Camera/CameraComponent.h" #include "Engine/World.h" @@ -27,9 +28,7 @@ void UInworldPlayerTargetingComponent::BeginPlay() else { PrimaryComponentTick.SetTickFunctionEnable(true); - - InworldSubsystem = GetWorld()->GetSubsystem(); - PlayerComponent = Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass())); + InworldPlayer = Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))->GetInworldPlayer(); } } @@ -42,22 +41,18 @@ void UInworldPlayerTargetingComponent::TickComponent(float DeltaTime, enum ELeve void UInworldPlayerTargetingComponent::UpdateTargetCharacters() { - auto* Player = PlayerComponent.Get(); - + //TODO: FIX // prevent starting another audio session in multiplayer - const auto* CurrentAudioSessionOwner = InworldSubsystem->GetAudioSessionOwner(); - if (CurrentAudioSessionOwner && CurrentAudioSessionOwner != Player->GetOwner()) - { - return; - } + //const auto* CurrentAudioSessionOwner = InworldSubsystem->GetAudioSessionOwner(); + //if (CurrentAudioSessionOwner && CurrentAudioSessionOwner != Player->GetOwner()) + //{ + // return; + //} // clear all targets if just switched from multiple targeting if (!bMultipleTargets && TargetCharacters.Num() > 1) { - for (auto* Character : TargetCharacters) - { - Player->ClearTargetInworldCharacter(Character); - } + InworldPlayer->ClearAllTargetInworldCharacters(); TargetCharacters.Empty(); } @@ -66,40 +61,35 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() const FVector Location = GetOwner()->GetActorLocation(); for (int32 i = 0; i < TargetCharacters.Num(); i++) { - auto* Character = TargetCharacters[i]; - const FVector CharacterLocation = Character->GetComponentOwner()->GetActorLocation(); + UInworldCharacter* Character = TargetCharacters[i]; + const FVector CharacterLocation = Character->GetInworldCharacterOwner()->GetInworldCharacterTransform().GetLocation(); const float DistSq = FVector::DistSquared(Location, CharacterLocation); if (DistSq > MinDistSq) { - Player->ClearTargetInworldCharacter(Character); + InworldPlayer->RemoveTargetInworldCharacter(Character); TargetCharacters.RemoveAt(i); i--; } } - const auto& CharacterComponents = InworldSubsystem->GetCharacterComponents(); - UInworldCharacterComponent* BestTarget = nullptr; + const TArray& Characters = InworldPlayer->GetInworldPlayerOwner()->GetInworldSession()->GetRegisteredCharacters(); + UInworldCharacter* BestTarget = nullptr; float BestTargetDot = -1.f; - for (auto& Char : CharacterComponents) + for (UInworldCharacter* Character : Characters) { - auto* Character = static_cast(Char); - if (!Character || Character->GetAgentId().IsEmpty()) - { - continue; - } - - const FVector CharacterLocation = Character->GetComponentOwner()->GetActorLocation(); + const FVector CharacterLocation = Character->GetInworldCharacterOwner()->GetInworldCharacterTransform().GetLocation(); const float DistSq = FVector::DistSquared(Location, CharacterLocation); if (DistSq > MinDistSq) { continue; } - const auto* CurrentTargetPlayer = Character->GetTargetPlayer(); - if (CurrentTargetPlayer && CurrentTargetPlayer != Player) - { - continue; - } + //TODO: FIX + //const auto* CurrentTargetPlayer = Character->GetTargetPlayer(); + //if (CurrentTargetPlayer && CurrentTargetPlayer != Player) + //{ + // continue; + //} // if multiple targets enabled add all characters in range if (bMultipleTargets) @@ -111,7 +101,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() } TargetCharacters.Add(Character); - PlayerComponent->SetTargetInworldCharacter(Character); + InworldPlayer->AddTargetInworldCharacter(Character); continue; } @@ -142,19 +132,19 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() return; } - auto* CurTarget = TargetCharacters.Num() != 0 ? TargetCharacters[0] : nullptr; - if (CurTarget != BestTarget) + UInworldCharacter* CurrentTarget = TargetCharacters.Num() != 0 ? TargetCharacters[0] : nullptr; + if (CurrentTarget != BestTarget) { - if (CurTarget) + if (CurrentTarget) { - PlayerComponent->ClearTargetInworldCharacter(CurTarget); + InworldPlayer->RemoveTargetInworldCharacter(CurrentTarget); TargetCharacters.Empty(); } if (BestTarget) { TargetCharacters.Add(BestTarget); - PlayerComponent->SetTargetInworldCharacter(BestTarget); + InworldPlayer->AddTargetInworldCharacter(BestTarget); } } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp new file mode 100644 index 00000000..64cb3a04 --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -0,0 +1,219 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + + +#include "InworldSession.h" +#include "InworldCharacter.h" +#include "InworldClient.h" + +UInworldSession::UInworldSession() + : InworldClient(NewObject(this, TEXT("InworldClient"))) +{ + OnClientPacketReceivedHandle = InworldClient->OnPacketReceived().AddLambda( + [this](const FInworldWrappedPacket& WrappedPacket) -> void + { + OnPacketReceivedDelegateNative.Broadcast(WrappedPacket); + OnPacketReceivedDelegate.Broadcast(WrappedPacket); + } + ); + OnClientConnectionStateChangedHandle = InworldClient->OnConnectionStateChanged().AddLambda( + [this](EInworldConnectionState ConnectionState) -> void + { + OnConnectionStateChangedDelegateNative.Broadcast(ConnectionState); + OnConnectionStateChangedDelegate.Broadcast(ConnectionState); + } + ); + OnClientPerceivedLatencyHandle = InworldClient->OnPerceivedLatency().AddLambda( + [this](const FString& InteractionId, int32 LatencyMs) -> void + { + OnPerceivedLatencyDelegateNative.Broadcast(InteractionId, LatencyMs); + OnPerceivedLatencyDelegate.Broadcast(InteractionId, LatencyMs); + } + ); +} + +UInworldSession::~UInworldSession() +{ + InworldClient->OnPacketReceived().Remove(OnClientPacketReceivedHandle); + InworldClient->OnConnectionStateChanged().Remove(OnClientConnectionStateChangedHandle); + InworldClient->OnPerceivedLatency().Remove(OnClientPerceivedLatencyHandle); + InworldClient = nullptr; +} + +void UInworldSession::RegisterCharacter(UInworldCharacter* Character) +{ + const FString& BrainName = Character->GetBrainName(); + if (!ensureMsgf(!BrainNameToCharacter.Contains(BrainName), TEXT("UInworldSession::RegisterInworldCharacter: Character already registered for Brain: %s!"), *BrainName)) + { + return; + } + + RegisteredCharacters.Add(Character); + BrainNameToCharacter.Add(BrainName, Character); + + if (bCharactersInitialized) + { + if (BrainNameToAgentInfo.Contains(BrainName)) + { + auto AgentInfo = BrainNameToAgentInfo[BrainName]; + AgentIdToCharacter.Add(AgentInfo.AgentId, Character); + Character->Possess(AgentInfo); + } + else + { + InworldClient->LoadCharacter(BrainName); + } + } +} + +void UInworldSession::UnregisterCharacter(UInworldCharacter* Character) +{ + const FString& BrainName = Character->GetBrainName(); + if (!ensureMsgf(BrainNameToCharacter.Contains(BrainName) && BrainNameToCharacter[BrainName] == Character, TEXT("UInworldSession::UnregisterInworldCharacter: Component mismatch for Brain: %s!"), *BrainName)) + { + return; + } + + AgentIdToCharacter.Remove(Character->GetAgentId()); + BrainNameToCharacter.Remove(BrainName); + RegisteredCharacters.Remove(Character); + InworldClient->UnloadCharacter(BrainName); + Character->Unpossess(); +} + +void UInworldSession::StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet) +{ + InworldClient->StartSession(SceneId, PlayerProfile, Auth, Save, SessionToken, CapabilitySet); +} + +void UInworldSession::StopSession() +{ + UnpossessAgents(); + InworldClient->StopSession(); +} + +TArray CharactersToAgentIds(const TArray& InworldCharacters) +{ + TArray AgentIds = {}; + AgentIds.Reserve(InworldCharacters.Num()); + for (const UInworldCharacter* Character : InworldCharacters) + { + AgentIds.Add(Character->GetAgentId()); + } + return AgentIds; +} + +void UInworldSession::LoadCharacters(const TArray& Characters) +{ + InworldClient->LoadCharacters(CharactersToAgentIds(Characters)); +} + +void UInworldSession::UnloadCharacters(const TArray& Characters) +{ + InworldClient->UnloadCharacters(CharactersToAgentIds(Characters)); +} + +FInworldWrappedPacket UInworldSession::BroadcastTextMessage(const TArray& Characters, const FString& Message) +{ + return InworldClient->SendTextMessage(CharactersToAgentIds(Characters), Message); +} + +void UInworldSession::BroadcastSoundMessage(const TArray& Characters, const TArray& InputData, const TArray& OutputData) +{ + InworldClient->BroadcastSoundMessage(CharactersToAgentIds(Characters), InputData, OutputData); +} + +void UInworldSession::BroadcastAudioSessionStart(const TArray& Characters) +{ + InworldClient->BroadcastAudioSessionStart(CharactersToAgentIds(Characters)); +} + +void UInworldSession::BroadcastAudioSessionStop(const TArray& Characters) +{ + InworldClient->BroadcastAudioSessionStop(CharactersToAgentIds(Characters)); +} + +void UInworldSession::SendNarrationEvent(UInworldCharacter* Character, const FString& Content) +{ + InworldClient->SendNarrationEvent(Character->GetAgentId(), Content); +} + +void UInworldSession::BroadcastTrigger(const TArray& Characters, const FString& Name, const TMap& Params) +{ + InworldClient->BroadcastTrigger(CharactersToAgentIds(Characters), Name, Params); +} + +void UInworldSession::SendChangeSceneEvent(const FString& SceneName) +{ + UnpossessAgents(); + InworldClient->SendChangeSceneEvent(SceneName); +} + +void UInworldSession::CancelResponse(UInworldCharacter* Character, const FString& InteractionId, const TArray& UtteranceIds) +{ + InworldClient->CancelResponse(Character->GetAgentId(), InteractionId, UtteranceIds); +} + +void UInworldSession::PossessAgents(const TArray& AgentInfos) +{ + for (const auto& AgentInfo : AgentInfos) + { + const FString& BrainName = AgentInfo.BrainName; + BrainNameToAgentInfo.Add(BrainName, AgentInfo); + if (BrainNameToCharacter.Contains(BrainName)) + { + UInworldCharacter* Character = BrainNameToCharacter[BrainName]; + if (!Character->GetAgentId().IsEmpty()) + { + AgentIdToCharacter.Add(AgentInfo.AgentId, Character); + Character->Possess(AgentInfo); + } + } + else if (BrainName != FString("__DUMMY__")) + { + UE_LOG(LogInworldAIIntegration, Warning, TEXT("No character found for BrainName: %s"), *BrainName); + } + } + + TArray BrainNames; + for (UInworldCharacter* Character : RegisteredCharacters) + { + const FString& BrainName = Character->GetBrainName(); + if (!BrainNameToAgentInfo.Contains(BrainName)) + { + BrainNames.Add(BrainName); + } + } + + if (BrainNames.Num() > 0) + { + InworldClient->LoadCharacters(BrainNames); + } + + bCharactersInitialized = true; + OnCharactersInitializedDelegateNative.Broadcast(bCharactersInitialized); + OnCharactersInitializedDelegate.Broadcast(bCharactersInitialized); +} + +void UInworldSession::UnpossessAgents() +{ + if (!bCharactersInitialized) + { + return; + } + + for (UInworldCharacter* Character : RegisteredCharacters) + { + Character->Unpossess(); + } + + AgentIdToCharacter.Empty(); + BrainNameToAgentInfo.Empty(); + bCharactersInitialized = false; + OnCharactersInitializedDelegateNative.Broadcast(bCharactersInitialized); + OnCharactersInitializedDelegate.Broadcast(bCharactersInitialized); +} diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index 65edcc66..0dcb358c 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -12,18 +12,13 @@ #include "Runtime/Launch/Resources/Version.h" #include "InworldClient.h" +#include "InworldSession.h" #include "InworldEnums.h" #include "InworldTypes.h" #include "InworldPackets.h" -#include "InworldComponentInterface.h" #include "InworldApi.generated.h" -namespace Inworld -{ - class ICharacterComponent; - class IPlayerComponent; -} class USoundWave; class UInworldAudioRepl; @@ -31,18 +26,18 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnConnectionStateChanged, EInworldC DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCharactersInitialized, bool, bCharactersInitialized); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCustomTrigger, FString, Name); -DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnSaveReady, FInworldSave, Save, bool, bSuccess); - -DECLARE_DYNAMIC_DELEGATE_TwoParams(FResponseLatencyTrackerDelegate, FString, InteractionId, int32, LatencyMs); - UCLASS(BlueprintType, Config = InworldAI) -class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, public InworldPacketVisitor +class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, public InworldPacketVisitor, public IInworldSessionOwnerInterface { GENERATED_BODY() public: UInworldApiSubsystem(); + // IInworldSessionOwnerInterface + UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } + // IInworldSessionOwnerInterface + /** * Start InworldAI session * call after all Player/Character components have been registered @@ -81,24 +76,24 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu * Save InworldAI session data */ UFUNCTION(BlueprintCallable, Category = "Inworld") - void SaveSession(FOnSaveReady Delegate); + void SaveSession(FOnInworldSessionSavedCallback Delegate); /** * Set delegate for response latency tracker */ UFUNCTION(BlueprintCallable, Category = "Inworld") - void SetResponseLatencyTrackerDelegate(FResponseLatencyTrackerDelegate Delegate); + void SetResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate); /** * Clear delegate for response latency tracker */ UFUNCTION(BlueprintCallable, Category = "Inworld") - void ClearResponseLatencyTrackerDelegate(); + void ClearResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate); /** * Load new characters */ - UFUNCTION(BlueprintCallable, Category = "Inworld") + UFUNCTION(BlueprintCallable, Category = "Inworld", meta = (DeprecatedFunction, DeprecationMessage = "Please use GetInworldSession::LoadCharacters node")) void LoadCharacters(const TArray& Names); /** @@ -111,7 +106,7 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu * Load saved state */ UFUNCTION(BlueprintCallable, Category = "Inworld") - void LoadSavedState(const TArray& SavedState); + void LoadSavedState(const FInworldSave& SavedState); /** * Load capabilities @@ -125,22 +120,6 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu UFUNCTION(BlueprintCallable, Category = "Inworld") void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile); -private: - void PossessAgents(const TArray& AgentInfos); - void UnpossessAgents(); - -public: - /** - * Register Character component - * call before StartSession - */ - void RegisterCharacterComponent(Inworld::ICharacterComponent* Component); - void UnregisterCharacterComponent(Inworld::ICharacterComponent* Component); - - bool IsCharacterComponentRegistered(Inworld::ICharacterComponent* Component); - - void UpdateCharacterComponentRegistrationOnClient(Inworld::ICharacterComponent* Component, const FString& NewAgentId, const FString& OldAgentId); - public: /** Send text to agent */ UFUNCTION(BlueprintCallable, Category = "Messages") @@ -169,16 +148,7 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu * chunks should be ~100ms */ UFUNCTION(BlueprintCallable, Category = "Messages") - void SendAudioMessage(const FString& AgentId, USoundWave* SoundWave); - void SendAudioMessage(const TArray& AgentIds, USoundWave* SoundWave); - void SendAudioDataMessage(const FString& AgentId, const TArray& Data); - void SendAudioDataMessage(const TArray& AgentIds, const TArray& Data); - - - UFUNCTION(BlueprintCallable, Category = "Messages") - void SendAudioMessageWithAEC(const FString& AgentId, USoundWave* InputWave, USoundWave* OutputWave); - void SendAudioDataMessageWithAEC(const FString& AgentId, const TArray& InputData, const TArray& OutputData); - void SendAudioDataMessageWithAEC(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData); + void SendAudioMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData); /** * Start audio session with agent @@ -210,28 +180,16 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu /** Get current connection state */ UFUNCTION(BlueprintCallable, Category = "Connection") - EInworldConnectionState GetConnectionState() const { return Client->GetConnectionState(); } + EInworldConnectionState GetConnectionState() const { return InworldSession->GetConnectionState(); } /** Get connection error message and code from previous Disconnect */ UFUNCTION(BlueprintCallable, Category = "Inworld") void GetConnectionError(FString& Message, int32& Code); - - /** Get all registered character components */ - const TArray& GetCharacterComponents() const { return CharacterComponentRegistry; } - - /** Get registered character component by agent id */ - Inworld::ICharacterComponent* GetCharacterComponentByAgentId(const FString& AgentId) const; /** Cancel agents response in case agent has been interrupted by player */ UFUNCTION(BlueprintCallable, Category = "Messages") void CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds); - /** - * Call on Inworld::FCustomEvent coming to agent - * custom events meant to be triggered on interaction end (see InworldCharacterComponent) - */ - void NotifyCustomTrigger(const FString& Name) { OnCustomTrigger.Broadcast(Name); } - /** * Call this in multiplayer on BeginPlay both on server and client * called in UE5 automatically @@ -250,30 +208,13 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu void ReplicateAudioEventFromServer(FInworldAudioDataEvent& Packet); void HandleAudioEventOnClient(TSharedPtr Packet); - UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "EventDispatchers") + UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "EventDispatchers", meta = (DeprecatedProperty, DeprecationMessage = "Use InworldSession->OnConnectionStateChanged.")) FOnConnectionStateChanged OnConnectionStateChanged; - UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "EventDispatchers") + UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "EventDispatchers", meta = (DeprecatedProperty, DeprecationMessage = "Use InworldSession->OnCharactersInitialized.")) FOnCharactersInitialized OnCharactersInitialized; - UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "EventDispatchers") - FCustomTrigger OnCustomTrigger; - private: - void DispatchPacket(TSharedPtr InworldPacket); - - virtual void Visit(const FInworldChangeSceneEvent& Event) override; - virtual void Visit(const FInworldLoadCharactersEvent& Event) override; - - UPROPERTY(EditAnywhere, config, Category = "Connection") - FString SentryDSN; - - UPROPERTY(EditAnywhere, config, Category = "Connection") - FString SentryTransactionName; - - UPROPERTY(EditAnywhere, config, Category = "Connection") - FString SentryTransactionOperation; - UPROPERTY(EditAnywhere, config, Category = "Connection") float RetryConnectionIntervalTime = 0.25f; @@ -290,14 +231,8 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu FTimerHandle RetryConnectionTimerHandle; - TMap CharacterComponentByBrainName; - TMap CharacterComponentByAgentId; - TArray CharacterComponentRegistry; - TMap AgentInfoByBrain; - - TSharedPtr Client; - - bool bCharactersInitialized = false; + UPROPERTY() + UInworldSession* InworldSession; #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h new file mode 100644 index 00000000..6bf6471d --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -0,0 +1,63 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "InworldTypes.h" +#include "InworldCharacter.generated.h" + + +UCLASS(BlueprintType) +class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category = "Inworld|Player") + TScriptInterface GetInworldCharacterOwner(); + + void SetBrainName(const FString& BrainName); + + void Possess(const FInworldAgentInfo& InAgentInfo); + void Unpossess(); + + UFUNCTION(BlueprintPure, Category = "Inworld|Agent") + const FString& GetBrainName() const { return AgentInfo.BrainName; } + UFUNCTION(BlueprintPure, Category = "Inworld|Agent") + const FString& GetAgentId() const { return AgentInfo.AgentId; } + UFUNCTION(BlueprintPure, Category = "Inworld|Agent") + const FString& GetGivenName() const { return AgentInfo.GivenName; } + +private: + FInworldAgentInfo AgentInfo; +}; + + +UINTERFACE(MinimalAPI, BlueprintType) +class UInworldCharacterOwnerInterface : public UInterface +{ + GENERATED_BODY() +}; + +class INWORLDAIINTEGRATION_API IInworldCharacterOwnerInterface +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") + UInworldSession* GetInworldSession() const; + + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") + UInworldCharacter* GetInworldCharacter() const; + +public: + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") + FTransform GetInworldCharacterTransform() const; +}; + diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index 5bf66f63..ad15b900 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -9,9 +9,9 @@ #include "CoreMinimal.h" #include "InworldApi.h" +#include "InworldCharacter.h" #include "Components/ActorComponent.h" -#include "InworldComponentInterface.h" #include "InworldCharacterPlayback.h" #include "InworldCharacterMessage.h" #include "InworldEnums.h" @@ -28,13 +28,19 @@ class UInworldPlayerComponent; class FInternetAddr; UCLASS(ClassGroup = (Inworld), meta = (BlueprintSpawnableComponent)) -class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorComponent, public InworldPacketVisitor, public Inworld::ICharacterComponent, public ICharacterMessageVisitor +class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorComponent, public InworldPacketVisitor, public ICharacterMessageVisitor, public IInworldCharacterOwnerInterface { GENERATED_BODY() public: UInworldCharacterComponent(); + // IInworldCharacterOwnerInterface + UInworldCharacter* GetInworldCharacter_Implementation() const { return InworldCharacter; } + UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } + FTransform GetInworldPlayerTransform() const { return GetOwner()->GetTransform(); } + // IInworldCharacterOwnerInterface + virtual void InitializeComponent() override; virtual void UninitializeComponent() override; @@ -80,23 +86,17 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; - virtual void Possess(const FInworldAgentInfo& AgentInfo) override; - virtual void Unpossess() override; - virtual bool IsPossessing() override { return !AgentId.IsEmpty(); } - UFUNCTION(BlueprintCallable, Category = "Inworld") void SetBrainName(const FString& Name); UFUNCTION(BlueprintCallable, Category = "Inworld") - virtual const FString& GetBrainName() const override { return BrainName; } + const FString& GetBrainName() const { return InworldCharacter->GetBrainName(); } UFUNCTION(BlueprintCallable, Category = "Inworld") - virtual const FString& GetAgentId() const override { return AgentId; } + const FString& GetAgentId() const { return InworldCharacter->GetAgentId(); } UFUNCTION(BlueprintCallable, Category = "Inworld") - virtual const FString& GetGivenName() const override { return GivenName; } - - virtual AActor* GetComponentOwner() const override { return GetOwner(); } + const FString& GetGivenName() const { return InworldCharacter->GetGivenName(); } UFUNCTION(BlueprintCallable, Category = "Inworld") const FString& GetUiName() const { return UiName; } @@ -106,9 +106,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UFUNCTION(BlueprintCallable, Category = "Inworld", meta = (DeterminesOutputType = "Class")) UInworldCharacterPlayback* GetPlayback(TSubclassOf Class) const; - virtual void HandlePacket(TSharedPtr Packet) override; - - virtual Inworld::IPlayerComponent* GetTargetPlayer() override; + void HandlePacket(TSharedPtr Packet); bool StartPlayerInteraction(UInworldPlayerComponent* Player); bool StopPlayerInteraction(UInworldPlayerComponent* Player); @@ -129,9 +127,6 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone void SendTrigger(const FString& Name, const TMap& Params) const; [[deprecated("UInworldCharacterComponent::SendCustomEvent is deprecated, please use UInworldCharacterComponent::SendTrigger")]] void SendCustomEvent(const FString& Name) const { SendTrigger(Name, {}); } - - UFUNCTION(BlueprintCallable, Category = "Interaction") - void SendAudioMessage(USoundWave* SoundWave) const; UFUNCTION(BlueprintCallable, Category = "Interaction") void SendNarrationEvent(const FString& Content); @@ -253,6 +248,13 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone FString GivenName; +private: + UPROPERTY() + UInworldCharacter* InworldCharacter; + + UPROPERTY() + UInworldSession* InworldSession; + #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; #endif diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldComponentInterface.h b/InworldAI/Source/InworldAIIntegration/Public/InworldComponentInterface.h deleted file mode 100644 index eaa63a15..00000000 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldComponentInterface.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright 2022-2024 Theai, Inc. dba Inworld AI - * - * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement - * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license - */ - -#pragma once - -#include "CoreMinimal.h" -#include "InworldPackets.h" - -namespace Inworld -{ - class IPlayerComponent; - - class ICharacterComponent - { - public: - virtual void Possess(const FInworldAgentInfo& AgentInfo) = 0; - virtual void Unpossess() = 0; - virtual bool IsPossessing() = 0; - virtual const FString& GetAgentId() const = 0; - virtual const FString& GetGivenName() const = 0; - virtual const FString& GetBrainName() const = 0; - virtual void HandlePacket(TSharedPtr Packet) = 0; - virtual AActor* GetComponentOwner() const = 0; - virtual IPlayerComponent* GetTargetPlayer() = 0; - }; - - class IPlayerComponent - { - public: - virtual ICharacterComponent* GetTargetCharacter() = 0; - }; -} diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h new file mode 100644 index 00000000..8b154847 --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -0,0 +1,67 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Interface.h" +#include "UObject/NoExportTypes.h" +#include "InworldPlayer.generated.h" + +class UInworldSession; +class UInworldCharacter; + +UCLASS(BlueprintType) +class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, Category = "Inworld|Player") + TScriptInterface GetInworldPlayerOwner(); + + UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + const TArray& GetTargetInworldCharacters() const { return TargetInworldCharacters; } + + UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + void AddTargetInworldCharacter(UInworldCharacter* TargetCharacter) { TargetInworldCharacters.AddUnique(TargetCharacter); } + + UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + void RemoveTargetInworldCharacter(UInworldCharacter* TargetCharacter) { TargetInworldCharacters.Remove(TargetCharacter); } + + UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + void ClearAllTargetInworldCharacters() { TargetInworldCharacters.Empty(); } + + //UFUNCTION(BlueprintCallable, Category = "Message") + //void SendTextMessageToTargets(const FString& Message); + +private: + UPROPERTY() + TArray TargetInworldCharacters; +}; + +UINTERFACE(MinimalAPI, BlueprintType) +class UInworldPlayerOwnerInterface : public UInterface +{ + GENERATED_BODY() +}; + +class INWORLDAIINTEGRATION_API IInworldPlayerOwnerInterface +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") + UInworldSession* GetInworldSession() const; + + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") + UInworldPlayer* GetInworldPlayer() const; + +public: + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") + FTransform GetInworldPlayerTransform() const; +}; \ No newline at end of file diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h index e62c0b60..19f15faa 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h @@ -14,9 +14,7 @@ #include "InworldPlayerAudioCaptureComponent.generated.h" -class UInworldApiSubsystem; -class UInworldPlayerComponent; -class UInworldCharacterComponent; +class UInworldPlayer; class USoundWave; class UAudioCaptureComponent; @@ -72,9 +70,6 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct private: void EvaluateVoiceCapture(); - UFUNCTION() - void OnInworldConnectionStateChanged(EInworldConnectionState ConnectionState); - public: UFUNCTION(BlueprintCallable, Category = "Volume", meta=(DeprecatedFunction, DeprecationMessage="SetVolumeMultiplier is deprecated, use SetMuted instead.")) void SetVolumeMultiplier(float InVolumeMultiplier) { bMuted = InVolumeMultiplier == 0.f; } @@ -114,8 +109,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct TAtomic bCapturingVoice = false; - TWeakObjectPtr InworldSubsystem; - TWeakObjectPtr PlayerComponent; + TWeakObjectPtr InworldPlayer; TSharedPtr InputAudioCapture; TSharedPtr OutputAudioCapture; @@ -129,9 +123,6 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct FAudioBuffer InputBuffer; FAudioBuffer OutputBuffer; - void OnPlayerTargetSet(UInworldCharacterComponent* Target); - void OnPlayerTargetClear(UInworldCharacterComponent* Target); - FDelegateHandle PlayerTargetSetHandle; FDelegateHandle PlayerTargetClearHandle; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index dc41b5dc..14e8cd4a 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -9,6 +9,7 @@ #include "CoreMinimal.h" #include "InworldCharacterComponent.h" +#include "InworldPlayer.h" #include "InworldPlayerComponent.generated.h" @@ -27,33 +28,39 @@ struct FInworldPlayerTargetCharacter }; UCLASS(ClassGroup = (Inworld), meta = (BlueprintSpawnableComponent)) -class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, public Inworld::IPlayerComponent +class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, public IInworldPlayerOwnerInterface { GENERATED_BODY() public: + UInworldPlayerComponent(); + + // IInworldPlayerInterface + UInworldPlayer* GetInworldPlayer_Implementation() const { return InworldPlayer; } + UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } + FTransform GetInworldPlayerTransform() const { return GetOwner()->GetTransform(); } + // IInworldPlayerInterface + DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerTargetChange, UInworldCharacterComponent*); FOnInworldPlayerTargetChange OnTargetSet; FOnInworldPlayerTargetChange OnTargetClear; + virtual void InitializeComponent() override; + virtual void UninitializeComponent() override; + virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; UFUNCTION(BlueprintCallable, Category = "Interaction", meta = (Displayname = "GetTargetCharacter")) - UInworldCharacterComponent* GetTargetInworldCharacter() { return static_cast(GetTargetCharacter()); } + UInworldCharacterComponent* GetTargetInworldCharacter(); UFUNCTION(BlueprintCallable, Category = "Interaction", meta = (Displayname = "GetTargetCharacters")) TArray GetTargetInworldCharacters(); - UFUNCTION(BlueprintCallable, Category = "Interaction") - TArray GetTargetAgentIds(); - UFUNCTION(BlueprintCallable, Category = "Interaction", meta = (DeprecatedFunction, DeprecationMessage = "Will be removed in next release.")) void ContinueMultiAgentConversation(); - virtual Inworld::ICharacterComponent* GetTargetCharacter() override; - UFUNCTION(BlueprintCallable, Category = "Interaction", meta = (Displayname = "SetTargetCharacter")) void SetTargetInworldCharacter(UInworldCharacterComponent* Character); @@ -64,14 +71,11 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, void ClearAllTargetInworldCharacters(); UFUNCTION(BlueprintCallable, Category = "Interaction") - bool IsInteracting() { return Targets.Num() != 0; } + bool IsInteracting() { return InworldPlayer->GetTargetInworldCharacters().Num() > 0; } UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Interaction") void SendTextMessageToTarget(const FString& Message); - UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Interaction") - void SendTextMessage(const FString& Message, const FString& AgentId); - UFUNCTION(BlueprintCallable, Category = "Interaction", meta = (AutoCreateRefTerm = "Params")) void SendTriggerToTarget(const FString& Name, const TMap& Params); [[deprecated("UInworldPlayerComponent::SendCustomEventToTarget is deprecated, please use UInworldPlayerComponent::SendTriggerToTarget")]] @@ -84,22 +88,17 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, void StopAudioSessionWithTarget(); UFUNCTION(BlueprintCallable, Category = "Interaction") - void SendAudioMessageToTarget(USoundWave* SoundWave); - void SendAudioDataMessageToTarget(const TArray& Data); - void SendAudioDataMessageWithAECToTarget(const TArray& InputData, const TArray& OutputData); + void SendAudioMessageToTarget(const TArray& InputData, const TArray& OutputData); private: - - UFUNCTION() - void OnRep_Targets(const TArray& OldTrgets); - UPROPERTY(EditAnywhere, Category = "UI") FString UiName = "Player"; - TWeakObjectPtr InworldSubsystem; + UPROPERTY() + UInworldPlayer* InworldPlayer; - UPROPERTY(ReplicatedUsing = OnRep_Targets) - TArray Targets; + UPROPERTY() + UInworldSession* InworldSession; #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h index 63530fa4..914eac24 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h @@ -14,8 +14,8 @@ #include "InworldPlayerTargetingComponent.generated.h" class UInworldApiSubsystem; -class UInworldPlayerComponent; -class UInworldCharacterComponent; +class UInworldPlayer; +class UInworldCharacter; UCLASS(ClassGroup = (Inworld), meta = (BlueprintSpawnableComponent)) class INWORLDAIINTEGRATION_API UInworldPlayerTargetingComponent : public UActorComponent @@ -41,8 +41,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerTargetingComponent : public UActorC bool bMultipleTargets = false; private: - TArray TargetCharacters; + TArray TargetCharacters; - TWeakObjectPtr InworldSubsystem; - TWeakObjectPtr PlayerComponent; + UInworldPlayer* InworldPlayer; }; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h new file mode 100644 index 00000000..fd4b2f1e --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -0,0 +1,167 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "InworldClient.h" +#include "InworldTypes.h" +#include "InworldPackets.h" +#include "InworldSession.generated.h" + +class UInworldPlayer; +class UInworldCharacter; +class UInworldClient; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldCharactersInitialized, bool, bCharactersInitialized); +DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInworldCharactersInitializedCallback, bool, bCharactersInitialized); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldCharactersInitializedNative, bool /*bCharactersInitialized*/); + +UCLASS(BlueprintType) +class INWORLDAIINTEGRATION_API UInworldSession : public UObject +{ + GENERATED_BODY() + +public: + UInworldSession(); + virtual ~UInworldSession(); + + UFUNCTION(BlueprintCallable, Category = "Inworld|Register") + void RegisterCharacter(UInworldCharacter* Character); + UFUNCTION(BlueprintCallable, Category = "Inworld|Register") + void UnregisterCharacter(UInworldCharacter* Character); + + UFUNCTION(BlueprintPure, Category = "Inworld|Register") + const TArray& GetRegisteredCharacters() const { return RegisteredCharacters; } + + UFUNCTION(BlueprintCallable, Category = "Inworld|Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) + void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save = FInworldSave(), const FInworldSessionToken& SessionToken = FInworldSessionToken(), const FInworldCapabilitySet& CapabilitySet = FInworldCapabilitySet()); + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void StopSession(); + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void PauseSession() { InworldClient->PauseSession(); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void ResumeSession() { InworldClient->ResumeSession(); } + + UFUNCTION(BlueprintPure, Category = "Inworld|Session") + FString GetSessionId() const { return InworldClient->GetSessionId(); } + + UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + void SaveSession(FOnInworldSessionSavedCallback Callback) { InworldClient->SaveSession(Callback); } + + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void LoadCharacter(UInworldCharacter* Character) { LoadCharacters({ Character }); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void LoadCharacters(const TArray& Characters); + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void UnloadCharacter(UInworldCharacter* Character) { UnloadCharacters({ Character }); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + void UnloadCharacters(const TArray& Characters); + + UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + void LoadSavedState(const FInworldSave& Save) { InworldClient->LoadSavedState(Save); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + void LoadCapabilities(const FInworldCapabilitySet& CapabilitySet) { InworldClient->LoadCapabilities(CapabilitySet); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { InworldClient->LoadPlayerProfile(PlayerProfile); } + + UFUNCTION(BlueprintCallable, Category = "Message|Text") + FInworldWrappedPacket SendTextMessage(UInworldCharacter* Character, const FString& Message) { return BroadcastTextMessage({Character}, Message); } + UFUNCTION(BlueprintCallable, Category = "Message|Text") + FInworldWrappedPacket BroadcastTextMessage(const TArray& Characters, const FString& Message); + + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void SendSoundMessage(UInworldCharacter* Character, const TArray& InputData, const TArray& OutputData) { BroadcastSoundMessage({ Character }, InputData, OutputData); } + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void BroadcastSoundMessage(const TArray& Characters, const TArray& InputData, const TArray& OutputData); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void SendAudioSessionStart(UInworldCharacter* Character) { BroadcastAudioSessionStart({ Character }); } + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void BroadcastAudioSessionStart(const TArray& Characters); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void SendAudioSessionStop(UInworldCharacter* Character) { BroadcastAudioSessionStop({ Character }); } + UFUNCTION(BlueprintCallable, Category = "Message|Audio") + void BroadcastAudioSessionStop(const TArray& Characters); + + UFUNCTION(BlueprintCallable, Category = "Message|Narration") + void SendNarrationEvent(UInworldCharacter* Character, const FString& Content); + + UFUNCTION(BlueprintCallable, Category = "Message|Trigger") + void SendTrigger(UInworldCharacter* Character, const FString& Name, const TMap& Params) { BroadcastTrigger({ Character }, Name, Params); } + UFUNCTION(BlueprintCallable, Category = "Message|Trigger") + void BroadcastTrigger(const TArray& Characters, const FString& Name, const TMap& Params); + + UFUNCTION(BlueprintCallable, Category = "Message|Mutation") + void SendChangeSceneEvent(const FString& SceneName); + + UFUNCTION(BlueprintCallable, Category = "Message|Mutation") + void CancelResponse(UInworldCharacter* Character, const FString& InteractionId, const TArray& UtteranceIds); + + UPROPERTY(BlueprintAssignable, Category = "Packet") + FOnInworldPacketReceived OnPacketReceivedDelegate; + FOnInworldPacketReceivedNative& OnPacketReceived() { return OnPacketReceivedDelegateNative; } + + UFUNCTION(BlueprintPure, Category = "Connection") + EInworldConnectionState GetConnectionState() const { return InworldClient->GetConnectionState(); } + UFUNCTION(BlueprintPure, Category = "Connection") + void GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const { InworldClient->GetConnectionError(OutErrorMessage, OutErrorCode); } + + UPROPERTY(BlueprintAssignable, Category = "Connection") + FOnInworldConnectionStateChanged OnConnectionStateChangedDelegate; + FOnInworldConnectionStateChangedNative& OnConnectionStateChanged() { return OnConnectionStateChangedDelegateNative; } + + UPROPERTY(BlueprintAssignable, Category = "Connection") + FOnInworldCharactersInitialized OnCharactersInitializedDelegate; + FOnInworldCharactersInitializedNative& OnCharactersInitialized() { return OnCharactersInitializedDelegateNative; } + + UPROPERTY(BlueprintAssignable, Category = "Connection") + FOnInworldPerceivedLatency OnPerceivedLatencyDelegate; + FOnInworldPerceivedLatencyNative& OnPerceivedLatency() { return OnPerceivedLatencyDelegateNative; } + +private: + void PossessAgents(const TArray& AgentInfos); + void UnpossessAgents(); + +private: + TArray RegisteredCharacters; + TMap BrainNameToCharacter; + TMap AgentIdToCharacter; + TMap BrainNameToAgentInfo; + + bool bCharactersInitialized; + + UPROPERTY() + UInworldClient* InworldClient; + + FDelegateHandle OnClientPacketReceivedHandle; + FDelegateHandle OnClientConnectionStateChangedHandle; + FDelegateHandle OnClientPerceivedLatencyHandle; + + FOnInworldPacketReceivedNative OnPacketReceivedDelegateNative; + FOnInworldConnectionStateChangedNative OnConnectionStateChangedDelegateNative; + FOnInworldCharactersInitializedNative OnCharactersInitializedDelegateNative; + FOnInworldPerceivedLatencyNative OnPerceivedLatencyDelegateNative; + + // Temp: Hack until deprecated functions are removed + friend class UInworldApiSubsystem; +}; + +UINTERFACE(MinimalAPI, BlueprintType) +class UInworldSessionOwnerInterface : public UInterface +{ + GENERATED_BODY() +}; + +class INWORLDAIINTEGRATION_API IInworldSessionOwnerInterface +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") + UInworldSession* GetInworldSession() const; +}; diff --git a/InworldAI/Source/InworldAINDK/Private/InworldAINDK.cpp b/InworldAI/Source/InworldAINDK/Private/InworldAINDKModule.cpp similarity index 98% rename from InworldAI/Source/InworldAINDK/Private/InworldAINDK.cpp rename to InworldAI/Source/InworldAINDK/Private/InworldAINDKModule.cpp index d2fb410b..8fc2bfb1 100644 --- a/InworldAI/Source/InworldAINDK/Private/InworldAINDK.cpp +++ b/InworldAI/Source/InworldAINDK/Private/InworldAINDKModule.cpp @@ -5,7 +5,7 @@ * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license */ -#include "InworldAINDK.h" +#include "InworldAINDKModule.h" #include "Modules/ModuleManager.h" #include "Interfaces/IPluginManager.h" #include "HAL/PlatformProcess.h" diff --git a/InworldAI/Source/InworldAINDK/Public/InworldAINDK.h b/InworldAI/Source/InworldAINDK/Public/InworldAINDKModule.h similarity index 69% rename from InworldAI/Source/InworldAINDK/Public/InworldAINDK.h rename to InworldAI/Source/InworldAINDK/Public/InworldAINDKModule.h index d70cb038..ec1dbfd0 100644 --- a/InworldAI/Source/InworldAINDK/Public/InworldAINDK.h +++ b/InworldAI/Source/InworldAINDK/Public/InworldAINDKModule.h @@ -20,4 +20,15 @@ class FInworldAINDKModule : public IModuleInterface private: void* ndkLibraryHandle; void* webrtcLibraryHandle; + +public: + static inline FInworldAINDKModule& Get() + { + return FModuleManager::LoadModuleChecked("InworldAINDK"); + } + + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("InworldAINDK"); + } }; From 0dcc68118ca578c891205db73dca8c4465289f15 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 24 Apr 2024 14:34:17 -0400 Subject: [PATCH 02/45] character events and targeting --- .../InworldAIClient/Public/InworldPackets.h | 22 +-- .../Private/InworldApi.cpp | 56 +------- .../Private/InworldCharacter.cpp | 46 ++++++- .../Private/InworldCharacterComponent.cpp | 125 ++++++++---------- .../InworldCharacterPlaybackTrigger.cpp | 3 +- .../InworldGameplayDebuggerCategory.cpp | 4 +- .../Private/InworldPlayerComponent.cpp | 22 +-- .../InworldPlayerTargetingComponent.cpp | 10 +- .../Private/InworldSession.cpp | 67 ++++++++-- .../InworldAIIntegration/Public/InworldApi.h | 10 +- .../Public/InworldCharacter.h | 39 +++++- .../Public/InworldCharacterComponent.h | 60 ++++----- .../Public/InworldPlayer.h | 13 +- .../Public/InworldPlayerComponent.h | 6 +- .../Public/InworldSession.h | 68 +++++++++- 15 files changed, 329 insertions(+), 222 deletions(-) diff --git a/InworldAI/Source/InworldAIClient/Public/InworldPackets.h b/InworldAI/Source/InworldAIClient/Public/InworldPackets.h index d6a6122b..724001df 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldPackets.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldPackets.h @@ -183,7 +183,7 @@ struct INWORLDAICLIENT_API FInworldWrappedPacket }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldPacket { GENERATED_BODY() @@ -206,7 +206,7 @@ struct INWORLDAICLIENT_API FInworldPacket virtual void AppendDebugString(FString& Str) const PURE_VIRTUAL(FInworldPacket::AppendDebugString); }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldTextEvent : public FInworldPacket { GENERATED_BODY() @@ -225,7 +225,7 @@ struct INWORLDAICLIENT_API FInworldTextEvent : public FInworldPacket virtual void AppendDebugString(FString& Str) const override; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldDataEvent : public FInworldPacket { GENERATED_BODY() @@ -243,7 +243,7 @@ struct INWORLDAICLIENT_API FInworldDataEvent : public FInworldPacket virtual void AppendDebugString(FString& Str) const; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldVisemeInfo { GENERATED_BODY() @@ -256,7 +256,7 @@ struct INWORLDAICLIENT_API FInworldVisemeInfo float Timestamp = 0.f; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldAudioDataEvent : public FInworldDataEvent { GENERATED_BODY() @@ -277,7 +277,7 @@ struct INWORLDAICLIENT_API FInworldAudioDataEvent : public FInworldDataEvent virtual void AppendDebugString(FString& Str) const; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldSilenceEvent : public FInworldPacket { GENERATED_BODY() @@ -294,7 +294,7 @@ struct INWORLDAICLIENT_API FInworldSilenceEvent : public FInworldPacket virtual void AppendDebugString(FString& Str) const; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldControlEvent : public FInworldPacket { GENERATED_BODY() @@ -311,7 +311,7 @@ struct INWORLDAICLIENT_API FInworldControlEvent : public FInworldPacket virtual void AppendDebugString(FString& Str) const; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldEmotionEvent : public FInworldPacket { GENERATED_BODY() @@ -330,7 +330,7 @@ struct INWORLDAICLIENT_API FInworldEmotionEvent : public FInworldPacket virtual void AppendDebugString(FString& Str) const; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldCustomEvent : public FInworldPacket { GENERATED_BODY() @@ -350,7 +350,7 @@ struct INWORLDAICLIENT_API FInworldCustomEvent : public FInworldPacket virtual void AppendDebugString(FString& Str) const; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldLoadCharactersEvent : public FInworldPacket { GENERATED_BODY() @@ -366,7 +366,7 @@ struct INWORLDAICLIENT_API FInworldLoadCharactersEvent : public FInworldPacket virtual void AppendDebugString(FString& Str) const; }; -USTRUCT() +USTRUCT(BlueprintType) struct INWORLDAICLIENT_API FInworldChangeSceneEvent : public FInworldLoadCharactersEvent { GENERATED_BODY() diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 0d4ed858..8de6d8d1 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -120,7 +120,7 @@ void UInworldApiSubsystem::LoadCharacters(const TArray& Names) TArray Characters; for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) { - if (Names.Contains(Character->GetBrainName())) + if (Names.Contains(Character->GetAgentInfo().BrainName)) { Characters.Add(Character); } @@ -133,7 +133,7 @@ void UInworldApiSubsystem::UnloadCharacters(const TArray& Names) TArray Characters; for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) { - if (Names.Contains(Character->GetBrainName())) + if (Names.Contains(Character->GetAgentInfo().BrainName)) { Characters.Add(Character); } @@ -315,55 +315,6 @@ void UInworldApiSubsystem::OnWorldBeginPlay(UWorld& InWorld) } #endif -/* -void UInworldApiSubsystem::DispatchPacket(TSharedPtr InworldPacket) -{ - auto* SourceComponentPtr = CharacterComponentByAgentId.Find(InworldPacket->Routing.Source.Name); - if (SourceComponentPtr) - { - (*SourceComponentPtr)->HandlePacket(InworldPacket); - } - - if (InworldPacket->Routing.Source.Type == EInworldActorType::PLAYER) - { - auto ProcessTarget = [this, InworldPacket](const FInworldActor& TargetActor) - { - auto* TargetComponentPtr = CharacterComponentByAgentId.Find(TargetActor.Name); - if (TargetComponentPtr) - { - (*TargetComponentPtr)->HandlePacket(InworldPacket); - } - }; - - ProcessTarget(InworldPacket->Routing.Target); - - for (const auto& Target : InworldPacket->Routing.Targets) - { - if (Target.Name != InworldPacket->Routing.Target.Name) - { - ProcessTarget(Target); - } - } - } - - if (ensure(InworldPacket)) - { - InworldPacket->Accept(*this); - } -} - -void UInworldApiSubsystem::Visit(const FInworldChangeSceneEvent& Event) -{ - UnpossessAgents(); - PossessAgents(Event.AgentInfos); -} - -void UInworldApiSubsystem::Visit(const FInworldLoadCharactersEvent& Event) -{ - PossessAgents(Event.AgentInfos); -} -*/ - void UInworldApiSubsystem::ReplicateAudioEventFromServer(FInworldAudioDataEvent& Packet) { if (AudioRepl) @@ -374,6 +325,5 @@ void UInworldApiSubsystem::ReplicateAudioEventFromServer(FInworldAudioDataEvent& void UInworldApiSubsystem::HandleAudioEventOnClient(TSharedPtr Packet) { - //TODO: FIX - //DispatchPacket(Packet); + Packet->Accept(*InworldSession->PacketVisitor); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index a96592f6..d1467736 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -40,10 +40,52 @@ void UInworldCharacter::SetBrainName(const FString& BrainName) void UInworldCharacter::Possess(const FInworldAgentInfo& InAgentInfo) { - AgentInfo = InAgentInfo; + if (InAgentInfo.AgentId.IsEmpty()) + { + Unpossess(); + return; + } + if (AgentInfo.AgentId != InAgentInfo.AgentId) + { + Unpossess(); + AgentInfo = InAgentInfo; + OnPossessedDelegateNative.Broadcast(true); + OnPossessedDelegate.Broadcast(true); + } } void UInworldCharacter::Unpossess() { - AgentInfo = {}; + if (IsPossessed()) + { + AgentInfo = {}; + OnPossessedDelegateNative.Broadcast(false); + OnPossessedDelegate.Broadcast(false); + } +} + +void UInworldCharacter::SetEngagedPlayer(UInworldPlayer* Player) +{ + if (Player == nullptr) + { + ClearEngagedPlayer(); + return; + } + if (Player != EngagedPlayer) + { + ClearEngagedPlayer(); + EngagedPlayer = Player; + OnEngagedDelegateNative.Broadcast(true); + OnEngagedDelegate.Broadcast(true); + } +} + +void UInworldCharacter::ClearEngagedPlayer() +{ + if (IsEngagedWithPlayer()) + { + EngagedPlayer = nullptr; + OnEngagedDelegateNative.Broadcast(false); + OnEngagedDelegate.Broadcast(false); + } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 58a21bdc..f95402a4 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -29,6 +29,19 @@ void UInworldCharacterComponent::InitializeComponent() Super::InitializeComponent(); InworldCharacter = NewObject(this, "InworldCharacter"); + InworldCharacter->OnPossessed().AddLambda( + [this](bool bPossessed) -> void + { + AgentInfo = InworldCharacter->GetAgentInfo(); + } + ); + InworldCharacter->OnEngaged().AddLambda( + [this](bool bEngaged) -> void + { + //TODO: FIX + // set player id and whatnot + } + ); #if WITH_EDITOR if (GetWorld() == nullptr || !GetWorld()->IsPlayInEditor()) @@ -77,6 +90,12 @@ void UInworldCharacterComponent::BeginPlay() SetIsReplicated(true); InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); + InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); + InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); + InworldSession->OnInworldSilenceEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldSilenceEvent); + InworldSession->OnInworldControlEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldControlEvent); + InworldSession->OnInworldEmotionEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldEmotionEvent); + InworldSession->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); if (GetNetMode() != NM_Client) { @@ -142,7 +161,7 @@ void UInworldCharacterComponent::GetLifetimeReplicatedProps(TArray Packet) -{ - if (ensure(Packet)) - { - Packet->Accept(*this); - } -} - -bool UInworldCharacterComponent::StartPlayerInteraction(UInworldPlayerComponent* Player) -{ - if (TargetPlayer != nullptr) - { - return false; - } - - TargetPlayer = Player; - OnPlayerInteractionStateChanged.Broadcast(true); - return true; -} - -bool UInworldCharacterComponent::StopPlayerInteraction(UInworldPlayerComponent* Player) -{ - if (TargetPlayer != Player) - { - return false; - } - - TargetPlayer = nullptr; - OnPlayerInteractionStateChanged.Broadcast(false); - return true; -} - -bool UInworldCharacterComponent::IsInteractingWithPlayer() const -{ - return TargetPlayer != nullptr; -} - void UInworldCharacterComponent::CancelCurrentInteraction() { TSharedPtr CurrentMessage = GetCurrentMessage(); @@ -382,33 +364,9 @@ void UInworldCharacterComponent::OnRep_TargetPlayer(UInworldPlayerComponent* Old OnPlayerInteractionStateChanged.Broadcast(TargetPlayer != nullptr); } -void UInworldCharacterComponent::OnRep_AgentId(FString OldAgentId) +void UInworldCharacterComponent::OnRep_AgentInfo(FInworldAgentInfo OldAgentId) { - if (AgentId == OldAgentId) - { - return; - } - - // BeginPlay can be called later, don't use cached ptr - auto* InworldApi = GetWorld()->GetSubsystem(); - if (!ensure(InworldApi)) - { - return; - } - - const bool bWasRegistered = !OldAgentId.IsEmpty(); - const bool bIsRegistered = !AgentId.IsEmpty(); - if (bIsRegistered && !bWasRegistered) - { - OnPossessed.Broadcast(); - } - if (!bIsRegistered && bWasRegistered) - { - OnUnpossessed.Broadcast(); - } - - //TODO: FIX - //InworldApi->UpdateCharacterComponentRegistrationOnClient(this, AgentId, OldAgentId); + InworldCharacter->Possess(AgentInfo); } void UInworldCharacterComponent::Multicast_VisitSilence_Implementation(const FInworldSilenceEvent& Event) @@ -484,13 +442,22 @@ void UInworldCharacterComponent::Multicast_VisitEmotion_Implementation(const FIn } } -void UInworldCharacterComponent::Visit(const FInworldTextEvent& Event) +void UInworldCharacterComponent::OnInworldTextEvent(const FInworldTextEvent& Event) { + if (Event.Routing.Source.Name != GetAgentId()) + { + return; + } Multicast_VisitText(Event); } -void UInworldCharacterComponent::Visit(const FInworldAudioDataEvent& Event) +void UInworldCharacterComponent::OnInworldAudioEvent(const FInworldAudioDataEvent& Event) { + if (Event.Routing.Source.Name != GetAgentId()) + { + return; + } + if (GetNetMode() == NM_Standalone || GetNetMode() == NM_Client) { VisitAudioOnClient(Event); @@ -514,27 +481,43 @@ void UInworldCharacterComponent::Visit(const FInworldAudioDataEvent& Event) } } -void UInworldCharacterComponent::Visit(const FInworldSilenceEvent& Event) +void UInworldCharacterComponent::OnInworldSilenceEvent(const FInworldSilenceEvent& Event) { + if (Event.Routing.Source.Name != GetAgentId()) + { + return; + } Multicast_VisitSilence(Event); } -void UInworldCharacterComponent::Visit(const FInworldControlEvent& Event) +void UInworldCharacterComponent::OnInworldControlEvent(const FInworldControlEvent& Event) { + if (Event.Routing.Source.Name != GetAgentId()) + { + return; + } Multicast_VisitControl(Event); } -void UInworldCharacterComponent::Visit(const FInworldEmotionEvent& Event) +void UInworldCharacterComponent::OnInworldEmotionEvent(const FInworldEmotionEvent& Event) { + if (Event.Routing.Source.Name != GetAgentId()) + { + return; + } Multicast_VisitEmotion(Event); } -void UInworldCharacterComponent::Visit(const FInworldCustomEvent& Event) +void UInworldCharacterComponent::OnInworldCustomEvent(const FInworldCustomEvent& Event) { + if (Event.Routing.Source.Name != GetAgentId()) + { + return; + } Multicast_VisitCustom(Event); } -void UInworldCharacterComponent::Visit(const FInworldRelationEvent& Event) +void UInworldCharacterComponent::OnInworldRelationEvent(const FInworldRelationEvent& Event) { Multicast_VisitRelation(Event); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp index 3f2773fa..b91f05df 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterPlaybackTrigger.cpp @@ -23,8 +23,7 @@ void UInworldCharacterPlaybackTrigger::OnCharacterInteractionEnd_Implementation( { for (auto& Trigger : PendingTriggers[Message.InteractionId]) { - //TODO: FIX - //OwnerActor->GetWorld()->GetSubsystem()->NotifyCustomTrigger(Trigger.Name); + OwnerActor->GetWorld()->GetSubsystem()->NotifyCustomTrigger(Trigger.Name); } } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp index 5301d87f..37c1b9ac 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp @@ -51,8 +51,8 @@ void FInworldGameplayDebuggerCategory::CollectData(APlayerController* OwnerPC, A //TODO: FIX //Data.OverheadLocation = Actor->GetActorLocation() + FVector(0, 0, Actor->GetSimpleCollisionHalfHeight()); //Data.bIsInteracting = Comp->IsInteractingWithPlayer(); - Data.GivenName = Character->GetGivenName(); - Data.AgentId = Character->GetAgentId(); + Data.GivenName = Character->GetAgentInfo().GivenName; + Data.AgentId = Character->GetAgentInfo().AgentId; //Data.CurrentMessage = Comp->GetCurrentMessage() ? Comp->GetCurrentMessage()->ToDebugString() : TEXT(""); //Data.MessageQueueEntries = Comp->MessageQueue->PendingMessageEntries.Num(); //Data.EmotionalBehavior = static_cast(Comp->GetEmotionalBehavior()); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index bcf9ba40..b080d553 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -68,7 +68,7 @@ UInworldCharacterComponent* UInworldPlayerComponent::GetTargetInworldCharacter() TArray UInworldPlayerComponent::GetTargetInworldCharacters() { TArray InworldCharacterComponents; - for (UInworldCharacter* Character : InworldPlayer->GetTargetInworldCharacters()) + for (UInworldCharacter* Character : InworldPlayer->GetTargetCharacters()) { UInworldCharacterComponent* InworldCharacterComponent = Cast(Character->GetInworldCharacterOwner().GetObject()); if (InworldCharacterComponent) @@ -81,51 +81,51 @@ TArray UInworldPlayerComponent::GetTargetInworldCha void UInworldPlayerComponent::ContinueMultiAgentConversation() { - if (InworldPlayer->GetTargetInworldCharacters().Num() > 1) + if (InworldPlayer->GetTargetCharacters().Num() > 1) { - InworldSession->BroadcastTrigger(InworldPlayer->GetTargetInworldCharacters(), "inworld.conversation.next_turn", {}); + InworldSession->BroadcastTrigger(InworldPlayer->GetTargetCharacters(), "inworld.conversation.next_turn", {}); } } void UInworldPlayerComponent::SetTargetInworldCharacter(UInworldCharacterComponent* Character) { - InworldPlayer->AddTargetInworldCharacter(Character->GetInworldCharacter()); + InworldPlayer->AddTargetCharacter(IInworldCharacterOwnerInterface::Execute_GetInworldCharacter(Character)); } void UInworldPlayerComponent::ClearTargetInworldCharacter(UInworldCharacterComponent* Character) { - InworldPlayer->RemoveTargetInworldCharacter(Character->GetInworldCharacter()); + InworldPlayer->RemoveTargetCharacter(IInworldCharacterOwnerInterface::Execute_GetInworldCharacter(Character)); } void UInworldPlayerComponent::ClearAllTargetInworldCharacters() { - InworldPlayer->ClearAllTargetInworldCharacters(); + InworldPlayer->ClearAllTargetCharacters(); } void UInworldPlayerComponent::SendTextMessageToTarget_Implementation(const FString& Message) { if (!Message.IsEmpty()) { - InworldSession->BroadcastTextMessage(InworldPlayer->GetTargetInworldCharacters(), Message); + InworldSession->BroadcastTextMessage(InworldPlayer->GetTargetCharacters(), Message); } } void UInworldPlayerComponent::SendTriggerToTarget(const FString& Name, const TMap& Params) { - InworldSession->BroadcastTrigger(InworldPlayer->GetTargetInworldCharacters(), Name, Params); + InworldSession->BroadcastTrigger(InworldPlayer->GetTargetCharacters(), Name, Params); } void UInworldPlayerComponent::StartAudioSessionWithTarget() { - InworldSession->BroadcastAudioSessionStart(InworldPlayer->GetTargetInworldCharacters()); + InworldSession->BroadcastAudioSessionStart(InworldPlayer->GetTargetCharacters()); } void UInworldPlayerComponent::StopAudioSessionWithTarget() { - InworldSession->BroadcastAudioSessionStop(InworldPlayer->GetTargetInworldCharacters()); + InworldSession->BroadcastAudioSessionStop(InworldPlayer->GetTargetCharacters()); } void UInworldPlayerComponent::SendAudioMessageToTarget(const TArray& InputData, const TArray& OutputData) { - InworldSession->BroadcastSoundMessage(InworldPlayer->GetTargetInworldCharacters(), InputData, OutputData); + InworldSession->BroadcastSoundMessage(InworldPlayer->GetTargetCharacters(), InputData, OutputData); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 3eb799f1..7fd43362 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -52,7 +52,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() // clear all targets if just switched from multiple targeting if (!bMultipleTargets && TargetCharacters.Num() > 1) { - InworldPlayer->ClearAllTargetInworldCharacters(); + InworldPlayer->ClearAllTargetCharacters(); TargetCharacters.Empty(); } @@ -66,7 +66,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() const float DistSq = FVector::DistSquared(Location, CharacterLocation); if (DistSq > MinDistSq) { - InworldPlayer->RemoveTargetInworldCharacter(Character); + InworldPlayer->RemoveTargetCharacter(Character); TargetCharacters.RemoveAt(i); i--; } @@ -101,7 +101,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() } TargetCharacters.Add(Character); - InworldPlayer->AddTargetInworldCharacter(Character); + InworldPlayer->AddTargetCharacter(Character); continue; } @@ -137,14 +137,14 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() { if (CurrentTarget) { - InworldPlayer->RemoveTargetInworldCharacter(CurrentTarget); + InworldPlayer->RemoveTargetCharacter(CurrentTarget); TargetCharacters.Empty(); } if (BestTarget) { TargetCharacters.Add(BestTarget); - InworldPlayer->AddTargetInworldCharacter(BestTarget); + InworldPlayer->AddTargetCharacter(BestTarget); } } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 64cb3a04..2e1a4883 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -12,12 +12,12 @@ UInworldSession::UInworldSession() : InworldClient(NewObject(this, TEXT("InworldClient"))) + , PacketVisitor(MakeShared(this)) { OnClientPacketReceivedHandle = InworldClient->OnPacketReceived().AddLambda( [this](const FInworldWrappedPacket& WrappedPacket) -> void { - OnPacketReceivedDelegateNative.Broadcast(WrappedPacket); - OnPacketReceivedDelegate.Broadcast(WrappedPacket); + WrappedPacket.Packet->Accept(*PacketVisitor); } ); OnClientConnectionStateChangedHandle = InworldClient->OnConnectionStateChanged().AddLambda( @@ -46,7 +46,7 @@ UInworldSession::~UInworldSession() void UInworldSession::RegisterCharacter(UInworldCharacter* Character) { - const FString& BrainName = Character->GetBrainName(); + const FString& BrainName = Character->GetAgentInfo().BrainName; if (!ensureMsgf(!BrainNameToCharacter.Contains(BrainName), TEXT("UInworldSession::RegisterInworldCharacter: Character already registered for Brain: %s!"), *BrainName)) { return; @@ -72,13 +72,13 @@ void UInworldSession::RegisterCharacter(UInworldCharacter* Character) void UInworldSession::UnregisterCharacter(UInworldCharacter* Character) { - const FString& BrainName = Character->GetBrainName(); + const FString& BrainName = Character->GetAgentInfo().BrainName; if (!ensureMsgf(BrainNameToCharacter.Contains(BrainName) && BrainNameToCharacter[BrainName] == Character, TEXT("UInworldSession::UnregisterInworldCharacter: Component mismatch for Brain: %s!"), *BrainName)) { return; } - AgentIdToCharacter.Remove(Character->GetAgentId()); + AgentIdToCharacter.Remove(Character->GetAgentInfo().AgentId); BrainNameToCharacter.Remove(BrainName); RegisteredCharacters.Remove(Character); InworldClient->UnloadCharacter(BrainName); @@ -102,7 +102,7 @@ TArray CharactersToAgentIds(const TArray& InworldCh AgentIds.Reserve(InworldCharacters.Num()); for (const UInworldCharacter* Character : InworldCharacters) { - AgentIds.Add(Character->GetAgentId()); + AgentIds.Add(Character->GetAgentInfo().AgentId); } return AgentIds; } @@ -139,7 +139,7 @@ void UInworldSession::BroadcastAudioSessionStop(const TArray void UInworldSession::SendNarrationEvent(UInworldCharacter* Character, const FString& Content) { - InworldClient->SendNarrationEvent(Character->GetAgentId(), Content); + InworldClient->SendNarrationEvent(Character->GetAgentInfo().AgentId, Content); } void UInworldSession::BroadcastTrigger(const TArray& Characters, const FString& Name, const TMap& Params) @@ -155,7 +155,7 @@ void UInworldSession::SendChangeSceneEvent(const FString& SceneName) void UInworldSession::CancelResponse(UInworldCharacter* Character, const FString& InteractionId, const TArray& UtteranceIds) { - InworldClient->CancelResponse(Character->GetAgentId(), InteractionId, UtteranceIds); + InworldClient->CancelResponse(Character->GetAgentInfo().AgentId, InteractionId, UtteranceIds); } void UInworldSession::PossessAgents(const TArray& AgentInfos) @@ -167,7 +167,7 @@ void UInworldSession::PossessAgents(const TArray& AgentInfos) if (BrainNameToCharacter.Contains(BrainName)) { UInworldCharacter* Character = BrainNameToCharacter[BrainName]; - if (!Character->GetAgentId().IsEmpty()) + if (Character->GetAgentInfo().AgentId.IsEmpty()) { AgentIdToCharacter.Add(AgentInfo.AgentId, Character); Character->Possess(AgentInfo); @@ -182,7 +182,7 @@ void UInworldSession::PossessAgents(const TArray& AgentInfos) TArray BrainNames; for (UInworldCharacter* Character : RegisteredCharacters) { - const FString& BrainName = Character->GetBrainName(); + const FString& BrainName = Character->GetAgentInfo().BrainName; if (!BrainNameToAgentInfo.Contains(BrainName)) { BrainNames.Add(BrainName); @@ -217,3 +217,50 @@ void UInworldSession::UnpossessAgents() OnCharactersInitializedDelegateNative.Broadcast(bCharactersInitialized); OnCharactersInitializedDelegate.Broadcast(bCharactersInitialized); } + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldTextEvent& Event) +{ + Session->OnInworldTextEventDelegateNative.Broadcast(Event); + Session->OnInworldTextEventDelegate.Broadcast(Event); +} + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldAudioDataEvent& Event) +{ + Session->OnInworldAudioEventDelegateNative.Broadcast(Event); + Session->OnInworldAudioEventDelegate.Broadcast(Event); +} + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldSilenceEvent& Event) +{ + Session->OnInworldSilenceEventDelegateNative.Broadcast(Event); + Session->OnInworldSilenceEventDelegate.Broadcast(Event); +} + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldControlEvent& Event) +{ + Session->OnInworldControlEventDelegateNative.Broadcast(Event); + Session->OnInworldControlEventDelegate.Broadcast(Event); +} + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldEmotionEvent& Event) +{ + Session->OnInworldEmotionEventDelegateNative.Broadcast(Event); + Session->OnInworldEmotionEventDelegate.Broadcast(Event); +} + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldCustomEvent& Event) +{ + Session->OnInworldCustomEventDelegateNative.Broadcast(Event); + Session->OnInworldCustomEventDelegate.Broadcast(Event); +} + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldLoadCharactersEvent& Event) +{ + Session->UnpossessAgents(); + Session->PossessAgents(Event.AgentInfos); +} + +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldChangeSceneEvent& Event) +{ + Session->PossessAgents(Event.AgentInfos); +} diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index 0dcb358c..01a65a6f 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -27,7 +27,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCharactersInitialized, bool, bCha DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCustomTrigger, FString, Name); UCLASS(BlueprintType, Config = InworldAI) -class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, public InworldPacketVisitor, public IInworldSessionOwnerInterface +class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, public IInworldSessionOwnerInterface { GENERATED_BODY() @@ -189,6 +189,11 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu /** Cancel agents response in case agent has been interrupted by player */ UFUNCTION(BlueprintCallable, Category = "Messages") void CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds); + /** + * Call on Inworld::FCustomEvent coming to agent + * custom events meant to be triggered on interaction end (see InworldCharacterComponent) + */ + void NotifyCustomTrigger(const FString& Name) { OnCustomTrigger.Broadcast(Name); } /** * Call this in multiplayer on BeginPlay both on server and client @@ -214,6 +219,9 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "EventDispatchers", meta = (DeprecatedProperty, DeprecationMessage = "Use InworldSession->OnCharactersInitialized.")) FOnCharactersInitialized OnCharactersInitialized; + UPROPERTY(BlueprintAssignable, BlueprintCallable, Category = "EventDispatchers", meta = (DeprecatedProperty, DeprecationMessage = "Use InworldCharacter->OnTrigger.")) + FCustomTrigger OnCustomTrigger; + private: UPROPERTY(EditAnywhere, config, Category = "Connection") float RetryConnectionIntervalTime = 0.25f; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index 6bf6471d..da0b1492 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -12,6 +12,11 @@ #include "InworldTypes.h" #include "InworldCharacter.generated.h" +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerPossessed, bool, bPossessed); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerPossessedNative, bool /*bPossessed*/); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerEngaged, bool, bEngaged); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerEngagedNative, bool /*bEngaged*/); UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject @@ -22,20 +27,44 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject UFUNCTION(BlueprintCallable, Category = "Inworld|Player") TScriptInterface GetInworldCharacterOwner(); + UFUNCTION(BlueprintCallable, Category = "Inworld|Player") void SetBrainName(const FString& BrainName); + UFUNCTION(BlueprintPure, Category = "Inworld|Player") + bool IsPossessed() const { return !AgentInfo.AgentId.IsEmpty(); } + UFUNCTION(BlueprintCallable, Category = "Inworld|Player") void Possess(const FInworldAgentInfo& InAgentInfo); + UFUNCTION(BlueprintCallable, Category = "Inworld|Player") void Unpossess(); UFUNCTION(BlueprintPure, Category = "Inworld|Agent") - const FString& GetBrainName() const { return AgentInfo.BrainName; } - UFUNCTION(BlueprintPure, Category = "Inworld|Agent") - const FString& GetAgentId() const { return AgentInfo.AgentId; } - UFUNCTION(BlueprintPure, Category = "Inworld|Agent") - const FString& GetGivenName() const { return AgentInfo.GivenName; } + const FInworldAgentInfo& GetAgentInfo() const { return AgentInfo; } + + UPROPERTY(BlueprintAssignable, Category = "Possession") + FOnInworldPlayerPossessed OnPossessedDelegate; + FOnInworldPlayerPossessedNative& OnPossessed() { return OnPossessedDelegateNative; } + + UFUNCTION(BlueprintPure, Category = "Engagement") + bool IsEngagedWithPlayer() const { return EngagedPlayer != nullptr; } + UFUNCTION(BlueprintCallable, Category = "Engagement") + void SetEngagedPlayer(UInworldPlayer* Player); + UFUNCTION(BlueprintCallable, Category = "Engagement") + void ClearEngagedPlayer(); + + UFUNCTION(BlueprintPure, Category="Engagement") + UInworldPlayer* GetEngagedPlayer() const { return EngagedPlayer; } + + UPROPERTY(BlueprintAssignable, Category = "Engagement") + FOnInworldPlayerEngaged OnEngagedDelegate; + FOnInworldPlayerEngagedNative& OnEngaged() { return OnEngagedDelegateNative; } private: FInworldAgentInfo AgentInfo; + FOnInworldPlayerPossessedNative OnPossessedDelegateNative; + + UPROPERTY() + UInworldPlayer* EngagedPlayer; + FOnInworldPlayerEngagedNative OnEngagedDelegateNative; }; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index ad15b900..d2c55272 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -28,7 +28,7 @@ class UInworldPlayerComponent; class FInternetAddr; UCLASS(ClassGroup = (Inworld), meta = (BlueprintSpawnableComponent)) -class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorComponent, public InworldPacketVisitor, public ICharacterMessageVisitor, public IInworldCharacterOwnerInterface +class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorComponent, public IInworldCharacterOwnerInterface, public ICharacterMessageVisitor { GENERATED_BODY() @@ -44,9 +44,11 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone virtual void InitializeComponent() override; virtual void UninitializeComponent() override; - DECLARE_MULTICAST_DELEGATE(FOnInworldCharacterPossessed); - FOnInworldCharacterPossessed OnPossessed; - FOnInworldCharacterPossessed OnUnpossessed; + virtual void BeginPlay() override; + virtual void EndPlay(EEndPlayReason::Type Reason); + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction); + + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FInworldCharacterPlayerInteractionStateChanged, bool, bInteracting); UPROPERTY(BlueprintAssignable, Category = "EventDispatchers|Interaction") @@ -80,23 +82,17 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UPROPERTY(BlueprintAssignable, Category = "EventDispatchers|InteractionEnd") FOnInworldCharacterInteractionEnd OnInteractionEnd; - virtual void BeginPlay() override; - virtual void EndPlay(EEndPlayReason::Type Reason); - virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction); - - virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; - UFUNCTION(BlueprintCallable, Category = "Inworld") void SetBrainName(const FString& Name); UFUNCTION(BlueprintCallable, Category = "Inworld") - const FString& GetBrainName() const { return InworldCharacter->GetBrainName(); } + const FString& GetBrainName() const { return InworldCharacter->GetAgentInfo().BrainName; } UFUNCTION(BlueprintCallable, Category = "Inworld") - const FString& GetAgentId() const { return InworldCharacter->GetAgentId(); } + const FString& GetAgentId() const { return InworldCharacter->GetAgentInfo().AgentId; } UFUNCTION(BlueprintCallable, Category = "Inworld") - const FString& GetGivenName() const { return InworldCharacter->GetGivenName(); } + const FString& GetGivenName() const { return InworldCharacter->GetAgentInfo().GivenName; } UFUNCTION(BlueprintCallable, Category = "Inworld") const FString& GetUiName() const { return UiName; } @@ -106,13 +102,8 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UFUNCTION(BlueprintCallable, Category = "Inworld", meta = (DeterminesOutputType = "Class")) UInworldCharacterPlayback* GetPlayback(TSubclassOf Class) const; - void HandlePacket(TSharedPtr Packet); - - bool StartPlayerInteraction(UInworldPlayerComponent* Player); - bool StopPlayerInteraction(UInworldPlayerComponent* Player); - UFUNCTION(BlueprintCallable, Category = "Interactions") - bool IsInteractingWithPlayer() const; + bool IsInteractingWithPlayer() const { return InworldCharacter->IsEngagedWithPlayer(); } UFUNCTION(BlueprintCallable, Category = "Emotions") EInworldCharacterEmotionalBehavior GetEmotionalBehavior() const { return EmotionalBehavior; } @@ -182,14 +173,20 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone FString UiName = "Character"; private: - - virtual void Visit(const FInworldTextEvent& Event) override; - virtual void Visit(const FInworldAudioDataEvent& Event) override; - virtual void Visit(const FInworldSilenceEvent& Event) override; - virtual void Visit(const FInworldControlEvent& Event) override; - virtual void Visit(const FInworldEmotionEvent& Event) override; - virtual void Visit(const FInworldCustomEvent& Event) override; - virtual void Visit(const FInworldRelationEvent& Event) override; + UFUNCTION() + void OnInworldTextEvent(const FInworldTextEvent& Event); + UFUNCTION() + void OnInworldAudioEvent(const FInworldAudioDataEvent& Event); + UFUNCTION() + void OnInworldSilenceEvent(const FInworldSilenceEvent& Event); + UFUNCTION() + void OnInworldControlEvent(const FInworldControlEvent& Event); + UFUNCTION() + void OnInworldEmotionEvent(const FInworldEmotionEvent& Event); + UFUNCTION() + void OnInworldCustomEvent(const FInworldCustomEvent& Event); + UFUNCTION() + void OnInworldRelationEvent(const FInworldRelationEvent& Event); UFUNCTION(NetMulticast, Reliable) void Multicast_VisitText(const FInworldTextEvent& Event); @@ -212,7 +209,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone void OnRep_TargetPlayer(UInworldPlayerComponent* OldPlayer); UFUNCTION() - void OnRep_AgentId(FString OldAgentId); + void OnRep_AgentInfo(FInworldAgentInfo AgentInfo); TQueue PendingRepAudioEvents; @@ -243,10 +240,9 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UPROPERTY(EditAnywhere, Category = "Inworld") FString BrainName; - UPROPERTY(ReplicatedUsing = OnRep_AgentId) - FString AgentId; - - FString GivenName; + // Replicated from server to client to update possession. + UPROPERTY(ReplicatedUsing = OnRep_AgentInfo) + FInworldAgentInfo AgentInfo; private: UPROPERTY() diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index 8b154847..5422aae0 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -25,23 +25,20 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject TScriptInterface GetInworldPlayerOwner(); UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") - const TArray& GetTargetInworldCharacters() const { return TargetInworldCharacters; } + const TArray& GetTargetCharacters() const { return TargetCharacters; } UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") - void AddTargetInworldCharacter(UInworldCharacter* TargetCharacter) { TargetInworldCharacters.AddUnique(TargetCharacter); } + void AddTargetCharacter(UInworldCharacter* TargetCharacter) { TargetCharacters.AddUnique(TargetCharacter); } UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") - void RemoveTargetInworldCharacter(UInworldCharacter* TargetCharacter) { TargetInworldCharacters.Remove(TargetCharacter); } + void RemoveTargetCharacter(UInworldCharacter* TargetCharacter) { TargetCharacters.Remove(TargetCharacter); } UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") - void ClearAllTargetInworldCharacters() { TargetInworldCharacters.Empty(); } - - //UFUNCTION(BlueprintCallable, Category = "Message") - //void SendTextMessageToTargets(const FString& Message); + void ClearAllTargetCharacters() { TargetCharacters.Empty(); } private: UPROPERTY() - TArray TargetInworldCharacters; + TArray TargetCharacters; }; UINTERFACE(MinimalAPI, BlueprintType) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index 14e8cd4a..fa0a8f5d 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -41,10 +41,6 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, FTransform GetInworldPlayerTransform() const { return GetOwner()->GetTransform(); } // IInworldPlayerInterface - DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerTargetChange, UInworldCharacterComponent*); - FOnInworldPlayerTargetChange OnTargetSet; - FOnInworldPlayerTargetChange OnTargetClear; - virtual void InitializeComponent() override; virtual void UninitializeComponent() override; @@ -71,7 +67,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, void ClearAllTargetInworldCharacters(); UFUNCTION(BlueprintCallable, Category = "Interaction") - bool IsInteracting() { return InworldPlayer->GetTargetInworldCharacters().Num() > 0; } + bool IsInteracting() { return InworldPlayer->GetTargetCharacters().Num() > 0; } UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Interaction") void SendTextMessageToTarget(const FString& Message); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index fd4b2f1e..71e0cc08 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -18,6 +18,19 @@ class UInworldPlayer; class UInworldCharacter; class UInworldClient; +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldTextEvent, const FInworldTextEvent&, TextEvent); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldTextEventNative, const FInworldTextEvent& /*TextEvent*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldAudioEvent, const FInworldAudioDataEvent&, AudioEvent); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldAudioEventNative, const FInworldAudioDataEvent& /*AudioEvent*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldSilenceEvent, const FInworldSilenceEvent&, SilenceEvent); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldSilenceEventNative, const FInworldSilenceEvent& /*SilenceEvent*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldControlEvent, const FInworldControlEvent&, ControlEvent); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldControlEventNative, const FInworldControlEvent& /*ControlEvent*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldEmotionEvent, const FInworldEmotionEvent&, EmotionEvent); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldEmotionEventNative, const FInworldEmotionEvent& /*EmotionEvent*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldCustomEvent, const FInworldCustomEvent&, CustomEvent); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldCustomEventNative, const FInworldCustomEvent& /*CustomEvent*/); + DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldCharactersInitialized, bool, bCharactersInitialized); DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInworldCharactersInitializedCallback, bool, bCharactersInitialized); DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldCharactersInitializedNative, bool /*bCharactersInitialized*/); @@ -102,9 +115,24 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject UFUNCTION(BlueprintCallable, Category = "Message|Mutation") void CancelResponse(UInworldCharacter* Character, const FString& InteractionId, const TArray& UtteranceIds); - UPROPERTY(BlueprintAssignable, Category = "Packet") - FOnInworldPacketReceived OnPacketReceivedDelegate; - FOnInworldPacketReceivedNative& OnPacketReceived() { return OnPacketReceivedDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldTextEvent OnInworldTextEventDelegate; + FOnInworldTextEventNative& OnInworldTextEvent() { return OnInworldTextEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldAudioEvent OnInworldAudioEventDelegate; + FOnInworldAudioEventNative& OnInworldAudioEvent() { return OnInworldAudioEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldSilenceEvent OnInworldSilenceEventDelegate; + FOnInworldSilenceEventNative& OnInworldSilenceEvent() { return OnInworldSilenceEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldControlEvent OnInworldControlEventDelegate; + FOnInworldControlEventNative& OnInworldControlEvent() { return OnInworldControlEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldEmotionEvent OnInworldEmotionEventDelegate; + FOnInworldEmotionEventNative& OnInworldEmotionEvent() { return OnInworldEmotionEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldCustomEvent OnInworldCustomEventDelegate; + FOnInworldCustomEventNative& OnInworldCustomEvent() { return OnInworldCustomEventDelegateNative; } UFUNCTION(BlueprintPure, Category = "Connection") EInworldConnectionState GetConnectionState() const { return InworldClient->GetConnectionState(); } @@ -142,11 +170,43 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject FDelegateHandle OnClientConnectionStateChangedHandle; FDelegateHandle OnClientPerceivedLatencyHandle; - FOnInworldPacketReceivedNative OnPacketReceivedDelegateNative; FOnInworldConnectionStateChangedNative OnConnectionStateChangedDelegateNative; FOnInworldCharactersInitializedNative OnCharactersInitializedDelegateNative; FOnInworldPerceivedLatencyNative OnPerceivedLatencyDelegateNative; + class FInworldSessionPacketVisitor : public TSharedFromThis, public InworldPacketVisitor + { + public: + FInworldSessionPacketVisitor() + : FInworldSessionPacketVisitor(nullptr) + {} + FInworldSessionPacketVisitor(class UInworldSession* InSession) + : Session(InSession) + {} + virtual ~FInworldSessionPacketVisitor() = default; + + virtual void Visit(const FInworldTextEvent& Event) override; + virtual void Visit(const FInworldAudioDataEvent& Event) override; + virtual void Visit(const FInworldSilenceEvent& Event) override; + virtual void Visit(const FInworldControlEvent& Event) override; + virtual void Visit(const FInworldEmotionEvent& Event) override; + virtual void Visit(const FInworldCustomEvent& Event) override; + virtual void Visit(const FInworldLoadCharactersEvent& Event) override; + virtual void Visit(const FInworldChangeSceneEvent& Event) override; + + private: + UInworldSession* Session; + }; + + TSharedRef PacketVisitor; + + FOnInworldTextEventNative OnInworldTextEventDelegateNative; + FOnInworldAudioEventNative OnInworldAudioEventDelegateNative; + FOnInworldSilenceEventNative OnInworldSilenceEventDelegateNative; + FOnInworldControlEventNative OnInworldControlEventDelegateNative; + FOnInworldEmotionEventNative OnInworldEmotionEventDelegateNative; + FOnInworldCustomEventNative OnInworldCustomEventDelegateNative; + // Temp: Hack until deprecated functions are removed friend class UInworldApiSubsystem; }; From f5ebe8707fe3359d357d1f4bfac01a946cab50c9 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 24 Apr 2024 17:08:21 -0400 Subject: [PATCH 03/45] targeting and audio --- .../Private/InworldCharacter.cpp | 24 +++--- .../Private/InworldCharacterComponent.cpp | 4 +- .../Private/InworldPlayer.cpp | 54 ++++++++++++- .../InworldPlayerAudioCaptureComponent.cpp | 76 +++++++++---------- .../Private/InworldPlayerComponent.cpp | 2 - .../InworldPlayerTargetingComponent.cpp | 13 ++-- .../Public/InworldCharacter.h | 30 ++++---- .../Public/InworldCharacterComponent.h | 2 +- .../Public/InworldPlayer.h | 29 ++++++- .../InworldPlayerAudioCaptureComponent.h | 12 ++- 10 files changed, 154 insertions(+), 92 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index d1467736..672f79ce 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -64,28 +64,28 @@ void UInworldCharacter::Unpossess() } } -void UInworldCharacter::SetEngagedPlayer(UInworldPlayer* Player) +void UInworldCharacter::SetTargetPlayer(UInworldPlayer* Player) { if (Player == nullptr) { - ClearEngagedPlayer(); + ClearTargetPlayer(); return; } - if (Player != EngagedPlayer) + if (Player != TargetPlayer) { - ClearEngagedPlayer(); - EngagedPlayer = Player; - OnEngagedDelegateNative.Broadcast(true); - OnEngagedDelegate.Broadcast(true); + ClearTargetPlayer(); + TargetPlayer = Player; + OnTargetPlayerChangedDelegateNative.Broadcast(); + OnTargetPlayerChangedDelegate.Broadcast(); } } -void UInworldCharacter::ClearEngagedPlayer() +void UInworldCharacter::ClearTargetPlayer() { - if (IsEngagedWithPlayer()) + if (TargetPlayer != nullptr) { - EngagedPlayer = nullptr; - OnEngagedDelegateNative.Broadcast(false); - OnEngagedDelegate.Broadcast(false); + TargetPlayer = nullptr; + OnTargetPlayerChangedDelegateNative.Broadcast(); + OnTargetPlayerChangedDelegate.Broadcast(); } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index f95402a4..c1102ca6 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -35,8 +35,8 @@ void UInworldCharacterComponent::InitializeComponent() AgentInfo = InworldCharacter->GetAgentInfo(); } ); - InworldCharacter->OnEngaged().AddLambda( - [this](bool bEngaged) -> void + InworldCharacter->OnTargetPlayerChanged().AddLambda( + [this]() -> void { //TODO: FIX // set player id and whatnot diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index cc7288a8..e3520685 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -7,6 +7,7 @@ #include "InworldPlayer.h" +#include "InworldCharacter.h" #include "InworldSession.h" TScriptInterface UInworldPlayer::GetInworldPlayerOwner() @@ -17,8 +18,53 @@ TScriptInterface UInworldPlayer::GetInworldPlayerO } return TScriptInterface(GetOuter()); } -/* -void UInworldPlayer::SendTextMessageToTargets(const FString& Message) + +void UInworldPlayer::AddTargetCharacter(UInworldCharacter* TargetCharacter) +{ + if (TargetCharacter->GetTargetPlayer() == nullptr) + { + TargetCharacter->SetTargetPlayer(this); + TargetCharacters.AddUnique(TargetCharacter); + OnTargetCharacterAddedDelegateNative.Broadcast(TargetCharacter); + OnTargetCharacterAddedDelegate.Broadcast(TargetCharacter); + + OnTargetCharactersChangedDelegateNative.Broadcast(); + OnTargetCharactersChangedDelegate.Broadcast(); + } +} + +void UInworldPlayer::RemoveTargetCharacter(UInworldCharacter* TargetCharacter) +{ + if (TargetCharacter->GetTargetPlayer() == this) + { + TargetCharacter->ClearTargetPlayer(); + TargetCharacters.RemoveSingle(TargetCharacter); + OnTargetCharacterRemovedDelegateNative.Broadcast(TargetCharacter); + OnTargetCharacterRemovedDelegate.Broadcast(TargetCharacter); + + OnTargetCharactersChangedDelegateNative.Broadcast(); + OnTargetCharactersChangedDelegate.Broadcast(); + } +} + +void UInworldPlayer::ClearAllTargetCharacters() { - GetInworldPlayerOwner()->GetInworldSession()->BroadcastTextMessage(GetTargetInworldCharacters(), Message); -}*/ \ No newline at end of file + TArray TargetCharactersCopy = TargetCharacters; + for (UInworldCharacter* TargetCharacter : TargetCharactersCopy) + { + bool bRemovedAny = false; + if (TargetCharacter->GetTargetPlayer() == this) + { + TargetCharacter->ClearTargetPlayer(); + TargetCharacters.RemoveSingle(TargetCharacter); + OnTargetCharacterRemovedDelegateNative.Broadcast(TargetCharacter); + OnTargetCharacterRemovedDelegate.Broadcast(TargetCharacter); + bRemovedAny = true; + } + if (bRemovedAny) + { + OnTargetCharactersChangedDelegateNative.Broadcast(); + OnTargetCharactersChangedDelegate.Broadcast(); + } + } +} diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index a6e4ba62..7ae898f0 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -10,6 +10,7 @@ #include "InworldPlayerAudioCaptureComponent.h" #include "InworldPlayerComponent.h" +#include "InworldCharacter.h" #include "AudioMixerDevice.h" #include "AudioMixerSubmix.h" #include "AudioResampler.h" @@ -164,6 +165,14 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() if (GetOwnerRole() == ROLE_Authority) { InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))); + InworldPlayer->OnTargetCharactersChanged().AddLambda( + [this]() -> void + { + PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); + EvaluateVoiceCapture(); + } + ); + PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); PrimaryComponentTick.SetTickFunctionEnable(false); } @@ -263,34 +272,40 @@ void UInworldPlayerAudioCaptureComponent::EvaluateVoiceCapture() { if (GetOwnerRole() == ROLE_Authority) { - const bool bIsMicHot = !bMuted; - const bool bIsWorldPlaying = !GetWorld()->IsPaused(); - const bool bHasTargetCharacter = PlayerAudioTarget.DesiredAgentIds.Num() != 0; const bool bHasPlayer = InworldPlayer != nullptr; UInworldSession* InworldSession = bHasPlayer ? IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()) : nullptr; - const EInworldConnectionState ConnectionState = InworldSession != nullptr ? InworldSession->GetConnectionState() : EInworldConnectionState::Idle; + if (InworldSession == nullptr) + { + return; + } + + const bool bIsMicHot = !bMuted; + const bool bIsWorldPlaying = !GetWorld()->IsPaused(); + const bool bHasTargetCharacter = PlayerAudioTargetState.DesiredCharacters.Num() != 0; + const EInworldConnectionState ConnectionState = InworldSession->GetConnectionState(); const bool bHasActiveInworldSession = ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting; - const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasTargetCharacter && bHasPlayer && bHasActiveInworldSession; + const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasTargetCharacter && bHasActiveInworldSession; - //TODO: FIX - if (bShouldCaptureVoice && bServerCapturingVoice && (PlayerAudioTarget.DesiredAgentIds != PlayerAudioTarget.ActiveAgentIds)) + if (bShouldCaptureVoice && bServerCapturingVoice && PlayerAudioTargetState.bDirty) { - //InworldSubsystem->StopAudioSessionMultiAgent(PlayerAudioTarget.ActiveAgentIds); - //InworldSubsystem->StartAudioSessionMultiAgent(PlayerAudioTarget.DesiredAgentIds, GetOwner()); - PlayerAudioTarget.ActiveAgentIds = PlayerAudioTarget.DesiredAgentIds; + InworldSession->BroadcastAudioSessionStop(PlayerAudioTargetState.ActiveCharacters); + InworldSession->BroadcastAudioSessionStart(PlayerAudioTargetState.DesiredCharacters); + PlayerAudioTargetState.ActiveCharacters = PlayerAudioTargetState.DesiredCharacters; + PlayerAudioTargetState.bDirty = false; } else if (bShouldCaptureVoice != bServerCapturingVoice) { if (bShouldCaptureVoice) { - //InworldSubsystem->StartAudioSessionMultiAgent(PlayerAudioTarget.DesiredAgentIds, GetOwner()); - PlayerAudioTarget.ActiveAgentIds = PlayerAudioTarget.DesiredAgentIds; + InworldSession->BroadcastAudioSessionStart(PlayerAudioTargetState.DesiredCharacters); + PlayerAudioTargetState.ActiveCharacters = PlayerAudioTargetState.DesiredCharacters; + PlayerAudioTargetState.bDirty = false; } else { - //InworldSubsystem->StopAudioSessionMultiAgent(PlayerAudioTarget.ActiveAgentIds); - PlayerAudioTarget.ActiveAgentIds.Empty(); + InworldSession->BroadcastAudioSessionStop(PlayerAudioTargetState.ActiveCharacters); + PlayerAudioTargetState.ActiveCharacters = {}; } bServerCapturingVoice = bShouldCaptureVoice; @@ -401,10 +416,16 @@ void UInworldPlayerAudioCaptureComponent::StopCapture() void UInworldPlayerAudioCaptureComponent::Server_ProcessVoiceCaptureChunk_Implementation(FPlayerVoiceCaptureInfoRep PlayerVoiceCaptureInfo) { - //TODO: FIX - if (PlayerAudioTarget.ActiveAgentIds.Num() != 0) + if (PlayerAudioTargetState.ActiveCharacters.Num() != 0) { - //InworldSubsystem->SendAudioMessage(PlayerAudioTarget.ActiveAgentIds, PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); + const bool bHasPlayer = InworldPlayer != nullptr; + UInworldSession* InworldSession = bHasPlayer ? IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()) : nullptr; + if (InworldSession == nullptr) + { + return; + } + + InworldSession->BroadcastSoundMessage(PlayerAudioTargetState.ActiveCharacters, PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); } } @@ -413,27 +434,6 @@ bool UInworldPlayerAudioCaptureComponent::IsLocallyControlled() const auto* Controller = Cast(GetOwner()->GetInstigatorController()); return Controller && Controller->IsLocalController(); } -/* -void UInworldPlayerAudioCaptureComponent::OnPlayerTargetSet(UInworldCharacterComponent* Target) -{ - if (PlayerAudioTarget.DesiredAgentIds.Contains(Target->GetAgentId())) - { - return; - } - PlayerAudioTarget.DesiredAgentIds.Add(Target->GetAgentId()); - EvaluateVoiceCapture(); -} - -void UInworldPlayerAudioCaptureComponent::OnPlayerTargetClear(UInworldCharacterComponent* Target) -{ - if (!PlayerAudioTarget.DesiredAgentIds.Contains(Target->GetAgentId())) - { - return; - } - PlayerAudioTarget.DesiredAgentIds.RemoveSingle(Target->GetAgentId()); - EvaluateVoiceCapture(); -} -*/ void UInworldPlayerAudioCaptureComponent::Rep_ServerCapturingVoice() { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index b080d553..657636a9 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -36,8 +36,6 @@ void UInworldPlayerComponent::BeginPlay() { Super::BeginPlay(); - InworldPlayer = NewObject(this); - InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); SetIsReplicated(true); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 7fd43362..8c8c707d 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -77,19 +77,18 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() float BestTargetDot = -1.f; for (UInworldCharacter* Character : Characters) { + UInworldPlayer* Player = Character->GetTargetPlayer(); + if (Player && Player != InworldPlayer) + { + continue; + } + const FVector CharacterLocation = Character->GetInworldCharacterOwner()->GetInworldCharacterTransform().GetLocation(); const float DistSq = FVector::DistSquared(Location, CharacterLocation); if (DistSq > MinDistSq) { continue; } - - //TODO: FIX - //const auto* CurrentTargetPlayer = Character->GetTargetPlayer(); - //if (CurrentTargetPlayer && CurrentTargetPlayer != Player) - //{ - // continue; - //} // if multiple targets enabled add all characters in range if (bMultipleTargets) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index da0b1492..a51968dc 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -12,11 +12,11 @@ #include "InworldTypes.h" #include "InworldCharacter.generated.h" -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerPossessed, bool, bPossessed); -DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerPossessedNative, bool /*bPossessed*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldCharacterPossessed, bool, bPossessed); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldCharacterPossessedNative, bool /*bPossessed*/); -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerEngaged, bool, bEngaged); -DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerEngagedNative, bool /*bEngaged*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInworldCharacterTargetPlayerChanged); +DECLARE_MULTICAST_DELEGATE(FOnInworldCharacterTargetPlayerChangedNative); UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject @@ -41,30 +41,28 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject const FInworldAgentInfo& GetAgentInfo() const { return AgentInfo; } UPROPERTY(BlueprintAssignable, Category = "Possession") - FOnInworldPlayerPossessed OnPossessedDelegate; - FOnInworldPlayerPossessedNative& OnPossessed() { return OnPossessedDelegateNative; } + FOnInworldCharacterPossessed OnPossessedDelegate; + FOnInworldCharacterPossessedNative& OnPossessed() { return OnPossessedDelegateNative; } - UFUNCTION(BlueprintPure, Category = "Engagement") - bool IsEngagedWithPlayer() const { return EngagedPlayer != nullptr; } UFUNCTION(BlueprintCallable, Category = "Engagement") - void SetEngagedPlayer(UInworldPlayer* Player); + void SetTargetPlayer(UInworldPlayer* Player); UFUNCTION(BlueprintCallable, Category = "Engagement") - void ClearEngagedPlayer(); + void ClearTargetPlayer(); UFUNCTION(BlueprintPure, Category="Engagement") - UInworldPlayer* GetEngagedPlayer() const { return EngagedPlayer; } + UInworldPlayer* GetTargetPlayer() const { return TargetPlayer; } UPROPERTY(BlueprintAssignable, Category = "Engagement") - FOnInworldPlayerEngaged OnEngagedDelegate; - FOnInworldPlayerEngagedNative& OnEngaged() { return OnEngagedDelegateNative; } + FOnInworldCharacterTargetPlayerChanged OnTargetPlayerChangedDelegate; + FOnInworldCharacterTargetPlayerChangedNative& OnTargetPlayerChanged() { return OnTargetPlayerChangedDelegateNative; } private: FInworldAgentInfo AgentInfo; - FOnInworldPlayerPossessedNative OnPossessedDelegateNative; + FOnInworldCharacterPossessedNative OnPossessedDelegateNative; UPROPERTY() - UInworldPlayer* EngagedPlayer; - FOnInworldPlayerEngagedNative OnEngagedDelegateNative; + UInworldPlayer* TargetPlayer; + FOnInworldCharacterTargetPlayerChangedNative OnTargetPlayerChangedDelegateNative; }; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index d2c55272..3ac826ba 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -103,7 +103,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UInworldCharacterPlayback* GetPlayback(TSubclassOf Class) const; UFUNCTION(BlueprintCallable, Category = "Interactions") - bool IsInteractingWithPlayer() const { return InworldCharacter->IsEngagedWithPlayer(); } + bool IsInteractingWithPlayer() const { return InworldCharacter->GetTargetPlayer() != nullptr; } UFUNCTION(BlueprintCallable, Category = "Emotions") EInworldCharacterEmotionalBehavior GetEmotionalBehavior() const { return EmotionalBehavior; } diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index 5422aae0..b29713d6 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -15,6 +15,13 @@ class UInworldSession; class UInworldCharacter; +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerTargetCharacterAdded, UInworldCharacter*, Character); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerTargetCharacterAddedNative, UInworldCharacter* /*Character*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerTargetCharacterRemoved, UInworldCharacter*, Character); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerTargetCharacterRemovedNative, UInworldCharacter* /*Character*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInworldPlayerTargetCharactersChanged); +DECLARE_MULTICAST_DELEGATE(FOnInworldPlayerTargetCharactersChangedNative); + UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject { @@ -28,17 +35,33 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject const TArray& GetTargetCharacters() const { return TargetCharacters; } UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") - void AddTargetCharacter(UInworldCharacter* TargetCharacter) { TargetCharacters.AddUnique(TargetCharacter); } + void AddTargetCharacter(UInworldCharacter* TargetCharacter); UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") - void RemoveTargetCharacter(UInworldCharacter* TargetCharacter) { TargetCharacters.Remove(TargetCharacter); } + void RemoveTargetCharacter(UInworldCharacter* TargetCharacter); UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") - void ClearAllTargetCharacters() { TargetCharacters.Empty(); } + void ClearAllTargetCharacters(); + + UPROPERTY(BlueprintAssignable, Category = "Engagement") + FOnInworldPlayerTargetCharacterAdded OnTargetCharacterAddedDelegate; + FOnInworldPlayerTargetCharacterAddedNative& OnTargetCharacterAdded() { return OnTargetCharacterAddedDelegateNative; } + + UPROPERTY(BlueprintAssignable, Category = "Engagement") + FOnInworldPlayerTargetCharacterRemoved OnTargetCharacterRemovedDelegate; + FOnInworldPlayerTargetCharacterRemovedNative& OnTargetCharacterRemoved() { return OnTargetCharacterRemovedDelegateNative; } + + UPROPERTY(BlueprintAssignable, Category = "Engagement") + FOnInworldPlayerTargetCharactersChanged OnTargetCharactersChangedDelegate; + FOnInworldPlayerTargetCharactersChangedNative& OnTargetCharactersChanged() { return OnTargetCharactersChangedDelegateNative; } private: UPROPERTY() TArray TargetCharacters; + + FOnInworldPlayerTargetCharacterAddedNative OnTargetCharacterAddedDelegateNative; + FOnInworldPlayerTargetCharacterRemovedNative OnTargetCharacterRemovedDelegateNative; + FOnInworldPlayerTargetCharactersChangedNative OnTargetCharactersChangedDelegateNative; }; UINTERFACE(MinimalAPI, BlueprintType) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h index 19f15faa..0d21f0a4 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h @@ -123,15 +123,13 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct FAudioBuffer InputBuffer; FAudioBuffer OutputBuffer; - FDelegateHandle PlayerTargetSetHandle; - FDelegateHandle PlayerTargetClearHandle; - - struct FPlayerAudioTarget + struct FPlayerAudioTargetState { - TArray ActiveAgentIds; - TArray DesiredAgentIds; + TArray ActiveCharacters; + TArray DesiredCharacters; + bool bDirty = false; - } PlayerAudioTarget; + } PlayerAudioTargetState; #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; From 25e755fe95a099730b8a52592bb6287783344fcb Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 24 Apr 2024 22:40:30 -0400 Subject: [PATCH 04/45] initial replication rework --- .../Private/InworldApi.cpp | 3 +- .../Private/InworldCharacter.cpp | 52 ++++++++++++++++++- .../Private/InworldCharacterComponent.cpp | 43 ++++++++++++--- .../Private/InworldPlayer.cpp | 39 ++++++++++++++ .../InworldPlayerAudioCaptureComponent.cpp | 3 +- .../Private/InworldPlayerComponent.cpp | 38 ++++++++++++-- .../Public/InworldCharacter.h | 13 ++++- .../Public/InworldCharacterComponent.h | 9 ++-- .../Public/InworldPlayer.h | 12 ++++- .../Public/InworldPlayerComponent.h | 3 +- 10 files changed, 190 insertions(+), 25 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 8de6d8d1..55895f07 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -283,11 +283,12 @@ void UInworldApiSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); + InworldSession = NewObject(this, TEXT("InworldSession")); + if (GetWorld()->GetNetMode() == NM_Client) { return; } - InworldSession = NewObject(this, TEXT("InworldSession")); InworldSession->OnCharactersInitialized().AddLambda( [this](bool bCharactersInitialized) -> void { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index 672f79ce..b0748f73 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -8,6 +8,47 @@ #include "InworldCharacter.h" #include "InworldSession.h" +#include "InworldPlayer.h" + +#include "Engine/BlueprintGeneratedClass.h" +#include "Engine/NetDriver.h" +#include "Engine/Engine.h" + +#include "Net/UnrealNetwork.h" + +void UInworldCharacter::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + if (UBlueprintGeneratedClass* BPCClass = Cast(GetClass())) + { + BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); + } + + DOREPLIFETIME(UInworldCharacter, AgentInfo); + DOREPLIFETIME(UInworldCharacter, TargetPlayer); +} + +int32 UInworldCharacter::GetFunctionCallspace(UFunction* Function, FFrame* Stack) +{ + if (HasAnyFlags(RF_ClassDefaultObject) || !IsSupportedForNetworking()) + { + return GEngine->GetGlobalFunctionCallspace(Function, this, Stack); + } + + return GetOuter()->GetFunctionCallspace(Function, Stack); +} + +bool UInworldCharacter::CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) +{ + AActor* Owner = GetTypedOuter(); + if (UNetDriver* NetDriver = Owner->GetNetDriver()) + { + NetDriver->ProcessRemoteFunction(Owner, Function, Parms, OutParms, Stack, this); + return true; + } + return false; +} TScriptInterface UInworldCharacter::GetInworldCharacterOwner() { @@ -47,10 +88,15 @@ void UInworldCharacter::Possess(const FInworldAgentInfo& InAgentInfo) } if (AgentInfo.AgentId != InAgentInfo.AgentId) { + UInworldPlayer* CachedTargetPlayer = TargetPlayer; Unpossess(); AgentInfo = InAgentInfo; OnPossessedDelegateNative.Broadcast(true); OnPossessedDelegate.Broadcast(true); + if(CachedTargetPlayer != nullptr) + { + CachedTargetPlayer->AddTargetCharacter(this); + } } } @@ -58,9 +104,13 @@ void UInworldCharacter::Unpossess() { if (IsPossessed()) { - AgentInfo = {}; + if (TargetPlayer != nullptr) + { + TargetPlayer->RemoveTargetCharacter(this); + } OnPossessedDelegateNative.Broadcast(false); OnPossessedDelegate.Broadcast(false); + AgentInfo = {}; } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index c1102ca6..b2ba88cb 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -22,13 +23,24 @@ UInworldCharacterComponent::UInworldCharacterComponent() { PrimaryComponentTick.bCanEverTick = true; bWantsInitializeComponent = true; + SetIsReplicatedByDefault(true); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + bReplicateUsingRegisteredSubObjectList = true; +#endif } void UInworldCharacterComponent::InitializeComponent() { Super::InitializeComponent(); - InworldCharacter = NewObject(this, "InworldCharacter"); + if (GetOwnerRole() == ROLE_Authority) + { + InworldCharacter = NewObject(this); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + AddReplicatedSubObject(InworldCharacter); +#endif + } + /* InworldCharacter->OnPossessed().AddLambda( [this](bool bPossessed) -> void { @@ -38,10 +50,9 @@ void UInworldCharacterComponent::InitializeComponent() InworldCharacter->OnTargetPlayerChanged().AddLambda( [this]() -> void { - //TODO: FIX - // set player id and whatnot + UInworldPlayer* TargetPlayer = InworldCharacter->GetTargetPlayer(); } - ); + );*/ #if WITH_EDITOR if (GetWorld() == nullptr || !GetWorld()->IsPlayInEditor()) @@ -87,8 +98,6 @@ void UInworldCharacterComponent::BeginPlay() { Super::BeginPlay(); - SetIsReplicated(true); - InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); @@ -160,8 +169,26 @@ void UInworldCharacterComponent::GetLifetimeReplicatedProps(TArray= 1 + return Super::ReplicateSubobjects(Channel, Bunch, RepFlags); +#else + bool WroteSomething = true; + + if (IsValid(InworldCharacter)) + { + WroteSomething |= Channel->ReplicateSubobject(InworldCharacter, *Bunch, *RepFlags); + } + + return WroteSomething; +#endif } void UInworldCharacterComponent::SetBrainName(const FString& Name) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index e3520685..cac7f92c 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -10,6 +10,45 @@ #include "InworldCharacter.h" #include "InworldSession.h" +#include "Engine/BlueprintGeneratedClass.h" +#include "Engine/NetDriver.h" +#include "Engine/Engine.h" + +#include "Net/UnrealNetwork.h" + +void UInworldPlayer::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + if (UBlueprintGeneratedClass* BPCClass = Cast(GetClass())) + { + BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); + } + + DOREPLIFETIME(UInworldPlayer, TargetCharacters); +} + +int32 UInworldPlayer::GetFunctionCallspace(UFunction* Function, FFrame* Stack) +{ + if (HasAnyFlags(RF_ClassDefaultObject) || !IsSupportedForNetworking()) + { + return GEngine->GetGlobalFunctionCallspace(Function, this, Stack); + } + + return GetOuter()->GetFunctionCallspace(Function, Stack); +} + +bool UInworldPlayer::CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) +{ + AActor* Owner = GetTypedOuter(); + if (UNetDriver* NetDriver = Owner->GetNetDriver()) + { + NetDriver->ProcessRemoteFunction(Owner, Function, Parms, OutParms, Stack, this); + return true; + } + return false; +} + TScriptInterface UInworldPlayer::GetInworldPlayerOwner() { if (!ensureMsgf(GetOuter()->Implements(), TEXT("UInworldPlayer outer must implement IInworldPlayerOwnerInterface!"))) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index 7ae898f0..56127723 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -154,14 +154,13 @@ UInworldPlayerAudioCaptureComponent::UInworldPlayerAudioCaptureComponent(const F { PrimaryComponentTick.bCanEverTick = true; PrimaryComponentTick.bTickEvenWhenPaused = true; + SetIsReplicatedByDefault(true); } void UInworldPlayerAudioCaptureComponent::BeginPlay() { Super::BeginPlay(); - SetIsReplicated(true); - if (GetOwnerRole() == ROLE_Authority) { InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index 657636a9..eb5d0d85 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -16,13 +16,26 @@ UInworldPlayerComponent::UInworldPlayerComponent() : Super() { bWantsInitializeComponent = true; + SetIsReplicatedByDefault(true); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + bReplicateUsingRegisteredSubObjectList = true; +#endif } void UInworldPlayerComponent::InitializeComponent() { Super::InitializeComponent(); - InworldPlayer = NewObject(this, "InworldPlayer"); + if (GetOwnerRole() == ROLE_Authority) + { + InworldPlayer = NewObject(this); + } + /*InworldPlayer->OnTargetCharacterAdded().AddLambda( + [this](UInworldCharacter* Character) -> void + { + //TargetCharacters.Add(Character->GetAgentInfo().AgentId); + } + );*/ } void UInworldPlayerComponent::UninitializeComponent() @@ -35,10 +48,7 @@ void UInworldPlayerComponent::UninitializeComponent() void UInworldPlayerComponent::BeginPlay() { Super::BeginPlay(); - InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); - - SetIsReplicated(true); } void UInworldPlayerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) @@ -51,6 +61,26 @@ void UInworldPlayerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) void UInworldPlayerComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + //DOREPLIFETIME(UInworldPlayerComponent, TargetCharacters); + DOREPLIFETIME(UInworldPlayerComponent, InworldPlayer); + //DOREPLIFETIME(UInworldPlayerComponent, InworldSession); +} + +bool UInworldPlayerComponent::ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) +{ +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + return Super::ReplicateSubobjects(Channel, Bunch, RepFlags); +#else + bool WroteSomething = true; + + if (IsValid(InworldPlayer)) + { + WroteSomething |= Channel->ReplicateSubobject(InworldPlayer, *Bunch, *RepFlags); + } + + return WroteSomething; +#endif } UInworldCharacterComponent* UInworldPlayerComponent::GetTargetInworldCharacter() diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index a51968dc..d63fd788 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -22,7 +22,15 @@ UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject { GENERATED_BODY() - +public: + //UObject + virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual bool IsSupportedForNetworking() const override { return true; } + virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override; + virtual bool CallRemoteFunction(UFunction* Function, void* Parms, struct FOutParmRec* OutParms, FFrame* Stack) override; + //~UObject + public: UFUNCTION(BlueprintCallable, Category = "Inworld|Player") TScriptInterface GetInworldCharacterOwner(); @@ -57,10 +65,11 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject FOnInworldCharacterTargetPlayerChangedNative& OnTargetPlayerChanged() { return OnTargetPlayerChangedDelegateNative; } private: + UPROPERTY(Replicated) FInworldAgentInfo AgentInfo; FOnInworldCharacterPossessedNative OnPossessedDelegateNative; - UPROPERTY() + UPROPERTY(Replicated) UInworldPlayer* TargetPlayer; FOnInworldCharacterTargetPlayerChangedNative OnTargetPlayerChangedDelegateNative; }; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index 3ac826ba..450b1800 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -39,7 +39,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UInworldCharacter* GetInworldCharacter_Implementation() const { return InworldCharacter; } UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } FTransform GetInworldPlayerTransform() const { return GetOwner()->GetTransform(); } - // IInworldCharacterOwnerInterface + // ~IInworldCharacterOwnerInterface virtual void InitializeComponent() override; virtual void UninitializeComponent() override; @@ -49,6 +49,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction); virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FInworldCharacterPlayerInteractionStateChanged, bool, bInteracting); UPROPERTY(BlueprintAssignable, Category = "EventDispatchers|Interaction") @@ -213,7 +214,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone TQueue PendingRepAudioEvents; - UPROPERTY(ReplicatedUsing = OnRep_TargetPlayer) + //UPROPERTY(ReplicatedUsing = OnRep_TargetPlayer) UInworldPlayerComponent* TargetPlayer; TWeakObjectPtr InworldSubsystem; @@ -241,11 +242,11 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone FString BrainName; // Replicated from server to client to update possession. - UPROPERTY(ReplicatedUsing = OnRep_AgentInfo) + //UPROPERTY(ReplicatedUsing = OnRep_AgentInfo) FInworldAgentInfo AgentInfo; private: - UPROPERTY() + UPROPERTY(Replicated) UInworldCharacter* InworldCharacter; UPROPERTY() diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index b29713d6..db5dd946 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -26,7 +26,15 @@ UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject { GENERATED_BODY() - +public: + //UObject + virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual bool IsSupportedForNetworking() const override { return true; } + virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override; + virtual bool CallRemoteFunction(UFunction* Function, void* Parms, struct FOutParmRec* OutParms, FFrame* Stack) override; + //~UObject + public: UFUNCTION(BlueprintCallable, Category = "Inworld|Player") TScriptInterface GetInworldPlayerOwner(); @@ -56,7 +64,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject FOnInworldPlayerTargetCharactersChangedNative& OnTargetCharactersChanged() { return OnTargetCharactersChangedDelegateNative; } private: - UPROPERTY() + UPROPERTY(Replicated) TArray TargetCharacters; FOnInworldPlayerTargetCharacterAddedNative OnTargetCharacterAddedDelegateNative; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index fa0a8f5d..c02e1eea 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -48,6 +48,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; UFUNCTION(BlueprintCallable, Category = "Interaction", meta = (Displayname = "GetTargetCharacter")) UInworldCharacterComponent* GetTargetInworldCharacter(); @@ -90,7 +91,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, UPROPERTY(EditAnywhere, Category = "UI") FString UiName = "Player"; - UPROPERTY() + UPROPERTY(Replicated) UInworldPlayer* InworldPlayer; UPROPERTY() From f11ab8bd283f007e280ee161274c98cef9dee0a5 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 24 Apr 2024 23:45:44 -0400 Subject: [PATCH 05/45] session replication --- .../Private/InworldApi.cpp | 27 +++++---- .../Private/InworldCharacterComponent.cpp | 15 +++-- .../Private/InworldPlayerComponent.cpp | 5 +- .../Private/InworldSession.cpp | 40 +++++++++++++ .../Private/InworldSessionActor.cpp | 60 +++++++++++++++++++ .../InworldAIIntegration/Public/InworldApi.h | 2 + .../Public/InworldSession.h | 15 ++++- .../Public/InworldSessionActor.h | 45 ++++++++++++++ 8 files changed, 186 insertions(+), 23 deletions(-) create mode 100644 InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp create mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 55895f07..32f88661 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -11,10 +11,12 @@ #include "InworldAIIntegrationModule.h" #include "InworldPackets.h" #include "InworldCharacter.h" +#include "InworldSessionActor.h" #include #include #include "TimerManager.h" #include "InworldAudioRepl.h" +#include "UObject/UObjectIterator.h" static TAutoConsoleVariable CVarLogAllPackets( TEXT("Inworld.Debug.LogAllPackets"), false, @@ -25,6 +27,18 @@ UInworldApiSubsystem::UInworldApiSubsystem() : Super() {} +void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) +{ + InworldSession = Session; + InworldSession->OnCharactersInitialized().AddLambda( + [this](bool bCharactersInitialized) -> void + { + OnCharactersInitialized.Broadcast(bCharactersInitialized); + } + ); + OnCharactersInitialized.Broadcast(InworldSession->IsCharactersInitialized()); +} + void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) { if (!ensure(GetWorld()->GetNetMode() < NM_Client)) @@ -282,19 +296,6 @@ bool UInworldApiSubsystem::DoesSupportWorldType(EWorldType::Type WorldType) cons void UInworldApiSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); - - InworldSession = NewObject(this, TEXT("InworldSession")); - - if (GetWorld()->GetNetMode() == NM_Client) - { - return; - } - InworldSession->OnCharactersInitialized().AddLambda( - [this](bool bCharactersInitialized) -> void - { - OnCharactersInitialized.Broadcast(bCharactersInitialized); - } - ); } void UInworldApiSubsystem::Deinitialize() diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index b2ba88cb..03ec7fc3 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -98,16 +98,15 @@ void UInworldCharacterComponent::BeginPlay() { Super::BeginPlay(); - InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); - InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); - InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); - InworldSession->OnInworldSilenceEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldSilenceEvent); - InworldSession->OnInworldControlEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldControlEvent); - InworldSession->OnInworldEmotionEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldEmotionEvent); - InworldSession->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); - if (GetNetMode() != NM_Client) { + InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); + InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); + InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); + InworldSession->OnInworldSilenceEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldSilenceEvent); + InworldSession->OnInworldControlEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldControlEvent); + InworldSession->OnInworldEmotionEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldEmotionEvent); + InworldSession->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); Register(); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index eb5d0d85..2f9c087d 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -48,7 +48,10 @@ void UInworldPlayerComponent::UninitializeComponent() void UInworldPlayerComponent::BeginPlay() { Super::BeginPlay(); - InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); + if (GetNetMode() != NM_Client) + { + InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); + } } void UInworldPlayerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 2e1a4883..05ba3221 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -10,6 +10,12 @@ #include "InworldCharacter.h" #include "InworldClient.h" +#include "Engine/BlueprintGeneratedClass.h" +#include "Engine/NetDriver.h" +#include "Engine/Engine.h" + +#include "Net/UnrealNetwork.h" + UInworldSession::UInworldSession() : InworldClient(NewObject(this, TEXT("InworldClient"))) , PacketVisitor(MakeShared(this)) @@ -44,6 +50,40 @@ UInworldSession::~UInworldSession() InworldClient = nullptr; } +void UInworldSession::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + if (UBlueprintGeneratedClass* BPCClass = Cast(GetClass())) + { + BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); + } + + DOREPLIFETIME(UInworldSession, RegisteredCharacters); + DOREPLIFETIME(UInworldSession, bCharactersInitialized); +} + +int32 UInworldSession::GetFunctionCallspace(UFunction* Function, FFrame* Stack) +{ + if (HasAnyFlags(RF_ClassDefaultObject) || !IsSupportedForNetworking()) + { + return GEngine->GetGlobalFunctionCallspace(Function, this, Stack); + } + + return GetOuter()->GetFunctionCallspace(Function, Stack); +} + +bool UInworldSession::CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) +{ + AActor* Owner = GetTypedOuter(); + if (UNetDriver* NetDriver = Owner->GetNetDriver()) + { + NetDriver->ProcessRemoteFunction(Owner, Function, Parms, OutParms, Stack, this); + return true; + } + return false; +} + void UInworldSession::RegisterCharacter(UInworldCharacter* Character) { const FString& BrainName = Character->GetAgentInfo().BrainName; diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp new file mode 100644 index 00000000..6498fd58 --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -0,0 +1,60 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "InworldSessionActor.h" +#include "InworldSession.h" +#include "InworldApi.h" +#include + +AInworldSessionActor::AInworldSessionActor() +{ + PrimaryActorTick.bCanEverTick = true; + SetReplicates(true); + bAlwaysRelevant = true; +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + bReplicateUsingRegisteredSubObjectList = true; +#endif +} + +void AInworldSessionActor::PreInitializeComponents() +{ + Super::PreInitializeComponents(); + + if (GetLocalRole() == ROLE_Authority) + { + InworldSession = NewObject(this); + OnRep_InworldSession(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + AddReplicatedSubObject(InworldCharacter); +#endif + } +} + +void AInworldSessionActor::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(AInworldSessionActor, InworldSession); +} + +bool AInworldSessionActor::ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) +{ +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + return Super::ReplicateSubobjects(Channel, Bunch, RepFlags); +#else + bool WroteSomething = true; + + if (IsValid(InworldSession)) + { + WroteSomething |= Channel->ReplicateSubobject(InworldSession, *Bunch, *RepFlags); + } + + return WroteSomething; +#endif +} + +void AInworldSessionActor::OnRep_InworldSession() +{ + GetWorld()->GetSubsystem()->SetInworldSession(InworldSession); +} + diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index 01a65a6f..2f9ec7dc 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -34,6 +34,8 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu public: UInworldApiSubsystem(); + void SetInworldSession(UInworldSession* Session); + // IInworldSessionOwnerInterface UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } // IInworldSessionOwnerInterface diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index 71e0cc08..060c68b6 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -39,7 +39,15 @@ UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldSession : public UObject { GENERATED_BODY() - +public: + //UObject + virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual bool IsSupportedForNetworking() const override { return true; } + virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override; + virtual bool CallRemoteFunction(UFunction* Function, void* Parms, struct FOutParmRec* OutParms, FFrame* Stack) override; + //~UObject + public: UInworldSession(); virtual ~UInworldSession(); @@ -147,6 +155,9 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject FOnInworldCharactersInitialized OnCharactersInitializedDelegate; FOnInworldCharactersInitializedNative& OnCharactersInitialized() { return OnCharactersInitializedDelegateNative; } + UFUNCTION(BlueprintPure, Category = "Connection") + bool IsCharactersInitialized() const { return bCharactersInitialized; } + UPROPERTY(BlueprintAssignable, Category = "Connection") FOnInworldPerceivedLatency OnPerceivedLatencyDelegate; FOnInworldPerceivedLatencyNative& OnPerceivedLatency() { return OnPerceivedLatencyDelegateNative; } @@ -156,11 +167,13 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject void UnpossessAgents(); private: + UPROPERTY(Replicated) TArray RegisteredCharacters; TMap BrainNameToCharacter; TMap AgentIdToCharacter; TMap BrainNameToAgentInfo; + UPROPERTY(Replicated) bool bCharactersInitialized; UPROPERTY() diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h new file mode 100644 index 00000000..55f7583c --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h @@ -0,0 +1,45 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Actor.h" +#include "InworldSessionActor.generated.h" + +class UInworldSession; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInworldSessionCreated); +DECLARE_MULTICAST_DELEGATE(FOnInworldSessionCreatedNative); + +UCLASS() +class INWORLDAIINTEGRATION_API AInworldSessionActor : public AActor, public IInworldSessionOwnerInterface +{ + GENERATED_BODY() + +public: + AInworldSessionActor(); + + // IInworldSessionOwnerInterface + UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } + // IInworldSessionOwnerInterface + + UPROPERTY(BlueprintAssignable, Category = "Session") + FOnInworldSessionCreated OnSessionCreatedDelegate; + FOnInworldSessionCreatedNative& OnSessionCreated() { return OnSessionCreatedDelegateNative; } + +private: + FOnInworldSessionCreatedNative OnSessionCreatedDelegateNative; + +protected: + virtual void PreInitializeComponents() override; + + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; + +private: + UFUNCTION() + void OnRep_InworldSession(); + + UPROPERTY(ReplicatedUsing=OnRep_InworldSession) + UInworldSession* InworldSession; +}; From 2bc274fc70acbcd151b9515244dd186227e6c4f4 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 10:44:55 -0400 Subject: [PATCH 06/45] fixup audio replication --- .../Private/InworldApi.cpp | 8 +- .../Private/InworldCharacter.cpp | 12 ++- .../Private/InworldCharacterComponent.cpp | 82 +++++++++---------- .../InworldPlayerAudioCaptureComponent.cpp | 4 +- .../Private/InworldPlayerComponent.cpp | 3 +- .../InworldPlayerTargetingComponent.cpp | 11 ++- .../Private/InworldSession.cpp | 47 +++++++---- .../Private/InworldSessionActor.cpp | 1 + .../Public/InworldCharacter.h | 9 +- .../Public/InworldCharacterComponent.h | 25 ++---- .../Public/InworldPlayerComponent.h | 2 +- .../Public/InworldSession.h | 39 +++++---- 12 files changed, 129 insertions(+), 114 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 32f88661..22ad9fa1 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -30,13 +30,13 @@ UInworldApiSubsystem::UInworldApiSubsystem() void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) { InworldSession = Session; - InworldSession->OnCharactersInitialized().AddLambda( - [this](bool bCharactersInitialized) -> void + InworldSession->OnLoaded().AddLambda( + [this](bool bLoaded) -> void { - OnCharactersInitialized.Broadcast(bCharactersInitialized); + OnCharactersInitialized.Broadcast(bLoaded); } ); - OnCharactersInitialized.Broadcast(InworldSession->IsCharactersInitialized()); + OnCharactersInitialized.Broadcast(InworldSession->IsLoaded()); } void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index b0748f73..ec324428 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -125,8 +125,7 @@ void UInworldCharacter::SetTargetPlayer(UInworldPlayer* Player) { ClearTargetPlayer(); TargetPlayer = Player; - OnTargetPlayerChangedDelegateNative.Broadcast(); - OnTargetPlayerChangedDelegate.Broadcast(); + OnRep_TargetPlayer(); } } @@ -135,7 +134,12 @@ void UInworldCharacter::ClearTargetPlayer() if (TargetPlayer != nullptr) { TargetPlayer = nullptr; - OnTargetPlayerChangedDelegateNative.Broadcast(); - OnTargetPlayerChangedDelegate.Broadcast(); + OnRep_TargetPlayer(); } } + +void UInworldCharacter::OnRep_TargetPlayer() +{ + OnTargetPlayerChangedDelegateNative.Broadcast(); + OnTargetPlayerChangedDelegate.Broadcast(); +} diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 03ec7fc3..fa1a4d66 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -36,23 +36,11 @@ void UInworldCharacterComponent::InitializeComponent() if (GetOwnerRole() == ROLE_Authority) { InworldCharacter = NewObject(this); + OnRep_InworldCharacter(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 AddReplicatedSubObject(InworldCharacter); #endif } - /* - InworldCharacter->OnPossessed().AddLambda( - [this](bool bPossessed) -> void - { - AgentInfo = InworldCharacter->GetAgentInfo(); - } - ); - InworldCharacter->OnTargetPlayerChanged().AddLambda( - [this]() -> void - { - UInworldPlayer* TargetPlayer = InworldCharacter->GetTargetPlayer(); - } - );*/ #if WITH_EDITOR if (GetWorld() == nullptr || !GetWorld()->IsPlayInEditor()) @@ -101,14 +89,10 @@ void UInworldCharacterComponent::BeginPlay() if (GetNetMode() != NM_Client) { InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); - InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); - InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); - InworldSession->OnInworldSilenceEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldSilenceEvent); - InworldSession->OnInworldControlEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldControlEvent); - InworldSession->OnInworldEmotionEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldEmotionEvent); - InworldSession->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); Register(); } + OnRep_InworldCharacter(); + OnRep_InworldSession(); for (auto* Pb : Playbacks) { @@ -124,16 +108,7 @@ void UInworldCharacterComponent::EndPlay(EEndPlayReason::Type Reason) Pb->ClearCharacterComponent(); } - if (GetNetMode() == NM_Client) - { - //TODO: FIX - //if (InworldSubsystem.IsValid()) - { - //FString NewAgentId = FString(); - //InworldSubsystem->UpdateCharacterComponentRegistrationOnClient(this, NewAgentId, AgentId); - } - } - else + if (GetNetMode() != NM_Client) { Unregister(); } @@ -168,10 +143,8 @@ void UInworldCharacterComponent::GetLifetimeReplicatedProps(TArrayGetTargetPlayer() == nullptr) { return FVector::ZeroVector; } - UCameraComponent* CameraComponent = Cast(TargetPlayer->GetOwner()->GetComponentByClass(UCameraComponent::StaticClass())); + AActor* TargetPlayerActor = InworldCharacter->GetTargetPlayer()->GetTypedOuter(); + UCameraComponent* CameraComponent = Cast(TargetPlayerActor->GetComponentByClass(UCameraComponent::StaticClass())); if (!CameraComponent) { return GetOwner()->GetActorLocation(); @@ -385,16 +359,6 @@ void UInworldCharacterComponent::VisitAudioOnClient(const FInworldAudioDataEvent }); } -void UInworldCharacterComponent::OnRep_TargetPlayer(UInworldPlayerComponent* OldTargetPlayer) -{ - OnPlayerInteractionStateChanged.Broadcast(TargetPlayer != nullptr); -} - -void UInworldCharacterComponent::OnRep_AgentInfo(FInworldAgentInfo OldAgentId) -{ - InworldCharacter->Possess(AgentInfo); -} - void UInworldCharacterComponent::Multicast_VisitSilence_Implementation(const FInworldSilenceEvent& Event) { if (GetNetMode() == NM_DedicatedServer) @@ -495,7 +459,8 @@ void UInworldCharacterComponent::OnInworldAudioEvent(const FInworldAudioDataEven VisitAudioOnClient(Event); } - if (ensure(InworldSubsystem.IsValid())) + UInworldApiSubsystem* InworldSubsystem = GetWorld()->GetSubsystem(); + if (ensure(InworldSubsystem)) { TArray RepEvents; FInworldAudioDataEvent::ConvertToReplicatableEvents(Event, RepEvents); @@ -577,3 +542,30 @@ void UInworldCharacterComponent::Handle(const FCharacterMessageInteractionEnd& M { OnInteractionEnd.Broadcast(Message); } + +void UInworldCharacterComponent::OnRep_InworldCharacter() +{ + if (InworldCharacter != nullptr) + { + InworldCharacter->OnTargetPlayerChanged().AddLambda( + [this]() -> void + { + OnPlayerInteractionStateChanged.Broadcast(InworldCharacter->GetTargetPlayer() != nullptr); + } + ); + OnPlayerInteractionStateChanged.Broadcast(InworldCharacter->GetTargetPlayer() != nullptr); + } +} + +void UInworldCharacterComponent::OnRep_InworldSession() +{ + if (InworldSession != nullptr) + { + InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); + InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); + InworldSession->OnInworldSilenceEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldSilenceEvent); + InworldSession->OnInworldControlEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldControlEvent); + InworldSession->OnInworldEmotionEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldEmotionEvent); + InworldSession->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); + } +} diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index 56127723..2d0feb12 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -168,6 +168,7 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() [this]() -> void { PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); + PlayerAudioTargetState.bDirty = true; EvaluateVoiceCapture(); } ); @@ -217,6 +218,7 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() } PrimaryComponentTick.SetTickFunctionEnable(true); + Rep_ServerCapturingVoice(); } } @@ -234,8 +236,6 @@ void UInworldPlayerAudioCaptureComponent::TickComponent(float DeltaTime, enum EL { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - EvaluateVoiceCapture(); - { FScopeLock InputScopedLock(&InputBuffer.CriticalSection); FScopeLock OutputScopedLock(&OutputBuffer.CriticalSection); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index 2f9c087d..834b4093 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -65,9 +65,8 @@ void UInworldPlayerComponent::GetLifetimeReplicatedProps(TArrayGetInworldCharacterOwner()->GetInworldCharacterTransform().GetLocation(); + AActor* OuterActor = Character->GetTypedOuter(); + const FVector CharacterLocation = OuterActor != nullptr ? OuterActor->GetActorLocation() : FVector::ZeroVector; const float DistSq = FVector::DistSquared(Location, CharacterLocation); if (DistSq > MinDistSq) { @@ -83,7 +84,13 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() continue; } - const FVector CharacterLocation = Character->GetInworldCharacterOwner()->GetInworldCharacterTransform().GetLocation(); + AActor* OuterActor = Character->GetTypedOuter(); + if (!OuterActor) + { + continue; + } + + const FVector CharacterLocation = OuterActor->GetActorLocation(); const float DistSq = FVector::DistSquared(Location, CharacterLocation); if (DistSq > MinDistSq) { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 05ba3221..a11cc7bb 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -17,9 +17,17 @@ #include "Net/UnrealNetwork.h" UInworldSession::UInworldSession() - : InworldClient(NewObject(this, TEXT("InworldClient"))) - , PacketVisitor(MakeShared(this)) + : PacketVisitor(MakeShared(this)) +{} + +UInworldSession::~UInworldSession() +{ + DestroyClient(); +} + +void UInworldSession::InitClient() { + InworldClient = NewObject(this); OnClientPacketReceivedHandle = InworldClient->OnPacketReceived().AddLambda( [this](const FInworldWrappedPacket& WrappedPacket) -> void { @@ -42,12 +50,15 @@ UInworldSession::UInworldSession() ); } -UInworldSession::~UInworldSession() +void UInworldSession::DestroyClient() { - InworldClient->OnPacketReceived().Remove(OnClientPacketReceivedHandle); - InworldClient->OnConnectionStateChanged().Remove(OnClientConnectionStateChangedHandle); - InworldClient->OnPerceivedLatency().Remove(OnClientPerceivedLatencyHandle); - InworldClient = nullptr; + if (InworldClient) + { + InworldClient->OnPacketReceived().Remove(OnClientPacketReceivedHandle); + InworldClient->OnConnectionStateChanged().Remove(OnClientConnectionStateChangedHandle); + InworldClient->OnPerceivedLatency().Remove(OnClientPerceivedLatencyHandle); + InworldClient = nullptr; + } } void UInworldSession::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const @@ -59,8 +70,8 @@ void UInworldSession::GetLifetimeReplicatedProps(TArray& OutL BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); } + DOREPLIFETIME(UInworldSession, bIsLoaded); DOREPLIFETIME(UInworldSession, RegisteredCharacters); - DOREPLIFETIME(UInworldSession, bCharactersInitialized); } int32 UInworldSession::GetFunctionCallspace(UFunction* Function, FFrame* Stack) @@ -95,7 +106,7 @@ void UInworldSession::RegisterCharacter(UInworldCharacter* Character) RegisteredCharacters.Add(Character); BrainNameToCharacter.Add(BrainName, Character); - if (bCharactersInitialized) + if (bIsLoaded) { if (BrainNameToAgentInfo.Contains(BrainName)) { @@ -234,14 +245,13 @@ void UInworldSession::PossessAgents(const TArray& AgentInfos) InworldClient->LoadCharacters(BrainNames); } - bCharactersInitialized = true; - OnCharactersInitializedDelegateNative.Broadcast(bCharactersInitialized); - OnCharactersInitializedDelegate.Broadcast(bCharactersInitialized); + bIsLoaded = true; + OnRep_IsLoaded(); } void UInworldSession::UnpossessAgents() { - if (!bCharactersInitialized) + if (!bIsLoaded) { return; } @@ -253,9 +263,14 @@ void UInworldSession::UnpossessAgents() AgentIdToCharacter.Empty(); BrainNameToAgentInfo.Empty(); - bCharactersInitialized = false; - OnCharactersInitializedDelegateNative.Broadcast(bCharactersInitialized); - OnCharactersInitializedDelegate.Broadcast(bCharactersInitialized); + bIsLoaded = false; + OnRep_IsLoaded(); +} + +void UInworldSession::OnRep_IsLoaded() +{ + OnLoadedDelegateNative.Broadcast(bIsLoaded); + OnLoadedDelegate.Broadcast(bIsLoaded); } void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldTextEvent& Event) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp index 6498fd58..4cbbec4d 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -23,6 +23,7 @@ void AInworldSessionActor::PreInitializeComponents() if (GetLocalRole() == ROLE_Authority) { InworldSession = NewObject(this); + InworldSession->InitClient(); OnRep_InworldSession(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 AddReplicatedSubObject(InworldCharacter); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index d63fd788..3ab73a4a 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -69,7 +69,10 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject FInworldAgentInfo AgentInfo; FOnInworldCharacterPossessedNative OnPossessedDelegateNative; - UPROPERTY(Replicated) + UFUNCTION() + void OnRep_TargetPlayer(); + + UPROPERTY(ReplicatedUsing=OnRep_TargetPlayer) UInworldPlayer* TargetPlayer; FOnInworldCharacterTargetPlayerChangedNative OnTargetPlayerChangedDelegateNative; }; @@ -91,9 +94,5 @@ class INWORLDAIINTEGRATION_API IInworldCharacterOwnerInterface UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") UInworldCharacter* GetInworldCharacter() const; - -public: - UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") - FTransform GetInworldCharacterTransform() const; }; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index 450b1800..28cee08c 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -206,19 +206,8 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone void VisitAudioOnClient(const FInworldAudioDataEvent& Event); - UFUNCTION() - void OnRep_TargetPlayer(UInworldPlayerComponent* OldPlayer); - - UFUNCTION() - void OnRep_AgentInfo(FInworldAgentInfo AgentInfo); - TQueue PendingRepAudioEvents; - //UPROPERTY(ReplicatedUsing = OnRep_TargetPlayer) - UInworldPlayerComponent* TargetPlayer; - - TWeakObjectPtr InworldSubsystem; - UPROPERTY() TArray Playbacks; @@ -241,15 +230,17 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UPROPERTY(EditAnywhere, Category = "Inworld") FString BrainName; - // Replicated from server to client to update possession. - //UPROPERTY(ReplicatedUsing = OnRep_AgentInfo) - FInworldAgentInfo AgentInfo; - private: - UPROPERTY(Replicated) + UFUNCTION() + void OnRep_InworldCharacter(); + + UPROPERTY(ReplicatedUsing=OnRep_InworldCharacter) UInworldCharacter* InworldCharacter; - UPROPERTY() + UFUNCTION() + void OnRep_InworldSession(); + + UPROPERTY(ReplicatedUsing=OnRep_InworldSession) UInworldSession* InworldSession; #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index c02e1eea..f2be8d2e 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -94,7 +94,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, UPROPERTY(Replicated) UInworldPlayer* InworldPlayer; - UPROPERTY() + UPROPERTY(Replicated) UInworldSession* InworldSession; #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index 060c68b6..df6f0ed9 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -31,9 +31,8 @@ DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldEmotionEventNative, const FInworld DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldCustomEvent, const FInworldCustomEvent&, CustomEvent); DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldCustomEventNative, const FInworldCustomEvent& /*CustomEvent*/); -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldCharactersInitialized, bool, bCharactersInitialized); -DECLARE_DYNAMIC_DELEGATE_OneParam(FOnInworldCharactersInitializedCallback, bool, bCharactersInitialized); -DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldCharactersInitializedNative, bool /*bCharactersInitialized*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldSessionLoaded, bool, bLoaded); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldSessionLoadedNative, bool /*bLoaded*/); UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldSession : public UObject @@ -52,6 +51,11 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject UInworldSession(); virtual ~UInworldSession(); + UFUNCTION(BlueprintCallable, Category = "Client") + void InitClient(); + UFUNCTION(BlueprintCallable, Category = "Client") + void DestroyClient(); + UFUNCTION(BlueprintCallable, Category = "Inworld|Register") void RegisterCharacter(UInworldCharacter* Character); UFUNCTION(BlueprintCallable, Category = "Inworld|Register") @@ -152,11 +156,11 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject FOnInworldConnectionStateChangedNative& OnConnectionStateChanged() { return OnConnectionStateChangedDelegateNative; } UPROPERTY(BlueprintAssignable, Category = "Connection") - FOnInworldCharactersInitialized OnCharactersInitializedDelegate; - FOnInworldCharactersInitializedNative& OnCharactersInitialized() { return OnCharactersInitializedDelegateNative; } + FOnInworldSessionLoaded OnLoadedDelegate; + FOnInworldSessionLoadedNative& OnLoaded() { return OnLoadedDelegateNative; } UFUNCTION(BlueprintPure, Category = "Connection") - bool IsCharactersInitialized() const { return bCharactersInitialized; } + bool IsLoaded() const { return bIsLoaded; } UPROPERTY(BlueprintAssignable, Category = "Connection") FOnInworldPerceivedLatency OnPerceivedLatencyDelegate; @@ -167,24 +171,27 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject void UnpossessAgents(); private: - UPROPERTY(Replicated) - TArray RegisteredCharacters; - TMap BrainNameToCharacter; - TMap AgentIdToCharacter; - TMap BrainNameToAgentInfo; - - UPROPERTY(Replicated) - bool bCharactersInitialized; - UPROPERTY() UInworldClient* InworldClient; + UFUNCTION() + void OnRep_IsLoaded(); + + UPROPERTY(ReplicatedUsing = OnRep_IsLoaded) + bool bIsLoaded; + FDelegateHandle OnClientPacketReceivedHandle; FDelegateHandle OnClientConnectionStateChangedHandle; FDelegateHandle OnClientPerceivedLatencyHandle; + UPROPERTY(Replicated) + TArray RegisteredCharacters; + TMap BrainNameToCharacter; + TMap AgentIdToCharacter; + TMap BrainNameToAgentInfo; + FOnInworldConnectionStateChangedNative OnConnectionStateChangedDelegateNative; - FOnInworldCharactersInitializedNative OnCharactersInitializedDelegateNative; + FOnInworldSessionLoadedNative OnLoadedDelegateNative; FOnInworldPerceivedLatencyNative OnPerceivedLatencyDelegateNative; class FInworldSessionPacketVisitor : public TSharedFromThis, public InworldPacketVisitor From eee5c03f82aa3c5c2622bade6ea99317ed97e8da Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 12:56:40 -0400 Subject: [PATCH 07/45] rep fixes --- .../Private/InworldCharacterComponent.cpp | 32 ++++++++++++----- .../InworldGameplayDebuggerCategory.cpp | 34 +++++++++++-------- .../InworldPlayerAudioCaptureComponent.cpp | 30 ++++++++-------- .../Private/InworldPlayerComponent.cpp | 5 +-- .../InworldPlayerTargetingComponent.cpp | 9 +++-- .../InworldAIIntegration/Public/InworldApi.h | 8 ++--- .../Public/InworldCharacterComponent.h | 3 +- .../InworldPlayerAudioCaptureComponent.h | 1 + 8 files changed, 71 insertions(+), 51 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index fa1a4d66..cda52e9a 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -36,7 +36,7 @@ void UInworldCharacterComponent::InitializeComponent() if (GetOwnerRole() == ROLE_Authority) { InworldCharacter = NewObject(this); - OnRep_InworldCharacter(); + InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 AddReplicatedSubObject(InworldCharacter); #endif @@ -88,7 +88,6 @@ void UInworldCharacterComponent::BeginPlay() if (GetNetMode() != NM_Client) { - InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); Register(); } OnRep_InworldCharacter(); @@ -247,7 +246,7 @@ bool UInworldCharacterComponent::Unregister() FVector UInworldCharacterComponent::GetTargetPlayerCameraLocation() { - if (InworldCharacter->GetTargetPlayer() == nullptr) + if (InworldCharacter == nullptr || InworldCharacter->GetTargetPlayer() == nullptr) { return FVector::ZeroVector; } @@ -432,9 +431,24 @@ void UInworldCharacterComponent::Multicast_VisitEmotion_Implementation(const FIn } } +bool UInworldCharacterComponent::ShouldHandleEvent(const FInworldRouting& Routing) +{ + bool bShouldHandle = false; + bShouldHandle |= Routing.Source.Name == GetAgentId(); + if (Routing.Source.Type == EInworldActorType::PLAYER) + { + bShouldHandle |= Routing.Target.Name == GetAgentId(); + for (const auto& Target : Routing.Targets) + { + bShouldHandle |= Target.Name == GetAgentId(); + } + } + return bShouldHandle; +} + void UInworldCharacterComponent::OnInworldTextEvent(const FInworldTextEvent& Event) { - if (Event.Routing.Source.Name != GetAgentId()) + if (!ShouldHandleEvent(Event.Routing)) { return; } @@ -443,7 +457,7 @@ void UInworldCharacterComponent::OnInworldTextEvent(const FInworldTextEvent& Eve void UInworldCharacterComponent::OnInworldAudioEvent(const FInworldAudioDataEvent& Event) { - if (Event.Routing.Source.Name != GetAgentId()) + if (!ShouldHandleEvent(Event.Routing)) { return; } @@ -474,7 +488,7 @@ void UInworldCharacterComponent::OnInworldAudioEvent(const FInworldAudioDataEven void UInworldCharacterComponent::OnInworldSilenceEvent(const FInworldSilenceEvent& Event) { - if (Event.Routing.Source.Name != GetAgentId()) + if (!ShouldHandleEvent(Event.Routing)) { return; } @@ -483,7 +497,7 @@ void UInworldCharacterComponent::OnInworldSilenceEvent(const FInworldSilenceEven void UInworldCharacterComponent::OnInworldControlEvent(const FInworldControlEvent& Event) { - if (Event.Routing.Source.Name != GetAgentId()) + if (!ShouldHandleEvent(Event.Routing)) { return; } @@ -492,7 +506,7 @@ void UInworldCharacterComponent::OnInworldControlEvent(const FInworldControlEven void UInworldCharacterComponent::OnInworldEmotionEvent(const FInworldEmotionEvent& Event) { - if (Event.Routing.Source.Name != GetAgentId()) + if (!ShouldHandleEvent(Event.Routing)) { return; } @@ -501,7 +515,7 @@ void UInworldCharacterComponent::OnInworldEmotionEvent(const FInworldEmotionEven void UInworldCharacterComponent::OnInworldCustomEvent(const FInworldCustomEvent& Event) { - if (Event.Routing.Source.Name != GetAgentId()) + if (!ShouldHandleEvent(Event.Routing)) { return; } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp index 37c1b9ac..c4c64133 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldGameplayDebuggerCategory.cpp @@ -9,11 +9,13 @@ #include "InworldGameplayDebuggerCategory.h" #include "InworldApi.h" -#include "InworldCharacterComponent.h" #include "Engine/Engine.h" #include "Engine/Font.h" #include "InworldPlayerAudioCaptureComponent.h" +#include "InworldCharacterComponent.h" #include "InworldPlayerComponent.h" +#include "InworldCharacter.h" +#include "InworldPlayer.h" #include "UObject/UObjectIterator.h" @@ -48,33 +50,35 @@ void FInworldGameplayDebuggerCategory::CollectData(APlayerController* OwnerPC, A for (UInworldCharacter* Character : InworldApi->GetInworldSession()->GetRegisteredCharacters()) { auto& Data = DataPack.CharData.Emplace_GetRef(); - //TODO: FIX - //Data.OverheadLocation = Actor->GetActorLocation() + FVector(0, 0, Actor->GetSimpleCollisionHalfHeight()); - //Data.bIsInteracting = Comp->IsInteractingWithPlayer(); + auto* Actor = Character->GetTypedOuter(); + Data.OverheadLocation = Actor->GetActorLocation() + FVector(0, 0, Actor->GetSimpleCollisionHalfHeight()); + Data.bIsInteracting = Character->GetTargetPlayer() != nullptr; Data.GivenName = Character->GetAgentInfo().GivenName; Data.AgentId = Character->GetAgentInfo().AgentId; - //Data.CurrentMessage = Comp->GetCurrentMessage() ? Comp->GetCurrentMessage()->ToDebugString() : TEXT(""); - //Data.MessageQueueEntries = Comp->MessageQueue->PendingMessageEntries.Num(); - //Data.EmotionalBehavior = static_cast(Comp->GetEmotionalBehavior()); - //Data.EmotionStrength = static_cast(Comp->GetEmotionStrength()); - //Data.bPendingRepAudioEvent = !Comp->PendingRepAudioEvents.IsEmpty(); + if (UInworldCharacterComponent* CharacterComponent = Character->GetTypedOuter()) + { + Data.CurrentMessage = CharacterComponent->GetCurrentMessage() ? CharacterComponent->GetCurrentMessage()->ToDebugString() : TEXT(""); + Data.MessageQueueEntries = CharacterComponent->MessageQueue->PendingMessageEntries.Num(); + Data.EmotionalBehavior = static_cast(CharacterComponent->GetEmotionalBehavior()); + Data.EmotionStrength = static_cast(CharacterComponent->GetEmotionStrength()); + Data.bPendingRepAudioEvent = !CharacterComponent->PendingRepAudioEvents.IsEmpty(); + } } for (TObjectIterator Itr; Itr; ++Itr) { - //TODO: FIX auto* AudioComp = *Itr; - //auto* PlayerComp = AudioComp->PlayerComponent.Get(); + auto* Player = AudioComp->InworldPlayer.Get(); - //if (!PlayerComp) + if (!Player) { - //continue; + continue; } auto& Data = DataPack.PlayerData.Emplace_GetRef(); //TODO: support multi agent - //Data.TargetCharacterAgentId = (PlayerComp->Targets.Num() == 0) ? "" : PlayerComp->Targets[0].AgentId; - //Data.bServerCapturingVoice = AudioComp->bServerCapturingVoice; + Data.TargetCharacterAgentId = (Player->GetTargetCharacters().Num() == 0) ? "" : Player->GetTargetCharacters()[0]->GetAgentInfo().AgentId; + Data.bServerCapturingVoice = AudioComp->bServerCapturingVoice; } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index 2d0feb12..7ba5d2a4 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -174,6 +174,20 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() ); PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); + InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()); + InworldSession->OnConnectionStateChanged().AddLambda( + [this](EInworldConnectionState ConnectionState) -> void + { + EvaluateVoiceCapture(); + } + ); + InworldSession->OnLoaded().AddLambda( + [this](bool bLoaded) -> void + { + EvaluateVoiceCapture(); + } + ); + PrimaryComponentTick.SetTickFunctionEnable(false); } @@ -271,18 +285,11 @@ void UInworldPlayerAudioCaptureComponent::EvaluateVoiceCapture() { if (GetOwnerRole() == ROLE_Authority) { - const bool bHasPlayer = InworldPlayer != nullptr; - UInworldSession* InworldSession = bHasPlayer ? IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()) : nullptr; - if (InworldSession == nullptr) - { - return; - } - const bool bIsMicHot = !bMuted; const bool bIsWorldPlaying = !GetWorld()->IsPaused(); const bool bHasTargetCharacter = PlayerAudioTargetState.DesiredCharacters.Num() != 0; const EInworldConnectionState ConnectionState = InworldSession->GetConnectionState(); - const bool bHasActiveInworldSession = ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting; + const bool bHasActiveInworldSession = InworldSession->IsLoaded() && (ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting); const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasTargetCharacter && bHasActiveInworldSession; @@ -417,13 +424,6 @@ void UInworldPlayerAudioCaptureComponent::Server_ProcessVoiceCaptureChunk_Implem { if (PlayerAudioTargetState.ActiveCharacters.Num() != 0) { - const bool bHasPlayer = InworldPlayer != nullptr; - UInworldSession* InworldSession = bHasPlayer ? IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()) : nullptr; - if (InworldSession == nullptr) - { - return; - } - InworldSession->BroadcastSoundMessage(PlayerAudioTargetState.ActiveCharacters, PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index 834b4093..d8a708d3 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -29,6 +29,7 @@ void UInworldPlayerComponent::InitializeComponent() if (GetOwnerRole() == ROLE_Authority) { InworldPlayer = NewObject(this); + InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); } /*InworldPlayer->OnTargetCharacterAdded().AddLambda( [this](UInworldCharacter* Character) -> void @@ -48,10 +49,6 @@ void UInworldPlayerComponent::UninitializeComponent() void UInworldPlayerComponent::BeginPlay() { Super::BeginPlay(); - if (GetNetMode() != NM_Client) - { - InworldSession = IInworldSessionOwnerInterface::Execute_GetInworldSession(GetWorld()->GetSubsystem()); - } } void UInworldPlayerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index a677c553..3f13c725 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -28,7 +28,7 @@ void UInworldPlayerTargetingComponent::BeginPlay() else { PrimaryComponentTick.SetTickFunctionEnable(true); - InworldPlayer = Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))->GetInworldPlayer(); + InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))); } } @@ -73,7 +73,12 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() } } - const TArray& Characters = InworldPlayer->GetInworldPlayerOwner()->GetInworldSession()->GetRegisteredCharacters(); + UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()); + if (!InworldSession) + { + return; + } + const TArray& Characters = InworldSession->GetRegisteredCharacters(); UInworldCharacter* BestTarget = nullptr; float BestTargetDot = -1.f; for (UInworldCharacter* Character : Characters) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index 2f9ec7dc..cd962a0b 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -27,7 +27,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCharactersInitialized, bool, bCha DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCustomTrigger, FString, Name); UCLASS(BlueprintType, Config = InworldAI) -class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, public IInworldSessionOwnerInterface +class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem { GENERATED_BODY() @@ -35,10 +35,8 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem, pu UInworldApiSubsystem(); void SetInworldSession(UInworldSession* Session); - - // IInworldSessionOwnerInterface - UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } - // IInworldSessionOwnerInterface + UFUNCTION(BlueprintPure, Category = "Session") + UInworldSession* GetInworldSession() const { return InworldSession; } /** * Start InworldAI session diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index 28cee08c..a500825c 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -104,7 +104,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UInworldCharacterPlayback* GetPlayback(TSubclassOf Class) const; UFUNCTION(BlueprintCallable, Category = "Interactions") - bool IsInteractingWithPlayer() const { return InworldCharacter->GetTargetPlayer() != nullptr; } + bool IsInteractingWithPlayer() const { return InworldCharacter != nullptr && InworldCharacter->GetTargetPlayer() != nullptr; } UFUNCTION(BlueprintCallable, Category = "Emotions") EInworldCharacterEmotionalBehavior GetEmotionalBehavior() const { return EmotionalBehavior; } @@ -174,6 +174,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone FString UiName = "Character"; private: + bool ShouldHandleEvent(const FInworldRouting& Routing); UFUNCTION() void OnInworldTextEvent(const FInworldTextEvent& Event); UFUNCTION() diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h index 0d21f0a4..f4945801 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h @@ -110,6 +110,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct TAtomic bCapturingVoice = false; TWeakObjectPtr InworldPlayer; + TWeakObjectPtr InworldSession; TSharedPtr InputAudioCapture; TSharedPtr OutputAudioCapture; From 653f57d2d791e201cba86a0484d0216a330d267b Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 13:03:54 -0400 Subject: [PATCH 08/45] replication fixups --- .../Private/InworldCharacterComponent.cpp | 10 +++++++--- .../Private/InworldPlayerComponent.cpp | 11 +++++++++-- .../Private/InworldSessionActor.cpp | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index cda52e9a..afd563e5 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -35,11 +35,15 @@ void UInworldCharacterComponent::InitializeComponent() if (GetOwnerRole() == ROLE_Authority) { - InworldCharacter = NewObject(this); - InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE)) + { + InworldCharacter = NewObject(this); + InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - AddReplicatedSubObject(InworldCharacter); + AddReplicatedSubObject(InworldCharacter); #endif + } } #if WITH_EDITOR diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index d8a708d3..c92c5c40 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -28,8 +28,15 @@ void UInworldPlayerComponent::InitializeComponent() if (GetOwnerRole() == ROLE_Authority) { - InworldPlayer = NewObject(this); - InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE)) + { + InworldPlayer = NewObject(this); + InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + AddReplicatedSubObject(InworldPlayer); +#endif + } } /*InworldPlayer->OnTargetCharacterAdded().AddLambda( [this](UInworldCharacter* Character) -> void diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp index 4cbbec4d..2c60ccf6 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -26,7 +26,7 @@ void AInworldSessionActor::PreInitializeComponents() InworldSession->InitClient(); OnRep_InworldSession(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - AddReplicatedSubObject(InworldCharacter); + AddReplicatedSubObject(InworldSession); #endif } } From cede5cacc51d35d40b5e4e01779778c699532f0e Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 14:16:19 -0400 Subject: [PATCH 09/45] destruction cleanup --- .../Private/InworldCharacterComponent.cpp | 24 +++++++++++++------ .../InworldPlayerAudioCaptureComponent.cpp | 20 +++++++++++++--- .../Private/InworldPlayerComponent.cpp | 16 ++++++++----- .../InworldPlayerTargetingComponent.cpp | 4 ++-- .../Private/InworldSession.cpp | 13 ++++++---- .../Private/InworldSessionActor.cpp | 24 ++++++++++++++++++- .../Public/InworldCharacterComponent.h | 7 +++--- .../InworldPlayerAudioCaptureComponent.h | 4 ++++ .../Public/InworldPlayerComponent.h | 9 ++++--- .../Public/InworldPlayerTargetingComponent.h | 5 ++-- .../Public/InworldSession.h | 4 ++-- .../Public/InworldSessionActor.h | 5 ++-- 12 files changed, 95 insertions(+), 40 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index afd563e5..0d3a0a63 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -71,6 +71,21 @@ void UInworldCharacterComponent::UninitializeComponent() { Super::UninitializeComponent(); + if (GetOwnerRole() == ROLE_Authority) + { + Unregister(); + } + + if (IsValid(InworldCharacter)) + { + #if ENGINE_MAJOR_VERSION == 5 + InworldCharacter->MarkAsGarbage(); + #endif + + #if ENGINE_MAJOR_VERSION == 4 + InworldCharacter->MarkPendingKill(); + #endif + } InworldCharacter = nullptr; #if WITH_EDITOR @@ -90,7 +105,7 @@ void UInworldCharacterComponent::BeginPlay() { Super::BeginPlay(); - if (GetNetMode() != NM_Client) + if (GetOwnerRole() == ROLE_Authority) { Register(); } @@ -110,11 +125,6 @@ void UInworldCharacterComponent::EndPlay(EEndPlayReason::Type Reason) Pb->EndPlay(); Pb->ClearCharacterComponent(); } - - if (GetNetMode() != NM_Client) - { - Unregister(); - } MessageQueue->Clear(); @@ -577,7 +587,7 @@ void UInworldCharacterComponent::OnRep_InworldCharacter() void UInworldCharacterComponent::OnRep_InworldSession() { - if (InworldSession != nullptr) + if (InworldSession.IsValid()) { InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index 7ba5d2a4..fdc5b279 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -164,7 +164,7 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() if (GetOwnerRole() == ROLE_Authority) { InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))); - InworldPlayer->OnTargetCharactersChanged().AddLambda( + OnPlayerTargetCharactersChanged = InworldPlayer->OnTargetCharactersChanged().AddLambda( [this]() -> void { PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); @@ -175,13 +175,13 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()); - InworldSession->OnConnectionStateChanged().AddLambda( + OnSessionConnectionStateChanged = InworldSession->OnConnectionStateChanged().AddLambda( [this](EInworldConnectionState ConnectionState) -> void { EvaluateVoiceCapture(); } ); - InworldSession->OnLoaded().AddLambda( + OnSessionLoaded = InworldSession->OnLoaded().AddLambda( [this](bool bLoaded) -> void { EvaluateVoiceCapture(); @@ -243,6 +243,20 @@ void UInworldPlayerAudioCaptureComponent::EndPlay(const EEndPlayReason::Type End StopCapture(); } + if (GetOwnerRole() == ROLE_Authority) + { + if (InworldPlayer.IsValid()) + { + InworldPlayer->OnTargetCharactersChanged().Remove(OnPlayerTargetCharactersChanged); + } + + if (InworldSession.IsValid()) + { + InworldSession->OnConnectionStateChanged().Remove(OnSessionConnectionStateChanged); + InworldSession->OnLoaded().Remove(OnSessionLoaded); + } + } + Super::EndPlay(EndPlayReason); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index c92c5c40..58f2b1f7 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -38,18 +38,22 @@ void UInworldPlayerComponent::InitializeComponent() #endif } } - /*InworldPlayer->OnTargetCharacterAdded().AddLambda( - [this](UInworldCharacter* Character) -> void - { - //TargetCharacters.Add(Character->GetAgentInfo().AgentId); - } - );*/ } void UInworldPlayerComponent::UninitializeComponent() { Super::UninitializeComponent(); + if (IsValid(InworldPlayer)) + { +#if ENGINE_MAJOR_VERSION == 5 + InworldPlayer->MarkAsGarbage(); +#endif + +#if ENGINE_MAJOR_VERSION == 4 + InworldPlayer->MarkPendingKill(); +#endif + } InworldPlayer = nullptr; } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 3f13c725..99549aa2 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -61,7 +61,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() const FVector Location = GetOwner()->GetActorLocation(); for (int32 i = 0; i < TargetCharacters.Num(); i++) { - UInworldCharacter* Character = TargetCharacters[i]; + UInworldCharacter* Character = TargetCharacters[i].Get(); AActor* OuterActor = Character->GetTypedOuter(); const FVector CharacterLocation = OuterActor != nullptr ? OuterActor->GetActorLocation() : FVector::ZeroVector; const float DistSq = FVector::DistSquared(Location, CharacterLocation); @@ -143,7 +143,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() return; } - UInworldCharacter* CurrentTarget = TargetCharacters.Num() != 0 ? TargetCharacters[0] : nullptr; + UInworldCharacter* CurrentTarget = TargetCharacters.Num() != 0 ? TargetCharacters[0].Get() : nullptr; if (CurrentTarget != BestTarget) { if (CurrentTarget) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index a11cc7bb..7f777836 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -21,11 +21,9 @@ UInworldSession::UInworldSession() {} UInworldSession::~UInworldSession() -{ - DestroyClient(); -} +{} -void UInworldSession::InitClient() +void UInworldSession::Init() { InworldClient = NewObject(this); OnClientPacketReceivedHandle = InworldClient->OnPacketReceived().AddLambda( @@ -50,8 +48,13 @@ void UInworldSession::InitClient() ); } -void UInworldSession::DestroyClient() +void UInworldSession::Destroy() { + TArray RegisteredCharactersCopy = RegisteredCharacters; + for (UInworldCharacter* RegisteredCharacter : RegisteredCharactersCopy) + { + UnregisterCharacter(RegisteredCharacter); + } if (InworldClient) { InworldClient->OnPacketReceived().Remove(OnClientPacketReceivedHandle); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp index 2c60ccf6..1d35264d 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -23,7 +23,8 @@ void AInworldSessionActor::PreInitializeComponents() if (GetLocalRole() == ROLE_Authority) { InworldSession = NewObject(this); - InworldSession->InitClient(); + InworldSession->Init(); + OnRep_InworldSession(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 AddReplicatedSubObject(InworldSession); @@ -31,6 +32,27 @@ void AInworldSessionActor::PreInitializeComponents() } } +void AInworldSessionActor::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); + + if (GetLocalRole() == ROLE_Authority) + { + InworldSession->Destroy(); + if (IsValid(InworldSession)) + { +#if ENGINE_MAJOR_VERSION == 5 + InworldSession->MarkAsGarbage(); +#endif + +#if ENGINE_MAJOR_VERSION == 4 + InworldSession->MarkPendingKill(); +#endif + } + InworldSession = nullptr; + } +} + void AInworldSessionActor::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index a500825c..f136e8af 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -36,9 +36,8 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UInworldCharacterComponent(); // IInworldCharacterOwnerInterface - UInworldCharacter* GetInworldCharacter_Implementation() const { return InworldCharacter; } - UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } - FTransform GetInworldPlayerTransform() const { return GetOwner()->GetTransform(); } + virtual UInworldCharacter* GetInworldCharacter_Implementation() const override { return InworldCharacter; } + virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession.Get(); } // ~IInworldCharacterOwnerInterface virtual void InitializeComponent() override; @@ -242,7 +241,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone void OnRep_InworldSession(); UPROPERTY(ReplicatedUsing=OnRep_InworldSession) - UInworldSession* InworldSession; + TWeakObjectPtr InworldSession; #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h index f4945801..a76d5bba 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h @@ -110,7 +110,11 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct TAtomic bCapturingVoice = false; TWeakObjectPtr InworldPlayer; + FDelegateHandle OnPlayerTargetCharactersChanged; + TWeakObjectPtr InworldSession; + FDelegateHandle OnSessionConnectionStateChanged; + FDelegateHandle OnSessionLoaded; TSharedPtr InputAudioCapture; TSharedPtr OutputAudioCapture; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index f2be8d2e..864e5c17 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -36,10 +36,9 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, UInworldPlayerComponent(); // IInworldPlayerInterface - UInworldPlayer* GetInworldPlayer_Implementation() const { return InworldPlayer; } - UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } - FTransform GetInworldPlayerTransform() const { return GetOwner()->GetTransform(); } - // IInworldPlayerInterface + virtual UInworldPlayer* GetInworldPlayer_Implementation() const override { return InworldPlayer; } + virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession.Get(); } + // ~IInworldPlayerInterface virtual void InitializeComponent() override; virtual void UninitializeComponent() override; @@ -95,7 +94,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, UInworldPlayer* InworldPlayer; UPROPERTY(Replicated) - UInworldSession* InworldSession; + TWeakObjectPtr InworldSession; #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h index 914eac24..cd0037ed 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h @@ -41,7 +41,6 @@ class INWORLDAIINTEGRATION_API UInworldPlayerTargetingComponent : public UActorC bool bMultipleTargets = false; private: - TArray TargetCharacters; - - UInworldPlayer* InworldPlayer; + TWeakObjectPtr InworldPlayer; + TArray> TargetCharacters; }; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index df6f0ed9..d09c543b 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -52,9 +52,9 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject virtual ~UInworldSession(); UFUNCTION(BlueprintCallable, Category = "Client") - void InitClient(); + void Init(); UFUNCTION(BlueprintCallable, Category = "Client") - void DestroyClient(); + void Destroy(); UFUNCTION(BlueprintCallable, Category = "Inworld|Register") void RegisterCharacter(UInworldCharacter* Character); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h index 55f7583c..72dd0247 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h @@ -20,8 +20,8 @@ class INWORLDAIINTEGRATION_API AInworldSessionActor : public AActor, public IInw AInworldSessionActor(); // IInworldSessionOwnerInterface - UInworldSession* GetInworldSession_Implementation() const { return InworldSession; } - // IInworldSessionOwnerInterface + virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession; } + // ~IInworldSessionOwnerInterface UPROPERTY(BlueprintAssignable, Category = "Session") FOnInworldSessionCreated OnSessionCreatedDelegate; @@ -32,6 +32,7 @@ class INWORLDAIINTEGRATION_API AInworldSessionActor : public AActor, public IInw protected: virtual void PreInitializeComponents() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; From eab2ef85f0410a3c02c56b1d3c3d72712d3c11cb Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 14:29:34 -0400 Subject: [PATCH 10/45] broadcast text event --- .../InworldAIIntegration/Private/InworldSession.cpp | 8 ++++++-- .../Source/InworldAIIntegration/Public/InworldSession.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 7f777836..bf0bd554 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -171,9 +171,13 @@ void UInworldSession::UnloadCharacters(const TArray& Charact InworldClient->UnloadCharacters(CharactersToAgentIds(Characters)); } -FInworldWrappedPacket UInworldSession::BroadcastTextMessage(const TArray& Characters, const FString& Message) +void UInworldSession::BroadcastTextMessage(const TArray& Characters, const FString& Message) { - return InworldClient->SendTextMessage(CharactersToAgentIds(Characters), Message); + auto Packet = InworldClient->SendTextMessage(CharactersToAgentIds(Characters), Message).Packet; + if (Packet.IsValid()) + { + Packet->Accept(*PacketVisitor); + } } void UInworldSession::BroadcastSoundMessage(const TArray& Characters, const TArray& InputData, const TArray& OutputData) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index d09c543b..b04fc190 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -96,9 +96,9 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { InworldClient->LoadPlayerProfile(PlayerProfile); } UFUNCTION(BlueprintCallable, Category = "Message|Text") - FInworldWrappedPacket SendTextMessage(UInworldCharacter* Character, const FString& Message) { return BroadcastTextMessage({Character}, Message); } + void SendTextMessage(UInworldCharacter* Character, const FString& Message) { BroadcastTextMessage({Character}, Message); } UFUNCTION(BlueprintCallable, Category = "Message|Text") - FInworldWrappedPacket BroadcastTextMessage(const TArray& Characters, const FString& Message); + void BroadcastTextMessage(const TArray& Characters, const FString& Message); UFUNCTION(BlueprintCallable, Category = "Message|Audio") void SendSoundMessage(UInworldCharacter* Character, const TArray& InputData, const TArray& OutputData) { BroadcastSoundMessage({ Character }, InputData, OutputData); } From ac4e4f9d49f16b926287cf95c3b034a5f9d5dc5f Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 18:16:51 -0400 Subject: [PATCH 11/45] Add missing functions to character and player --- .../BP_InworldSessionController.uasset | Bin 78478 -> 80366 bytes .../Private/InworldApi.cpp | 6 +++ .../Private/InworldCharacter.cpp | 43 ++++++++++++++++++ .../Private/InworldCharacterComponent.cpp | 20 ++++---- .../Private/InworldPlayer.cpp | 30 ++++++++++++ .../Private/InworldPlayerComponent.cpp | 14 +++--- .../Private/InworldSession.cpp | 4 ++ .../Private/InworldSessionActor.cpp | 18 ++++++-- .../Public/InworldCharacter.h | 22 +++++++-- .../Public/InworldCharacterComponent.h | 4 +- .../Public/InworldPlayer.h | 16 ++++++- .../Public/InworldPlayerComponent.h | 2 +- .../Public/InworldSession.h | 4 +- .../Public/InworldSessionActor.h | 1 + 14 files changed, 152 insertions(+), 32 deletions(-) diff --git a/InworldAI/Content/BP_InworldSessionController.uasset b/InworldAI/Content/BP_InworldSessionController.uasset index a0180bce448ca3d7031f8774b3e8cbcc941d7cba..896217e8a4929d5f4ecf4b1f0b418b6d2c0604e7 100644 GIT binary patch literal 80366 zcmeHw31CxI*8htlDuO7oi6RA57FoKa8*U_N(w3!ES{OxH()P6trb$UspehKiDDHwf zBI=-y`;MaH2IKDNxPGIfj{C}}<2ddc|MR=|p1hZrm-H2iqu>9#ki7TKz4x4Z&OPVc zbC=g_I(hWv-)`BmW!{dO)?)`v`-HAYJ?Qg~w)aPk2we5n!WZ^fyZQAo!}lcEA)DqD z|4{K>_s>t!?pnHF^nu+7HhuQ1M^#kj_gQ?@;(Jzpd{65x1Uqfu;CZJ^Yq;r+7yIAv zx5qd4I+$R~|7S_)M$fblJ~?924I}T~@E~Br{-^e`2d5o)U0~;-tDZY)eQ*rH-phaG zwqDcD7_wpMvp21q^ivVqa(Lp$XP1@T=6kd6`4`4>1`jxZVBR@vUI|QnVE^lG>T^o_ zfQC2sC)lUWx4rkVch#4>y_&bqb6;TGNP@-h(6pWCS{04xbm^w;@6xm{=rfd_+#dSp zE(o|i#kqcOv8O1vz+F~UQs61f^ZW7&i>ZiAL+J9|fg}OC{(i8g^>S+(;m`&bY1#qw z@zCd?Zh4;__tte4XMQ+u#GA***KF8l*C(HOueIX#ubVIZ=`Xk4hw{LK2B1YdYL^b4 z=;}jv2OTuSUwF`TJ*)@g`q;v8xguZFK3g{`Lq1g!>E@dUorRlwiT>tNP%sj8>=tnU z0fBIjqX}4ce|0L;)=Fv8` zl)beZ?&=fK*py(M9@efM5SzOfKn)9nk$SzMIut1j#aqL{c5Uf^f99AEx`meAg=XV`q{fXqfBdPvfi#O-}K&_&;fd^(d%P+LL25e@A};ViN%8L z)v;)+9!s=qmAAbc>JDgILnx~K>GgR!WbA26G;1gS{g_L8s)xA>?Hjwi-o3X8rf_e5 z?)1EV4E9oQ6uE0cO_5-tEv9RKdF-2a!L?W0d-4s_P`i#8i7qOmjzinEE&tyApL?Ky zrQ-9|wWYvX=L<$^qfJd=eP$>gstbif)bMGyj@m(HMq66+NW$AzR~ObvXc4_ZTQKf` zDZp4)5sXh;sK;WV24rcwAN_K#UVvA|smtPtKwG3_O1(}^Y@ZShHV~<2+jd{L z50FjKn}YT2Rl43#8zr<ⅆ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 $%6Gx59nE^C85p3krQgu$Gt)-3(dr>GH&WY)9 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 literal 78478 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 T{eq6e15r@1vVQoaVORY>6X@)` diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 22ad9fa1..50adcd3f 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -37,6 +37,12 @@ void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) } ); OnCharactersInitialized.Broadcast(InworldSession->IsLoaded()); + InworldSession->OnConnectionStateChanged().AddLambda( + [this](EInworldConnectionState ConnectionState) -> void + { + OnConnectionStateChanged.Broadcast(ConnectionState); + } + ); } void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index ec324428..0316bdda 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -50,6 +50,49 @@ bool UInworldCharacter::CallRemoteFunction(UFunction* Function, void* Parms, FOu return false; } + +void UInworldCharacter::SendTextMessage(const FString& Text) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + InworldSession->SendTextMessage(this, Text); +} + +void UInworldCharacter::SendTrigger(const FString& Name, const TMap& Params) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + InworldSession->SendTrigger(this, Name, Params); +} + +void UInworldCharacter::SendNarrationEvent(const FString& Content) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + InworldSession->SendNarrationEvent(this, Content); +} + +void UInworldCharacter::SendAudioSessionStart() +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + InworldSession->SendAudioSessionStart(this); +} + +void UInworldCharacter::SendAudioSessionStop() +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + InworldSession->SendAudioSessionStop(this); +} + +void UInworldCharacter::SendSoundMessage(const TArray& InputData, const TArray& OutputData) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + InworldSession->SendSoundMessage(this, InputData, OutputData); +} + +void UInworldCharacter::CancelResponse(const FString& InteractionId, const TArray& UtteranceIds) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + InworldSession->CancelResponse(this, InteractionId, UtteranceIds); +} + TScriptInterface UInworldCharacter::GetInworldCharacterOwner() { if (!ensureMsgf(GetOuter()->Implements(), TEXT("UInworldCharacter outer must implement IInworldCharacterOwnerInterface!"))) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 0d3a0a63..86b9b65c 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -201,37 +201,37 @@ void UInworldCharacterComponent::CancelCurrentInteraction() return; } - const FString CurrentInteractionId = CurrentMessage->InteractionId; - TArray CanceledUtterances = MessageQueue->CancelInteraction(CurrentInteractionId); + const FString CanceledInteractionId = CurrentMessage->InteractionId; + TArray CanceledUtterances = MessageQueue->CancelInteraction(CanceledInteractionId); if (CanceledUtterances.Num() > 0) { - InworldSession->CancelResponse(InworldCharacter, CurrentInteractionId, CanceledUtterances); + InworldCharacter->CancelResponse(CanceledInteractionId, CanceledUtterances); } } void UInworldCharacterComponent::SendTextMessage(const FString& Text) const { - InworldSession->SendTextMessage(InworldCharacter, Text); + InworldCharacter->SendTextMessage(Text); } void UInworldCharacterComponent::SendTrigger(const FString& Name, const TMap& Params) const { - InworldSession->SendTrigger(InworldCharacter, Name, Params); + InworldCharacter->SendTrigger(Name, Params); } void UInworldCharacterComponent::SendNarrationEvent(const FString& Content) { - InworldSession->SendNarrationEvent(InworldCharacter, Content); + InworldCharacter->SendNarrationEvent(Content); } -void UInworldCharacterComponent::StartAudioSession(const AActor* Owner) const +void UInworldCharacterComponent::StartAudioSession() { - InworldSession->SendAudioSessionStart(InworldCharacter); + InworldCharacter->SendAudioSessionStart(); } -void UInworldCharacterComponent::StopAudioSession() const +void UInworldCharacterComponent::StopAudioSession() { - InworldSession->SendAudioSessionStop(InworldCharacter); + InworldCharacter->SendAudioSessionStop(); } bool UInworldCharacterComponent::Register() diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index cac7f92c..6480f232 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -49,6 +49,36 @@ bool UInworldPlayer::CallRemoteFunction(UFunction* Function, void* Parms, FOutPa return false; } +void UInworldPlayer::BroadcastTextMessage(const FString& Text) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + InworldSession->BroadcastTextMessage(GetTargetCharacters(), Text); +} + +void UInworldPlayer::BroadcastTrigger(const FString& Name, const TMap& Params) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + InworldSession->BroadcastTrigger(GetTargetCharacters(), Name, Params); +} + +void UInworldPlayer::BroadcastAudioSessionStart() +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + InworldSession->BroadcastAudioSessionStart(GetTargetCharacters()); +} + +void UInworldPlayer::BroadcastAudioSessionStop() +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + InworldSession->BroadcastAudioSessionStop(GetTargetCharacters()); +} + +void UInworldPlayer::BroadcastSoundMessage(const TArray& Input, const TArray& Output) +{ + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + InworldSession->BroadcastSoundMessage(GetTargetCharacters(), Input, Output); +} + TScriptInterface UInworldPlayer::GetInworldPlayerOwner() { if (!ensureMsgf(GetOuter()->Implements(), TEXT("UInworldPlayer outer must implement IInworldPlayerOwnerInterface!"))) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index 58f2b1f7..defadd01 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -121,7 +121,7 @@ void UInworldPlayerComponent::ContinueMultiAgentConversation() { if (InworldPlayer->GetTargetCharacters().Num() > 1) { - InworldSession->BroadcastTrigger(InworldPlayer->GetTargetCharacters(), "inworld.conversation.next_turn", {}); + InworldPlayer->BroadcastTrigger("inworld.conversation.next_turn", {}); } } @@ -140,30 +140,30 @@ void UInworldPlayerComponent::ClearAllTargetInworldCharacters() InworldPlayer->ClearAllTargetCharacters(); } -void UInworldPlayerComponent::SendTextMessageToTarget_Implementation(const FString& Message) +void UInworldPlayerComponent::SendTextMessageToTarget(const FString& Message) { if (!Message.IsEmpty()) { - InworldSession->BroadcastTextMessage(InworldPlayer->GetTargetCharacters(), Message); + InworldPlayer->BroadcastTextMessage(Message); } } void UInworldPlayerComponent::SendTriggerToTarget(const FString& Name, const TMap& Params) { - InworldSession->BroadcastTrigger(InworldPlayer->GetTargetCharacters(), Name, Params); + InworldPlayer->BroadcastTrigger(Name, Params); } void UInworldPlayerComponent::StartAudioSessionWithTarget() { - InworldSession->BroadcastAudioSessionStart(InworldPlayer->GetTargetCharacters()); + InworldPlayer->BroadcastAudioSessionStart(); } void UInworldPlayerComponent::StopAudioSessionWithTarget() { - InworldSession->BroadcastAudioSessionStop(InworldPlayer->GetTargetCharacters()); + InworldPlayer->BroadcastAudioSessionStop(); } void UInworldPlayerComponent::SendAudioMessageToTarget(const TArray& InputData, const TArray& OutputData) { - InworldSession->BroadcastSoundMessage(InworldPlayer->GetTargetCharacters(), InputData, OutputData); + InworldPlayer->BroadcastSoundMessage(InputData, OutputData); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index bf0bd554..009296d7 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -173,6 +173,10 @@ void UInworldSession::UnloadCharacters(const TArray& Charact void UInworldSession::BroadcastTextMessage(const TArray& Characters, const FString& Message) { + if (!ensureMsgf(InworldClient, TEXT("InworldSession: InworldClient is null! Ensure to call Init() on Session."))) + { + return; + } auto Packet = InworldClient->SendTextMessage(CharactersToAgentIds(Characters), Message).Packet; if (Packet.IsValid()) { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp index 1d35264d..4ec37bb5 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -22,16 +22,24 @@ void AInworldSessionActor::PreInitializeComponents() if (GetLocalRole() == ROLE_Authority) { - InworldSession = NewObject(this); - InworldSession->Init(); - - OnRep_InworldSession(); + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE)) + { + InworldSession = NewObject(this); + InworldSession->Init(); + OnRep_InworldSession(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - AddReplicatedSubObject(InworldSession); + AddReplicatedSubObject(InworldSession); #endif + } } } +void AInworldSessionActor::BeginPlay() +{ + Super::BeginPlay(); +} + void AInworldSessionActor::EndPlay(const EEndPlayReason::Type EndPlayReason) { Super::EndPlay(EndPlayReason); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index 3ab73a4a..4f3f95dd 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -23,13 +23,29 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject { GENERATED_BODY() public: - //UObject + // UObject virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual bool IsSupportedForNetworking() const override { return true; } virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override; virtual bool CallRemoteFunction(UFunction* Function, void* Parms, struct FOutParmRec* OutParms, FFrame* Stack) override; - //~UObject + // ~UObject + +public: + UFUNCTION(BlueprintCallable, Category = "Message") + void SendTextMessage(const FString& Text); + UFUNCTION(BlueprintCallable, Category = "Trigger") + void SendTrigger(const FString& Name, const TMap& Params); + UFUNCTION(BlueprintCallable, Category = "Narration") + void SendNarrationEvent(const FString& Content); + UFUNCTION(BlueprintCallable, Category = "Audio") + void SendAudioSessionStart(); + UFUNCTION(BlueprintCallable, Category = "Audio") + void SendAudioSessionStop(); + UFUNCTION(BlueprintCallable, Category = "Audio") + void SendSoundMessage(const TArray& Input, const TArray& Output); + UFUNCTION(BlueprintCallable, Category = "Mutation") + void CancelResponse(const FString& InteractionId, const TArray& UtteranceIds); public: UFUNCTION(BlueprintCallable, Category = "Inworld|Player") @@ -57,7 +73,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject UFUNCTION(BlueprintCallable, Category = "Engagement") void ClearTargetPlayer(); - UFUNCTION(BlueprintPure, Category="Engagement") + UFUNCTION(BlueprintPure, Category = "Engagement") UInworldPlayer* GetTargetPlayer() const { return TargetPlayer; } UPROPERTY(BlueprintAssignable, Category = "Engagement") diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index f136e8af..19087b24 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -123,10 +123,10 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone void SendNarrationEvent(const FString& Content); UFUNCTION(BlueprintCallable, Category = "Interaction") - void StartAudioSession(const AActor* Owner) const; + void StartAudioSession(); UFUNCTION(BlueprintCallable, Category = "Interaction") - void StopAudioSession() const; + void StopAudioSession(); UFUNCTION(BlueprintCallable, Category = "Interaction") void CancelCurrentInteraction(); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index db5dd946..b828e0d6 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -27,13 +27,25 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject { GENERATED_BODY() public: - //UObject + // UObject virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual bool IsSupportedForNetworking() const override { return true; } virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override; virtual bool CallRemoteFunction(UFunction* Function, void* Parms, struct FOutParmRec* OutParms, FFrame* Stack) override; - //~UObject + // ~UObject + +public: + UFUNCTION(BlueprintCallable, Category = "Message") + void BroadcastTextMessage(const FString& Text); + UFUNCTION(BlueprintCallable, Category = "Trigger") + void BroadcastTrigger(const FString& Name, const TMap& Params); + UFUNCTION(BlueprintCallable, Category = "Audio") + void BroadcastAudioSessionStart(); + UFUNCTION(BlueprintCallable, Category = "Audio") + void BroadcastAudioSessionStop(); + UFUNCTION(BlueprintCallable, Category = "Audio") + void BroadcastSoundMessage(const TArray& Input, const TArray& Output); public: UFUNCTION(BlueprintCallable, Category = "Inworld|Player") diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index 864e5c17..f040f53f 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -69,7 +69,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, UFUNCTION(BlueprintCallable, Category = "Interaction") bool IsInteracting() { return InworldPlayer->GetTargetCharacters().Num() > 0; } - UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Interaction") + UFUNCTION(BlueprintCallable, Category = "Interaction") void SendTextMessageToTarget(const FString& Message); UFUNCTION(BlueprintCallable, Category = "Interaction", meta = (AutoCreateRefTerm = "Params")) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index b04fc190..da59be73 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -39,13 +39,13 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject { GENERATED_BODY() public: - //UObject + // UObject virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual bool IsSupportedForNetworking() const override { return true; } virtual int32 GetFunctionCallspace(UFunction* Function, FFrame* Stack) override; virtual bool CallRemoteFunction(UFunction* Function, void* Parms, struct FOutParmRec* OutParms, FFrame* Stack) override; - //~UObject + // ~UObject public: UInworldSession(); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h index 72dd0247..dc4cafda 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h @@ -32,6 +32,7 @@ class INWORLDAIINTEGRATION_API AInworldSessionActor : public AActor, public IInw protected: virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; From 993ae6a7b7ee68ad898ec4d9e6adfd3ae3543733 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 19:36:29 -0400 Subject: [PATCH 12/45] fix reps --- .../InworldAIClient/Private/InworldClient.cpp | 12 +++++++ .../Private/InworldApi.cpp | 31 ++++++++++--------- .../Private/InworldCharacter.cpp | 16 +++++----- .../Private/InworldPlayer.cpp | 12 +++---- .../InworldPlayerAudioCaptureComponent.cpp | 2 +- .../Private/InworldPlayerComponent.cpp | 2 +- .../InworldPlayerTargetingComponent.cpp | 10 +----- .../Private/InworldSession.cpp | 11 +++++-- .../Private/InworldSessionActor.cpp | 1 + .../Public/InworldPlayer.h | 2 +- 10 files changed, 57 insertions(+), 42 deletions(-) diff --git a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp index 188246ff..d7cb27a7 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp @@ -90,14 +90,26 @@ UInworldClient::UInworldClient() AsyncTask(ENamedThreads::GameThread, [this, ConnectionState]() { + if (bIsBeingDestroyed) + { + return; + } OnConnectionStateChangedDelegateNative.Broadcast(static_cast(ConnectionState)); OnConnectionStateChangedDelegate.Broadcast(static_cast(ConnectionState)); }); }, [this](std::shared_ptr Packet) { + if (bIsBeingDestroyed) + { + return; + } AsyncTask(ENamedThreads::GameThread, [this, Packet]() { + if (bIsBeingDestroyed) + { + return; + } InworldPacketTranslator PacketTranslator; Packet->Accept(PacketTranslator); TSharedPtr ReceivedPacket = PacketTranslator.GetPacket(); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 50adcd3f..e72035df 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -29,20 +29,23 @@ UInworldApiSubsystem::UInworldApiSubsystem() void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) { - InworldSession = Session; - InworldSession->OnLoaded().AddLambda( - [this](bool bLoaded) -> void - { - OnCharactersInitialized.Broadcast(bLoaded); - } - ); - OnCharactersInitialized.Broadcast(InworldSession->IsLoaded()); - InworldSession->OnConnectionStateChanged().AddLambda( - [this](EInworldConnectionState ConnectionState) -> void - { - OnConnectionStateChanged.Broadcast(ConnectionState); - } - ); + if (InworldSession != Session) + { + InworldSession = Session; + InworldSession->OnLoaded().AddLambda( + [this](bool bLoaded) -> void + { + OnCharactersInitialized.Broadcast(bLoaded); + } + ); + OnCharactersInitialized.Broadcast(InworldSession->IsLoaded()); + InworldSession->OnConnectionStateChanged().AddLambda( + [this](EInworldConnectionState ConnectionState) -> void + { + OnConnectionStateChanged.Broadcast(ConnectionState); + } + ); + } } void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index 0316bdda..2371ed17 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -53,43 +53,43 @@ bool UInworldCharacter::CallRemoteFunction(UFunction* Function, void* Parms, FOu void UInworldCharacter::SendTextMessage(const FString& Text) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->SendTextMessage(this, Text); } void UInworldCharacter::SendTrigger(const FString& Name, const TMap& Params) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->SendTrigger(this, Name, Params); } void UInworldCharacter::SendNarrationEvent(const FString& Content) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->SendNarrationEvent(this, Content); } void UInworldCharacter::SendAudioSessionStart() { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->SendAudioSessionStart(this); } void UInworldCharacter::SendAudioSessionStop() { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->SendAudioSessionStop(this); } void UInworldCharacter::SendSoundMessage(const TArray& InputData, const TArray& OutputData) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->SendSoundMessage(this, InputData, OutputData); } void UInworldCharacter::CancelResponse(const FString& InteractionId, const TArray& UtteranceIds) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->CancelResponse(this, InteractionId, UtteranceIds); } @@ -104,7 +104,7 @@ TScriptInterface UInworldCharacter::GetInworldC void UInworldCharacter::SetBrainName(const FString& BrainName) { - UInworldSession* Session = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldCharacterOwner().GetObject()); + UInworldSession* Session = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); if (!AgentInfo.BrainName.IsEmpty()) { if (Session != nullptr) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index 6480f232..b18b7f5d 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -49,33 +49,33 @@ bool UInworldPlayer::CallRemoteFunction(UFunction* Function, void* Parms, FOutPa return false; } -void UInworldPlayer::BroadcastTextMessage(const FString& Text) +void UInworldPlayer::BroadcastTextMessage_Implementation(const FString& Text) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->BroadcastTextMessage(GetTargetCharacters(), Text); } void UInworldPlayer::BroadcastTrigger(const FString& Name, const TMap& Params) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->BroadcastTrigger(GetTargetCharacters(), Name, Params); } void UInworldPlayer::BroadcastAudioSessionStart() { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->BroadcastAudioSessionStart(GetTargetCharacters()); } void UInworldPlayer::BroadcastAudioSessionStop() { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->BroadcastAudioSessionStop(GetTargetCharacters()); } void UInworldPlayer::BroadcastSoundMessage(const TArray& Input, const TArray& Output) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetInworldPlayerOwner().GetObject()); + UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); InworldSession->BroadcastSoundMessage(GetTargetCharacters(), Input, Output); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index fdc5b279..f096dd3c 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -174,7 +174,7 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() ); PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); - InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()); + InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetOuter()); OnSessionConnectionStateChanged = InworldSession->OnConnectionStateChanged().AddLambda( [this](EInworldConnectionState ConnectionState) -> void { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index defadd01..334a0728 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -108,7 +108,7 @@ TArray UInworldPlayerComponent::GetTargetInworldCha TArray InworldCharacterComponents; for (UInworldCharacter* Character : InworldPlayer->GetTargetCharacters()) { - UInworldCharacterComponent* InworldCharacterComponent = Cast(Character->GetInworldCharacterOwner().GetObject()); + UInworldCharacterComponent* InworldCharacterComponent = Cast(Character->GetOuter()); if (InworldCharacterComponent) { InworldCharacterComponents.Add(InworldCharacterComponent); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 99549aa2..c1e4af8b 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -41,14 +41,6 @@ void UInworldPlayerTargetingComponent::TickComponent(float DeltaTime, enum ELeve void UInworldPlayerTargetingComponent::UpdateTargetCharacters() { - //TODO: FIX - // prevent starting another audio session in multiplayer - //const auto* CurrentAudioSessionOwner = InworldSubsystem->GetAudioSessionOwner(); - //if (CurrentAudioSessionOwner && CurrentAudioSessionOwner != Player->GetOwner()) - //{ - // return; - //} - // clear all targets if just switched from multiple targeting if (!bMultipleTargets && TargetCharacters.Num() > 1) { @@ -73,7 +65,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() } } - UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetInworldPlayerOwner().GetObject()); + UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetOuter()); if (!InworldSession) { return; diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 009296d7..f4a3b9c7 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -55,13 +55,20 @@ void UInworldSession::Destroy() { UnregisterCharacter(RegisteredCharacter); } - if (InworldClient) + if (IsValid(InworldClient)) { +#if ENGINE_MAJOR_VERSION == 5 + InworldClient->MarkAsGarbage(); +#endif + +#if ENGINE_MAJOR_VERSION == 4 + InworldClient->MarkPendingKill(); +#endif InworldClient->OnPacketReceived().Remove(OnClientPacketReceivedHandle); InworldClient->OnConnectionStateChanged().Remove(OnClientConnectionStateChangedHandle); InworldClient->OnPerceivedLatency().Remove(OnClientPerceivedLatencyHandle); - InworldClient = nullptr; } + InworldClient = nullptr; } void UInworldSession::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp index 4ec37bb5..f4d96603 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -38,6 +38,7 @@ void AInworldSessionActor::PreInitializeComponents() void AInworldSessionActor::BeginPlay() { Super::BeginPlay(); + OnRep_InworldSession(); } void AInworldSessionActor::EndPlay(const EEndPlayReason::Type EndPlayReason) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index b828e0d6..b737f98b 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -36,7 +36,7 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject // ~UObject public: - UFUNCTION(BlueprintCallable, Category = "Message") + UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Message") void BroadcastTextMessage(const FString& Text); UFUNCTION(BlueprintCallable, Category = "Trigger") void BroadcastTrigger(const FString& Name, const TMap& Params); From e0692423f01a8f0320720b008c6d24236d4bce00 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 19:47:35 -0400 Subject: [PATCH 13/45] auto-reconnect --- .../Private/InworldSession.cpp | 18 ++++++++++++++++++ .../InworldAIIntegration/Public/InworldApi.h | 10 ---------- .../Public/InworldSession.h | 7 +++++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index f4a3b9c7..59a3a742 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -37,6 +37,24 @@ void UInworldSession::Init() { OnConnectionStateChangedDelegateNative.Broadcast(ConnectionState); OnConnectionStateChangedDelegate.Broadcast(ConnectionState); + + if (ConnectionState == EInworldConnectionState::Connected) + { + CurrentRetryConnectionTime = 1.f; + } + + if (ConnectionState == EInworldConnectionState::Disconnected) + { + if (CurrentRetryConnectionTime == 0.f) + { + ResumeSession(); + } + else + { + GetWorld()->GetTimerManager().SetTimer(RetryConnectionTimerHandle, this, &UInworldSession::ResumeSession, CurrentRetryConnectionTime); + } + CurrentRetryConnectionTime += FMath::Min(CurrentRetryConnectionTime + RetryConnectionIntervalTime, MaxRetryConnectionTime); + } } ); OnClientPerceivedLatencyHandle = InworldClient->OnPerceivedLatency().AddLambda( diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index cd962a0b..71140f09 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -223,22 +223,12 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem FCustomTrigger OnCustomTrigger; private: - UPROPERTY(EditAnywhere, config, Category = "Connection") - float RetryConnectionIntervalTime = 0.25f; - - UPROPERTY(EditAnywhere, config, Category = "Connection") - float MaxRetryConnectionTime = 5.0f; - - float CurrentRetryConnectionTime = 1.0f; - UPROPERTY() UInworldAudioRepl* AudioRepl; UPROPERTY() const AActor* AudioSessionOwner = nullptr; - FTimerHandle RetryConnectionTimerHandle; - UPROPERTY() UInworldSession* InworldSession; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index da59be73..01fc7f09 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -227,6 +227,13 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject FOnInworldEmotionEventNative OnInworldEmotionEventDelegateNative; FOnInworldCustomEventNative OnInworldCustomEventDelegateNative; +private: + float RetryConnectionIntervalTime = 0.25f; + float MaxRetryConnectionTime = 5.0f; + float CurrentRetryConnectionTime = 1.0f; + + FTimerHandle RetryConnectionTimerHandle; + // Temp: Hack until deprecated functions are removed friend class UInworldApiSubsystem; }; From f90131dd6ba8c4fd57963a59af8e42f7d1d7d814 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 20:14:24 -0400 Subject: [PATCH 14/45] copyright headers --- .../InworldAIIntegration/Private/InworldSessionActor.cpp | 7 ++++++- .../InworldAIIntegration/Public/InworldSessionActor.h | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp index f4d96603..98b3c849 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -1,4 +1,9 @@ -// Fill out your copyright notice in the Description page of Project Settings. +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ #include "InworldSessionActor.h" diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h index dc4cafda..5b21372e 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h @@ -1,4 +1,9 @@ -// Fill out your copyright notice in the Description page of Project Settings. +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ #pragma once From 3a892a6e600e1b329ab7105641ca97852a72dedb Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 20:25:26 -0400 Subject: [PATCH 15/45] add session created event on actor --- .../InworldAIIntegration/Private/InworldSessionActor.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp index 98b3c849..c0f7fb4a 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp @@ -92,6 +92,11 @@ bool AInworldSessionActor::ReplicateSubobjects(UActorChannel* Channel, FOutBunch void AInworldSessionActor::OnRep_InworldSession() { - GetWorld()->GetSubsystem()->SetInworldSession(InworldSession); + if (InworldSession) + { + GetWorld()->GetSubsystem()->SetInworldSession(InworldSession); + OnSessionCreatedDelegateNative.Broadcast(); + OnSessionCreatedDelegate.Broadcast(); + } } From e854a6468383f630c56709bd1c9c8ab850926746 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 22:11:37 -0400 Subject: [PATCH 16/45] missing headers --- InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h | 2 ++ InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h | 1 + InworldAI/Source/InworldAIIntegration/Public/InworldSession.h | 2 ++ 3 files changed, 5 insertions(+) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index 4f3f95dd..6f420525 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -8,7 +8,9 @@ #pragma once #include "CoreMinimal.h" +#include "UObject/Interface.h" #include "UObject/NoExportTypes.h" +#include "GameFramework/Actor.h" #include "InworldTypes.h" #include "InworldCharacter.generated.h" diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index b737f98b..d4576e80 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -10,6 +10,7 @@ #include "CoreMinimal.h" #include "UObject/Interface.h" #include "UObject/NoExportTypes.h" +#include "GameFramework/Actor.h" #include "InworldPlayer.generated.h" class UInworldSession; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index 01fc7f09..f8604517 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -8,7 +8,9 @@ #pragma once #include "CoreMinimal.h" +#include "UObject/Interface.h" #include "UObject/NoExportTypes.h" +#include "GameFramework/Actor.h" #include "InworldClient.h" #include "InworldTypes.h" #include "InworldPackets.h" From 89f4a6658fe995917ec88b5de7c92e8f249ddb40 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 22:34:37 -0400 Subject: [PATCH 17/45] 4.27 fux --- InworldAI/Source/InworldAIClient/Public/InworldClient.h | 1 + InworldAI/Source/InworldAIIntegration/Public/InworldApi.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIClient/Public/InworldClient.h b/InworldAI/Source/InworldAIClient/Public/InworldClient.h index da0a0960..ce6f81cc 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldClient.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldClient.h @@ -8,6 +8,7 @@ #pragma once #include "InworldEnums.h" +#include "InworldTypes.h" #include "InworldPackets.h" #if !UE_BUILD_SHIPPING diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index 71140f09..63b4adfc 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -93,7 +93,7 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem /** * Load new characters */ - UFUNCTION(BlueprintCallable, Category = "Inworld", meta = (DeprecatedFunction, DeprecationMessage = "Please use GetInworldSession::LoadCharacters node")) + UFUNCTION(BlueprintCallable, Category = "Inworld") void LoadCharacters(const TArray& Names); /** From ff4f62d24a6524083a014862afbd418b8cf69908 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 22:37:20 -0400 Subject: [PATCH 18/45] Android build fix --- InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index e72035df..6fde509a 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -191,7 +191,7 @@ void UInworldApiSubsystem::SendTextMessageMultiAgent(const TArray& Agen return; } - InworldSession->InworldClient->SendTextMessage(AgentIds, Text).Packet; + InworldSession->InworldClient->SendTextMessage(AgentIds, Text); } void UInworldApiSubsystem::SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params) From e51acfba8465f3891c60bc6e7b3049f43b831652 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 25 Apr 2024 23:32:00 -0400 Subject: [PATCH 19/45] android fix --- InworldAI/Source/InworldAIClient/Private/InworldClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp index d7cb27a7..523456c0 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp @@ -29,6 +29,7 @@ THIRD_PARTY_INCLUDES_END #include #include "Misc/Paths.h" +#include "Misc/App.h" const FString DefaultTargetUrl = "api-engine.inworld.ai:443"; From a769df9dee93974c755bcaa127d072d49bfb6349 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Fri, 26 Apr 2024 00:18:39 -0400 Subject: [PATCH 20/45] 4.27 fixes --- InworldAI/Source/InworldAIClient/Public/InworldClient.h | 2 +- InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp | 2 +- InworldAI/Source/InworldAIIntegration/Public/InworldSession.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/InworldAI/Source/InworldAIClient/Public/InworldClient.h b/InworldAI/Source/InworldAIClient/Public/InworldClient.h index ce6f81cc..ac74c550 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldClient.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldClient.h @@ -41,7 +41,7 @@ class INWORLDAICLIENT_API UInworldClient : public UObject ~UInworldClient(); UFUNCTION(BlueprintCallable, Category = "Inworld|Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) - void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save = FInworldSave(), const FInworldSessionToken& SessionToken = FInworldSessionToken(), const FInworldCapabilitySet& CapabilitySet = FInworldCapabilitySet()); + void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet); UFUNCTION(BlueprintCallable, Category = "Inworld|Session") void StopSession(); UFUNCTION(BlueprintCallable, Category = "Inworld|Session") diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 6fde509a..704e036a 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -83,7 +83,7 @@ void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& Environment.AuthUrl = AuthUrlOverride; Environment.TargetUrl = TargetUrlOverride; - InworldSession->InworldClient->StartSession(SceneName, PlayerProfile, Auth, FInworldSave(), SessionToken); + InworldSession->InworldClient->StartSession(SceneName, PlayerProfile, Auth, FInworldSave(), SessionToken, {}); } void UInworldApiSubsystem::StartSession_V2(const FString& SceneName, const FInworldPlayerProfile& PlayerProfile, const FInworldCapabilitySet& Capabilities, const FInworldAuth& Auth, const FInworldSessionToken& SessionToken, const FInworldEnvironment& Environment, FString UniqueUserIdOverride, FInworldSave SavedSessionState) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index f8604517..a2be1943 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -67,7 +67,7 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject const TArray& GetRegisteredCharacters() const { return RegisteredCharacters; } UFUNCTION(BlueprintCallable, Category = "Inworld|Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) - void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save = FInworldSave(), const FInworldSessionToken& SessionToken = FInworldSessionToken(), const FInworldCapabilitySet& CapabilitySet = FInworldCapabilitySet()); + void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet); UFUNCTION(BlueprintCallable, Category = "Inworld|Session") void StopSession(); UFUNCTION(BlueprintCallable, Category = "Inworld|Session") From 3ee26df3c71f1ac57f81124c9e2c81b2f362c10a Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Fri, 26 Apr 2024 12:54:50 -0400 Subject: [PATCH 21/45] fix setting unpossessed target --- InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp | 5 +++++ .../Private/InworldCharacterComponent.cpp | 2 +- .../Source/InworldAIIntegration/Private/InworldPlayer.cpp | 4 ++-- .../Private/InworldPlayerTargetingComponent.cpp | 5 +++++ InworldAI/Source/InworldAIIntegration/Public/InworldApi.h | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 34240765..401f0f16 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -272,6 +272,11 @@ void UInworldApiSubsystem::ChangeScene(const FString& SceneId) InworldSession->InworldClient->SendChangeSceneEvent(SceneId); } +EInworldConnectionState UInworldApiSubsystem::GetConnectionState() const +{ + return InworldSession->GetConnectionState(); +} + void UInworldApiSubsystem::GetConnectionError(FString& Message, int32& Code) { InworldSession->InworldClient->GetConnectionError(Message, Code); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 86b9b65c..5373af9a 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -178,7 +178,7 @@ bool UInworldCharacterComponent::ReplicateSubobjects(UActorChannel* Channel, FOu void UInworldCharacterComponent::SetBrainName(const FString& Name) { - InworldCharacter->SetBrainName(BrainName); + InworldCharacter->SetBrainName(Name); } UInworldCharacterPlayback* UInworldCharacterComponent::GetPlayback(TSubclassOf Class) const diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index b18b7f5d..d2b4aac2 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -90,7 +90,7 @@ TScriptInterface UInworldPlayer::GetInworldPlayerO void UInworldPlayer::AddTargetCharacter(UInworldCharacter* TargetCharacter) { - if (TargetCharacter->GetTargetPlayer() == nullptr) + if (TargetCharacter && TargetCharacter->IsPossessed() && TargetCharacter->GetTargetPlayer() == nullptr) { TargetCharacter->SetTargetPlayer(this); TargetCharacters.AddUnique(TargetCharacter); @@ -104,7 +104,7 @@ void UInworldPlayer::AddTargetCharacter(UInworldCharacter* TargetCharacter) void UInworldPlayer::RemoveTargetCharacter(UInworldCharacter* TargetCharacter) { - if (TargetCharacter->GetTargetPlayer() == this) + if (TargetCharacter && TargetCharacter->GetTargetPlayer() == this) { TargetCharacter->ClearTargetPlayer(); TargetCharacters.RemoveSingle(TargetCharacter); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index c1e4af8b..01a1e8ae 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -75,6 +75,11 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() float BestTargetDot = -1.f; for (UInworldCharacter* Character : Characters) { + if (!Character->IsPossessed()) + { + continue; + } + UInworldPlayer* Player = Character->GetTargetPlayer(); if (Player && Player != InworldPlayer) { diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index 63b4adfc..aa5f06a5 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -180,7 +180,7 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem /** Get current connection state */ UFUNCTION(BlueprintCallable, Category = "Connection") - EInworldConnectionState GetConnectionState() const { return InworldSession->GetConnectionState(); } + EInworldConnectionState GetConnectionState() const; /** Get connection error message and code from previous Disconnect */ UFUNCTION(BlueprintCallable, Category = "Inworld") From 7e68c6106870a9d71a2386cdbc0a37cebc5c4370 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Fri, 26 Apr 2024 12:55:42 -0400 Subject: [PATCH 22/45] add missing header --- .../Source/InworldAIIntegration/Private/InworldSession.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 59a3a742..b48a28a0 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -10,6 +10,8 @@ #include "InworldCharacter.h" #include "InworldClient.h" +#include "InworldAIIntegrationModule.h" + #include "Engine/BlueprintGeneratedClass.h" #include "Engine/NetDriver.h" #include "Engine/Engine.h" From 6410e1c7d83031cf757b2c7ecd72f3f1cf85c3f2 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Fri, 26 Apr 2024 14:53:10 -0400 Subject: [PATCH 23/45] register fixes --- .../BP_InworldSessionController.uasset | Bin 80366 -> 82347 bytes .../Dialog/BP_DialogMapCharacter.uasset | Bin 17017 -> 16747 bytes .../Content/Dialog/BP_DialogMapPawn.uasset | Bin 70705 -> 133207 bytes InworldAI/Content/Dialog/DialogMap.umap | Bin 16357 -> 17845 bytes .../Content/Dialog/WBP_DialogWidget.uasset | Bin 276079 -> 273086 bytes .../StudioWidget/EUW_InworldStudio.uasset | Bin 899752 -> 902850 bytes .../Private/InworldCharacterComponent.cpp | 60 +++++++------ .../InworldPlayerAudioCaptureComponent.cpp | 2 +- .../Private/InworldPlayerComponent.cpp | 28 +++---- .../InworldPlayerTargetingComponent.cpp | 2 +- .../Private/InworldSessionComponent.cpp | 79 ++++++++++++++++++ .../Public/InworldCharacterComponent.h | 2 + .../Public/InworldPlayerComponent.h | 5 +- .../Public/InworldSessionComponent.h | 34 ++++++++ 14 files changed, 169 insertions(+), 43 deletions(-) create mode 100644 InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp create mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h diff --git a/InworldAI/Content/BP_InworldSessionController.uasset b/InworldAI/Content/BP_InworldSessionController.uasset index 896217e8a4929d5f4ecf4b1f0b418b6d2c0604e7..f820e35668fb3b22eac55e6d2072782fe9ee6bac 100644 GIT binary patch literal 82347 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 delta 20398 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 diff --git a/InworldAI/Content/Dialog/BP_DialogMapCharacter.uasset b/InworldAI/Content/Dialog/BP_DialogMapCharacter.uasset index 377774751af2370eeb3bbd54f479babda0860d7b..646421e3e2cc1ac83e085fd0238045ab0dca4937 100644 GIT binary patch delta 845 zcmZ8fUr1A76hGgcb2Inn-fj18E)%njr5kNalWiL98X~Eza_FEy=^=v+rf8y4Jruqb zq@9b1j4AqRkY5xO&gud`TP5E&bc3_xWvBRV9TFu zsW5;Z01{K#i{$EHab-IaniK(KN?XhTYYG6PxX%eNNIFTH9}5M~6j#;9OAoW|!(T>m zoVnN{&a-4wp5RL=@oS_+lF~NWOdV4&Y;x5@=QG!in?gHgOcw1{eNxX3aRggTQRb@x z4YrAa{=~$XI&wZ} z(lB1L$+$-8^V(FzZkt0GiB=h2wAdX&X*ZSek4;pjD!rkdyr~*D#`b!q?V>VGW&X%U z(q$fyIR8;z6XkNH3Ih26HzW^w@V7lJyga_wEawoFc|vxZ?anJ!DDPyiyifyMtF!cY zwzCOe*p8rE78TCWk@9UmlX7vKD9@k%@D+8|6CBkh6^CWBGBg+jomc|xOl-)4C#U3=Bj1c0Oe v6?1_1kKM&qNz}HxhZ(L!PS$;+3&vPvNP87&HR4;PXE@*a&gDOI&dmR*hyJ`wdq3Dl z-Gs1&kVv$-5sj8~BQ8=H-s31nricl#og>7GHpf876M+zlywXNUHEKI*IBU-SIi4@M zxj1rr->q>y)X*f_4IQ*9c?Q#MB}%6?SVkF@-qV=YYsO$jb4N6GvZ3^NU97IYwJ}D< z-)K|uE&n7!Z4FIPvg>KmlGGnp#b%`br>3^NEK++YR9O)!373)1nTjEp+fqqWz^50X zH;#oS{Q~qD!t56u;tbG0B0MtOg&W39IA#)I-k_&lYLthM#!MPjygx>so>o}I#KU8w zNL%5&$$>bi;4=k(D7cMt&~_;2da1~D^uZOA=IiUqB8BX(lp%as<{Z^-l4=7ViS?xmChO|k2 zUE=1n2212=W>IBH3vN0ckD-leU1)8^h>*_Aue%R~*P0p|0WohY+_8!53A}8B(kojN zW97duFKcj4`PoSl6zh@>q~w~Z1ui-r8cMRDWrrOuIE!hv!e*S=)G0H`<62@g`6Lhe zTz0dIoF!?*jar17Pux(STSz^ab4cU42U$m-x@AOJ20{LU9@SY59-$B{7|8i%>K_z) zu8(;KhVPgCzBaa3ElXFeR<&emGVJ$DhYO}DT=JG`zv68Lmv_H3;oYu-$siBE0xw}U Jz{A_%mA@l&_qG54 diff --git a/InworldAI/Content/Dialog/BP_DialogMapPawn.uasset b/InworldAI/Content/Dialog/BP_DialogMapPawn.uasset index c821cf663400a4e5a7eb8463485170d1bcc1dff2..4f3d9aa58704bf78d9bdf12b225109ff3e5ddb42 100644 GIT binary patch literal 133207 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 z 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 G<^cfx3}s^g literal 70705 zcmeHQ349bq*6$He1VKgRP}B*E9C8FmAmBxA!j(Y6AqbgC(jkM%OqiJvKt)hgQ1L(% zS3D5J3s+H4@ZiwZ{XFnk6)zM#Sw-DN*IiU}`QE>(-gNg&&!h(ey8GM8ucx|Sy{cF5 z)qAgARo7&my}bLKKknPN&(lQHS{$Zn-%yU!g07G1zUbB^Z^g&c-#q4yT_5&1?O1}H z{p{ocdxv~}`0jbyK>+srtB#`l5oX0@i73$?Y2p&$vJDh?K=|T(;KRgJ7Tc zeQ$NE!UdbtYKW6w3SL zrDhLI9gvYWFe{^fZhHE_^vu*g=^1&s85!yQ`sDN_6q(MT>~S|yrCe{TX&X{CjoQ#A z^`mFH=F)Yd9lv5>a1tZbG z?gRH%6A1T6X>{Maz+WE-R##*e^v>~ls{>PdXBCyoyAj^nB5%FFS2RF7dd<2fEvas1 zc{mWvuJ(pP+L%6fZEg)vMMX(qtWU464Ftp5OaFIi#&H5V-Rm#cD~f#n9ABum+B;L5 z-R|#49Eqap>XCs8J*4eB;jdYT0}u>Sar378{w&(VQ&BKbs|Uj~wSv{3`Hm)>GO87* z&mj?oeF49=@4MDtw*xr4${X~ShxK5n!0!taJHA-5^7&mYdO^HpfCA93QC4rXY9pE~3BR*wnkh5qW9+La$K8-<=msuj-+ zh4q@T)MGF*H+s%IpAjbw*e#`{d$B zMTN1xP@NE9cA%z~%*7wpR$bNq1JRM0VO`tx>GhjMN9ZBak)0!ZZf;LaW_zovA<9xQ znx*-AxU_)y)b2WN*`AK(^6a4Q4eO<{cVoRIP3?ts)t$PSai}(pw@|iFVWrTw(!#p1 z1Za~!{vX6!9aDj9<;PSe&;odqT3$_6DY1L3yI;dpm%S3?88vhZ0hHf zKyaqEXZGS3z&Ha&dTVs;y8h#jI>rPnCiVCEr)b9?d&+BYS`p3Ew!VMMxzO`+VK?FW z(6e}wRurzEaU)zNi5!Zmz1-oMyP)rpA&_W&{{62p814wTM6V&EqCt84!A{RXo3rae z;XsYV&Taef(=b8_!>B+rM6bOMUHcvA<>-~(y6UhtcVFOKxOVlNAN1B%!8*0IpYEJ) zDkv`3{rc!YAgn!e?VZhFTdGE+K-3ykwBZYgu7V783c9yv?`_uu0LxW?A){rx5)e_O zl(KDuz#?Ok+Uh}_e2CVq^^k6YqVQI3a#C(XxUYA9vKaj5_(*;*DR&>uw{gbn5+*#4 zV0_liJF_5@+zMYp&%bm=jB(Ir__ST zMZ}|pG=1(-DKPt(l0k!ts{-|Y?a}P#uYkkMC54<>6d-q@Ju<$fm_>6<#wX~%c1ed1 zF&jk}3>q{t5H=xe{hEev0$;h)sq1brR@%;=PJILlBVdNi?pyxJDj2RlLoe4Z-u26g z7<4?;(V+O2eEwi3)RE6)%JkqA418&f-+$j zwW*69-U@pYoe(~G`DL$67u4XOvx|PN0<|IJBbEL7Xzpn{?90ut-U9!KKwU^59w@(X z1k`@x?3=%bz83gv>%uf)XixtrfD-u2<$o(o#iWZdeY?%t6QG*x^~ZXHJ}*r* zLgmic*WyRh$?N&8(~N1+u-h_C>XNe|90@ekXZ90Mo(J2d5vr@!DNgc+ebaSeqP3l_@uD3x8WHkk z-!~tM&Vh5G5r288=_&>k1w!Ms7bea>%mg@J3+8>R!z-goNPF_%ORJ$lB53@f$qTKH zpof5P44OV{$v!BQ@)I1WWNurt3-e&1KQeZfkmP}uv(}v%zr3`R2cy_G#qSkE_{!MV zR-KZdiWng6flq#Y6$)z1j~6yS{CRX(4zkvJPOnPQVe6P5RkLV>s;5-_&#gW@8L}*_ z_tQkCH0|M)+rK=SfJNT&3%yfdC&m8T>I2H#g!=_2<(!00aEx-ajVgsq#?Z03!;j$vY=Ldz?fst^PPNCgSu-~yXRR@B7 zbF?w3)knfbh_FsYwo*vi+Rp0A&FKI|MSh5{P7{NirQcI4eI7|X84{0l|>;9ajkzu}24XswNXdUh=3wmj}Fyg1> z&%>}HjR@svwkUU!+YFVO5D^I19^UQ40(kxC__{PdcVy|<%+UpzS;KR+hiA_l0(tPP z!7-P1-15{Vu;1JYsYy)(YbOCwJxh;PI;^j@{@GhwL5*^)0Z^NT-R^^n$o1FNXk-6$ zML)?wP? zt;aMo1vU{Ch%9`xyE^X4#8TZ75Lt!u=87-+b%{nXM@Lrl=`F8#7-nl}(Tr{oPhI!x zFqo|c)hIsZga;499H4@(%ut9Xa~>k?-0;3r!8eCwYQ-!JbI+1{wt#O_nVd``a&C6l zfbQnnVi~QxN&eaI)x!w5wh_N+JBIAI36512$(SK@#e|a(wkjag5Q`OU>08argbW;ai* zYW;(Y7K@@-^ExWywx2{FM3LN1VdGg>QLq@=IYJM6bG%`%_W7K(H=zR~XtC=XPJR-u z4H3EsZ(Xn*73*lB{P`z9wbgT^(K~wFqr*moU6(ic`_r%^u@E*? zVMzOmQZOLE)+x5rSBI~~kVw~GEaq)(*a`FIqvyrh#ia;Zv_5aW`2sv5MGR`TSD|Ls zOc6ofF|)@VBBJ0uj2KT+Tz&s)STCkrr6{ewzGOOj6+Iu3>)X5H$kC96!u&aJ<$AcG zC@&S|wx@4d)&ceqg~h|+S~)fQdMZX*A~Wq}+J?MU-FsAy>^gOig(=dDgm;g;)jTRk zW{3BvD)*=ynH}C^s@$V;WOjIKRJljx$n5YQSLGg+BeTPMLX~?|j?4~kohtXJ9GM;7 zdR6XGIWjxECsnye<;d*to>Ju=l_Rsmds>xyRF2FJ?-^C@Q8}_`y#J%|y=>YE|!aK|X-ZsKp>JV>+4IaT8DTG9pZ6cJPIEf!_56-88n1x*$NkvW%9vzB&I`Ypk}G{J9ERS~FfR~1j@;8T?)$`a9Ho85l)bf0Pmi=Us={a_A))w7e#39WgmA<*Js8psog6Cw)7j@I`kz97$Y6)t#u zqnUizd5~!7CR*$_pWwh+l{v}c@%4`44Seyu2ELfbQ5>8*A);{XXnh69<9 z16sP0VfwqtP?5M!X@QQJ)@|Dwht^(`zJLw5bk@WB)m*u6N8`}?Ac_{;EYsSpbpF22 z8i&@;QM9lR!#Y1x@wH@EGkr?M;G+LbapyLzE0LEwXOBq5R>e zzcvo7e?-y3-XY6S3>-Z_c9>F3B_$C@2HT9~#lUd)%jdE?Of&Ll%L z|0jG<0!u{@CMADMgBI?LCsAzsVJE|#CR%9!ZdDU8+ZpP9<1tQJSI8=}qxHUt7Fzr> zUC1FrjzvFjBwAmXXn~IxO|*8>J<{%jNDHzAUrg(rV;e_?c6_lvWLnR(X&hRgn`8)n zX3@ptbq(DkEkCYtXhE$pPH;!K??e}99!?kF$RSVI94LZkl;e7q`guI%C(v~qU9ISX zJ{?2Xv2-0xS39~+rmF*8ZRl!G*C}+hrt4I?PNeH3y3h_{;Er^G4&F9`Hj&u3i7wo~ zLOJMeR5@VWFWhqiFKCPDp>6PnzM+q(k3OPL;0G}DALYP9-_Uo!&{y;m?E{AXp?nLq zfdu~02HFD*ZQvRF;~8z>8GV7AIL-$g?SS?s!h?)Zhi>;l9^e7}2EQy9+@lS&#WDgO z`ha@qALI#okTciAGk66J<`H({Y2hZpW+DE&9Z6X{VSLTt&75xMb z+Ckgk6YZH3`kz7kZ$TIOdKz7))76=-Yv^hyfgb8cUfl{wMjvI-eEnqiBWO`? zVZlapC3>S2o7FH%X5IB zh0YYv_XmP>vNuu^65{FFO;`t&R_i!@tyhS1vz2s&Fodc?-jQa-`A*wDV>qKkP)MLi zO>0?~#3#LMzwlC;-9;#z`9LESOdM_O!snsn$*W#yp^MP%k?LS7PP58WkPTFVQjV;v z8BJ%5eC0R`t&Zy9h%$yORhUhLG5Q{dI17kxjv&FFB8AyhUwmBwC9t+giTVbPI5vPn zn3w2YUbS}$ojs<1+oShI~UxD|?^Hzs+;Y;&;S>ja1PqaDPgft(2 zTS)7X-zz>P44+3vp4+Rtd~K>0&~$AmeP(Ml+H|c_o2G>Xv`!nTl@Yv5t0HKKY8<6% zjiRSo!UMF9a4WTNgQbV5x(C{a!&N(DwQ|*~SP09Zv1k>N4E#jRMV?zq(||OM;j6WR z3@6EiMZG$$M61wz)PkQ{a*^+ptqdXgm605Mw3`gvX*2?5G(&Ui9xYF+r&%ulXtz@B6k4hpv6|+hIgce|RP zSs(B2}wrJ2eP(HXntX)HB%%_s>xhM#bQj9HO zFPxZ%POAPuEnVxQ^(Rk~t@WiZ%chfF=8$d;qNf}x$)J)!bmfp9WYd*Tf5-=EX#&%* z^8@9T`)&4x#;7GO_JJlq7>95t$&eFyg{!IL}Kg0nH^x#YL;c#u*=u5k`qQ z1anR-gl8e{g}p{`X%TtQIXP8&ye zGKzN5%1Kg+k8xrn^@SrbDa9PcYn9OQSwy3u@{?3QScdiz<{1eQ4ZMOO(~gbA2kYlh zn$NSy;~_dm|Kq_qj^^_HjV4$=po{os3SA+(5Pd;s8Y(} zV~vE&?OIz+anvfuCWuO8w9#M08|m6W8ux6Pp$AbufV?T9l`Q&87ct2|@q`-L6w#y; zEp90>7i{zK=2feO8gr{$MH~8Oj7M_OD$hcQb`Z@YayB9#)-H2timCi`B~z&@uuVhX zqxFS-PW%yKTQ_51wGkUF&nEwA9bKNk6Gh+6A`ywb7vY(GJdNQf;i0FJR4^k~#n9{Q zNSinYGdOV3ZnKmY?*wQr?)v~$k}CE*W(XfyLs3>1J*U!qVe}@IxJMs77N}Vwy&J^v zkX&6_m!$ZpAZfs+F&lPOHH{HxkC2=OvW}V8eP($zRNl=I2dw8~g+~fSX%8Y9{3W(k z)?oPII+|5OiZiwZuFIOXGXYAK;Y?@f&9OapHKSk{QO`{&>(C$>@M8Yg7 ziIYMStrglAjn~(a1mew}@OL#d^I7+ITw-O~u!ZoPmqVQN5v%ufv6ja=e<1lPtnUZV z44O?8`qKKo58Y)GZW_&){RsoR0Qm%U5yXi_a-?A1&+JWYfCs~eV2`kO3{OKzYvgVr zX6uG|V~v%osXo+VU*ZJ&7yamxt0_RiM;cv&=;}$_*{!kSt)}`r>IvIxB5mQhgtf+g z#$!)3M%a;z+gvm*PUOLLC(@1`{fisYR@n7GRX28aV+clfkRu8lLBJ!y0?tykWbg3F zTI|&N*o&EG%Ge#>5oCMi!morV#y?B#G2lIfT)T}Vy#c=-Z7j{qMFhtVOP<*C;5kt4 zOQeXIoL78YFGbW#iPUsyXFHMyTUR#eb{^^30Q!TrrIW_zia%*fva~;y<&gfNw2z2R z0Z$i}b&ex?ypoo@IOG3ZM=f)tWu7PC&+TT4^BlFv^CEg_jSbmT=2Pnx~%65krf#M7}n#YJL?u>E0Qx(|8(JhDBk3NgE32E#sfAF{&? z%F_src@1ku%yM#$8$@OBuKAAW#m+dO#DB(&GmtFZfMUkMJd|dE#+z}5IO++Hsnani zaMUWt)8;Xi9uwYmCbcotQ9C>?h%4}Zpg&0)u?1G<`Q%mP`va`qv8wM+FpL^L2hr0& zD#wZ*5yvn^?@(#8j8u$wSYetIrci&3RTf98tj)4U3iTN8$FTPvCQpJ|&~2mM@FXRN zC?T(`YfwcOOB%x!F9^S-2*K&onXORT^(VvUFl9X9u3$p4_!`zQ_)GDtK z4VhSFQK(vp^{$z!#L0@=`C6ej$tZelo_JkR=nRU1u`SlbLeNQ7Sti6jJalzVS-SLap z0~gI8PGrO0BZu@mi}W0kR0e50bRKUa<<1}0CmBNfQJO{CpF?_&y+EvR(rCn8v~F`k z&lp8x7kR9snylwo4P&MZknPL&?$*vN=X$B22Oj(9oWkt{e$Gjrw_&Thwu{M}W7&v#}BI}giDzTT~xeWaHsSfrjMhQyt^qPy>bJ7m` zX!B|?mJ9d_*co;uvD(s2QCU~o#fP>XikG*^1-X!LsEtJa9GZu}#A9vO3*+39&rus3C1w%!)TC-42DmV(8d!-}CshNMR^zA!>wUS{ zzp4@I3c0_+J`QnQ!!l*BP);!d-u>i~M&KMS-V?KqyGW~LTZRu}y|T`&!wD0+7{)m@ zhM3w&=ax`}QPT8u3EKRedV&xfjM1i#f>jta{5c6dS?Z~Im$BG$yLw&_MTE>Lf4Z?ea zd@6-rKxeS?539gmVjtH=VZkUu%&|ZF{8+4pONS^iO7)7rl55-E9 zX;^tQ?`yiq3pj~C`SO?;a5%wX{X*}dRMXVd;`Dn~USSeyhE=}kO-UC5{1`@4H z9MR+V(T4pQt4Cv>2|Mk6ns*RCaMTPdZg})Ldaz2yx-0L}E_Kuv&u`YY%u=@N=Nw0E zI~l>bj#}b91^LzttELdGo3NI$JFjq=qc&M9`YC(OCSQ;v<`s@au(Na=(L6^K48I?HhT{rHEpQ(j>XDsJT&XBX4gSyY zF+A@##IH-c%8~q7r|_l(@3F9>k9Pp+q$`MS5xpWlfrr6+0PIh}AN8ja%vkVFcmwUy z<~yRtk*u}<*r|`zfCY|PcVlcztlnx@)Y`TZHK@2Nr8+egxlcI zwk%aAaC9$M#bJQ}+ljkyM0yF}%5&keo z;SDcN$ieGEhY
d7N5f(FS`B1;uLW3Q9_PI4#TIR=j2dBVO^qO#j#=<~>$&%v6% zTk4|!F(UQT@bq|#Z1=r>#LIZIj1$|_X@?1OB_L>zzi02F|C1uybB29~!cIJ+vj2K1l3}2O5>Q^zKIL1N%07U#)~Bfh%_Jz!}zZN8`Xg$-1sE z?+Rp*9^1<;VRm;!c48OBr)^)gISLS1ej`E!Zq!=pw1jpzJ zO9MMbEHyc@7(d9MVTofc$awoN@qXmzB%ma2>B&?s%S7=vSWc2VK6q3;{tpAt-Q#ETGQ^krumMV{O@>D@f>V5K5 z4P8i<*H{TV=hYaAhN#9`7j{x5zieHY;U&cIXX%kq#2Im^#diJ-D|N1$$hz*_RIxL~Ft#qNH5t|rg;?#vIz-k^ ztX+o29ZK!$AJOV~Gbn5Gf3EMwwN(C)%i4+b94BNYR^xcl0Ve%Ti@NIijl+<`ZVEZc)8 zA*;6G9eFg(#+?K3CN`SF{*Qb7Jqo*#XRR?tp66@x$g@T#o&yF(^cN=_W%PtSQPw1; zf%nnOZ|v-BKk_&$$90k&dHjb4uA7`i9@q-R=y5|-OvH-xD|XkkCh1f!rmLl&$;uPUZLeiskG_1NI9}&7*;Pz^tR;Y_@Z{ zqX(N~OLhK^;y~7gpvZop;ay%kX-OM4OAGJJV`XK$NlENkP-f`{-dD@jks+1Fn3LrjL9^Z1y)%HuHLj0wx^~B$WcZ^09*=Kbu^mX%o}4$Z(uH&l zzss|>*%wQ%fp>o#ks14}sLjy*^V&xI#&ev#*On20ocE*-z!%%a8wb~Go8J&0TxnUy z=|J=&Eiz|086(K}V65seT9~s8?{#oz5cy8qp!UBR#C#USkV|9CAP2wq&(nvrkRdb0kC6E;dePe4Nel{~I5iQj)fVxsg`|PCP7Z&$=&S zoU7qk5G!b&m(43ZV-`+qKd5h5Rif2P;?rp6m3JDonRw;R6cev#l3BZ0CFRtHj99hd z@vu^W+?=h;fSJr1%x=_KYs{mLdl~1*`4MrBIU@hPd(Hiq{lOpI1Bs$wZ)}mtYn5^4 zs&QXfm=W9XEz(lUDz<1|)cPx5>4^#9W-x#w@4H4c_eO%nb`dLNv!<{c#L z<;uv#y5kBs`%I2(_*u?8vH0vc&05Od(5j_|Km2dd9;~0O(GI~xnPLb^|Z6k7Nh&Dz> z{J?+wpV zz?hn6P{HM@kbkipzpjqN$bvp-4F;4_LPY#tIeudsi4pO8-AEH(q`0SF;sy3f{bn5BzZ>ZiJx3{lu=@IGerJ`?!@VtS(lvaAM;#)TiXM*^uFz0zA(jV}qx z=cWXeee@7Sq#dT_Mk^S4v7gO-Y-+Cifj764np3TapN>CQJwSfCx`#Y#)jgPQ+I*h2 zo9bmL7&zhN;Ty^^9&^<*j|1u>1!NZc=}{og@mQx|JSq___&4>UR28y&Dv3g-FWkzX zX~(S6iY{m`h8}v2U$}?;VoW>Gg&%syly?eUaNwuXbs}B(d3m%0o9IXvM1mA+8+o!I zqIm3s;@Zaht;db;9NaQwY1+~K&z{x#E01abSyGI%Xjw`^!`f0Sjo8_LJ=}8Cif?vg zt)DyRoxV@(UFbnCRr2tSDaTLV^8`3R!C769V~#oL6I&gN7iPsi|>SL_MOMKDdK+RpNAz`WNv>&`~5a zC0UItdqg>XY%*1YN+ZQqlW>#hL9Lg97OUJ`4OUI8W2Nh!esnc80iL33zYg+Z55>GV_!^R+X)@quTVh>uvO~#mK~;?NzgbC5E^eg zxr68x&plAcZmJz*9p9j~BzNX&%w3T}B_zq68PIlu6dNnL5Zl{?*-rGO?POWZYKGzt z?u}HAVszA8((yG^bZ??hQD$!Rz=crtCbw&*nUbp56BNz-x1BIq3dM{L|IVr7>(roR z(Hfg|+kmIuP=h8VNTj`aqH3R|N8F2VIC76w~Q#J=&7~cFM1|**zzl1daY%T&KKIj&N0;$GA6d9 ztj|^@9utP;Hg16h%laUihGHOL7+V+a+wI-GzTmptvUcCCyYVW(QO-Dcj!xj?+i%)* zd~fI@Icv%1AudeO==Vv{$p<@2wZ*5%-9-?8> zRf9scU^K(}jto@jB4W+*hV&8HIeN7|#T(X(_3FwZpI>ab0I|dyoT7)triN(4t6K7? z915&%WyS>-U;_`9@r0}X=hT!@H?=4nx?u2SPp4&`wFvc{$fE1>tuHwL%8RnrKlS1* zJ-7V%JIEp$))S3Uik1at1L8a{=+pfb)iYTjVId0m2(cnJB+&znQ1XaR^}!1F0*R%< zTwuCq91|#VYmo#ZsP}_!-FS4j_eS2VuWG&Yrt`(BE0H8JRa5K+_TM#aBNpPirWuNi zN9A!{({7sQCM%>EzqOMJE>MNs;RgNI_{uMyS+VV-p=&P~^IG<6-IsY(1IRE;Nbvu6 zzv6%4(XOuyd*rZYC$t=W#4~oV-_mbkh56ym%g3Dd&qcY{uD>Arq=#;qioPcrU6g~5 zz5mFl`Lcdp?ws%qznruFhn;q?-?QIBf0sAE`=#w~zmWa(%U#y({Qmr1cCdJU%jB6% zx1_Mr7kMEkN*?j4X;5W#D>E*z0OLF$s6~;bg?NJmI1-pybK8t=XHDKxc+2jZNgWrI z-em`?5!muWQsJ&f^MKW-3E5!I0&L(xw7`9YrR{uUbelEL>ABb5RC?!+M=TX)9FI3{ z8+^2CUo*eug{y{LbM2UKS3cD1I6GJ&SD-vGZy)Y2Z`iUPN$)lylq?Lwqwm~)^-GJM zd0_C$3AeYs{iPfB0MiMB)BI1|`o?*E2hVW@UF*BP^fMTYh83VOm8=XRyhQSdPfdGw ze;7nSn-drr2oDdGU#MB1RJ+cU63CgV2D{n)pBFwNUgFLRSb`#X#HU8@US*1L{U6ix z8+TsVN|lJK-(7{khNoa8>5eD`#xGxbo*te*G0BzYot&TlL} z3xhiRrH6Y3-yM-V=bLp`ZmV?nLsL!||725n<;G7dGgr?VzkBnp=}W+PG;9GHQ_1SH zhAXIti=*?n1tvt;f2!CSjcmU-^HG?LGF3wd?xS`j@=-Gt8IQ{2`Y1PrlW~32J5)Pq z*Yl^1Gu*Q>+h<*+E&TPIO9w3FE}$pudRo){!p^;3^Qxx*i0; zEplh*s!rv49xi{>s_1`eZP$-ALG)QVh_wH^@u_LB4|OXuF0cR_c(CZgDTKT@=lVN;Ty%ZG%HBJ^Dr^4t zm8kDTQtPws`LcJx;;d_C|9tDCwaZ6BQqeFs8dE9aw+0X(yUH8%mWTCVL>>`HQX=`J z(M579^)7GClEu%DD$H8(Nc-;&dwAS6;2@DmGJ!zpz+K?iiCkcgq!Q7GxGr!vIrO+L z@JnhXX&1QRyDm3>zjEWq)!&X8(&>S(TX|GhkioW*;8;fFzw*`Ktg$1Oci!6T!y}&5 z?O?yX3+zZeZSnczpWeCdtHR~yP8e0btp=e>!ZAju zL%745uNUii4<9-6%_+XUuiL?rcY)ogW#t0%y)}9*xj%Ptm`;C{ha9***ai9*NuJ1E z!#7)0WlIb3Bmp=QxE}g)n=xtEJ~VXAoqwB_+V+c2?O^i-w)}{=xHIT^oN)7Wj47Ccy)l)wXdw#Sfl9Y54+q?pK7U0o_lUYs*j=W(L$!LjuhOSi zxT&R}9->1xZf`J1I#Tbet_Fr)QyZSyOVd)oA0?0Y)U>}ll^5{MEZ~{yN>1>=DW1Hz z9J1-^`|Hp3pD!z1{BqlK$|qfZogJ)_D^MPhm!BRA>%vkFBrd@t$tA1EEzfSc>F}o8 zm<*#8Ce)$@Rj;KMqbWwf5ik933^n@1_SXvGG%PWtLxM)EBWhqnIbeys66+2k+o)}bO zV#`DCV8P71ABOz2b>%_67YfSCoK+9u&-J6{JaX41&*fh}cfpz8o_=N%JJ>YB<8-K<47QF|{d9TvKx*#LtIm66bZNK{ zrx6l5nZ}D(5X+8JtjC-ys#OIZmB)=&HWNb9A<2x7yM2`T*13htzJCAvW@mg>%2YtC z2|g&{%ud~-e;hFMs@3^djT$??wAt+Q?O?zC0{;Z+X?x$m3D=+aaKW1Fm3y{+llKpB zkZ7(zx!tKGJJ@f(z=u{wpYZ|*PB`p&e|6hW2G{33dicCQ4CK$$R`$s1>!q zmy5jUrAutknbg`1+}S1JBDf$P`+&zam?Aoj5O?nVE7eTenr_;|V$Lz1ZAD zlMlM=$ex%tFdqHl(+*}kr{`1UamL1n5=pe%AnAnbf`0c{Z*`sC0-}jX0NX`EOtG6B z%nf%mvR@PdIJgm_;KLDiFQn1N$#gyGs~`C4_HQ!h^nEYyeb@230e4~}(V+%J7Y&<= z##D;v5zbae-XQtI!9aC2DOHT<3hVto{}lDENyrZSu7nw`@`l}A0`>k-7qM$pFVwMD ztcz~^b(~$u2lkxEYf1Ix501WH%e~{8pH6T4<3~?HUeT~rG^Ub8UUvIyEe!Qbyzkbc zg;MF}A$lB8FQ zBE_Ba-l5{8=e$Y(y!o8LhqoGh@1{LD+7J6uJ(7s{{!Ak1t~Z^2*Hs#CW; z{+FtpP2aX(aOeB2-m-)JmUAI^J0WLDkH3y1aIog&qF>*ZDYhhOD?jn;X7e`R_sWp*xdh1v#&>;F7y@IrZ{gzgX0gqmf zqwk3{9_5+%pmdP+bDpFUG3}&vZFEY{N9NqLZup9|?aIIZ%a_YNszGGJ&?s+9*VNqn z6aD}GDSP$c(B`J+Zau;d_FIe-`ia!gcp!>FiZ;&#OV(7{!Hqk8pFjkY7Iyff`(LR*Ie|=+$p!t`OXg3$5h$M+wbF54*J~G`#|SgcWlqSV$Lm7 z{zOay5(Yfc*u)k8 zGKxInivKUvWYXeq|K=xuJ?z=eS(|!zI``Gj>fk}&RAScf4U*k;nOUDsx_abwO^5y1 z^sxR@>|jH=BIOqG$GEBOjcx+iH3*+`ddc`>7Y&nxM-!G^~cjAeeqg3z_{p}b# zm=BGqWZ^AFwHlu{ys3@;su8*pk2jRXRiTd)&2-E5M}>Oy>3DyqxE~XNGxx{apK*QDs|4_PJfkeG zY8`V#0`Ih6s#P`Ujh1)JOUvJQ-}2*2e)z)=9?(~bS+iro4)$BBmYq6)jd)^a)dC;U z+f;V2-$J#}cO<(#L%`$lhO*xHpmed!wEbVvH{QRFh&!)-Nu5l3Uj6m_5uaVMp+0|Q z&Y0}-IXfqK6sO2I)Iw+wy-Q>VJI7SlGWQ&UZ@1X(tf4!JMi=GaBl<|V9c(s`RkHAQ z2;Nv>X%l_G9$j(5TXaYV-lAdg-uc2C{I~qS3Gf}gi)#n#Nq9)Yv(Y@k|9b7{jh;dai{ErXK`O7 zL%2Y-z?|`}Za$NU&WBv}@%!VSX_vXAV*I=J1!}(Vm=Ji%KAB+A!MYuc`9%{}=ipVX zdQ{%{K{pgLdeH-74LJw!5&ino4i?Wjz&6ysn=#!+BEo3Kp)crGBzYot&Tm8uUibUK{NtMs_VFmv$XKUOq5J5s{@KBpLDWsG(>oe{XmR```pcK- zN1~xcIrunxXhnIGHgkqtK6b<5m;SKp6gyZW=`@QJq($y9sMLaT3^Xo8$4GejK>s*g*M^8k`A>aEdZ+v7AEo&Me(}Z#^t-9z2tJ-sFh&({ z1_T`bL5d)sCZDx=l=tr5y~UC4?)1fF<6oA$L*jpy_YkLR=+I5Mjhz!9BLB?aU0LTB z{~R6oz3C?wWWqdT>4*B?=@V2r+@Sa}o*wFr?_uTz>4UzJeqnEMXtP(9Hb-HGfY~@4 zCBcm#p3HEf0;WHYfT^c5!^fE+(^MX3iLDxI$KGL=Ja zBH_QycUJc?h3E{t57H$v(->KDfOd+ri^T)~=Y6oo_gAP|j@Nb%-n22Z!$kkc`|7*w zso&eYa)fFiW}(_$6?jyREH0P$7yaDv7%q>bnunOnCh3>;NFB9s5nRCLR6JPxFhPYhvg2e;&R0^v6aFz3} o01uzmgbFZ&KpYrbs3MZ%3TI0E$UlJR21KhKRfz1_%e&wC|K42Q7ytkO diff --git a/InworldAI/Content/Dialog/DialogMap.umap b/InworldAI/Content/Dialog/DialogMap.umap index 630e4877de37d447f1dbd22805d31351467627f6..4eb7a008de5010667c54b9767b302bc2c6f8d365 100644 GIT binary patch literal 17845 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 W@6hGHEKW|3I78W;^922eE&l+SS}}D1 literal 16357 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 QY{#J#OEu0*^bh|33*ikY;Q#;t diff --git a/InworldAI/Content/Dialog/WBP_DialogWidget.uasset b/InworldAI/Content/Dialog/WBP_DialogWidget.uasset index 175959b8a1e1b3611f4f72fccef454ff7d15b6a6..72912cdd85fb67836d97583d3cdc1f09698f018f 100644 GIT binary patch literal 273086 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 IeYgJnzZM)ZPyhe` literal 276079 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 diff --git a/InworldAI/Content/StudioWidget/EUW_InworldStudio.uasset b/InworldAI/Content/StudioWidget/EUW_InworldStudio.uasset index 313ed41d74e1378d1f944b8182e0fbb1c3ba3df1..2ed403692d2d07043a2e196b3cf9a51ff7ecf40b 100644 GIT binary patch delta 37003 zcmcJ&2YggT7dM<+7B(SDh#>|jJ_FX{8R*IAmFmy<0LO=+;3PDg16cR3EkPZSO zA_hMHsI(E!3{E*|`D?aY(SZQQj+%7yiy2Qn8=`F+w7!RH!#O349u_7U^ z|MAo6^^<@2=ezIe`qB8M2mZYA+Pzn1Y|Whi*81mP-_dCbUGEa(;@(rc2|a2Ai-oxT zhws2#87eZ z>+f#VwM^PwHG8xmY*Wu>H&SQxST7t`NB3+bET-S;Ctd0rh5>0SQoPN0m-=4M6roh@ z|3IVNRUQ~2sGs-D5MH5=>Z+U!VILcPmy@Lq>6Ib8L7#*-+4m6!`J`8d+O&6uD&fzM zz3Zz}dN)(w#<&N@clYTj9NIm)&pAPOeRt=6?F8Wk^>V*P>hAtW)i-i#sqOk1cdr{@ zl!YR7YhEJ|Tb|cQeJ?Ljl?K-mwyUPWjnwqPiE0l#?NAE_Hxgb{SFrCg_I-(cCk>(V zF7}UDa>gW;o2*=a~BO2kmlzo3RVwAY%kh*hZj=E}O zitvb9I&zfQ>kONike?!2zGTC57*@Z^hWC$35wHBF=8ei1k5*EvJ(Q!?8=WFPU5yQw zV7Qhf>6Q+OlE0F)8Bp4s7@whR1uT2gc-!&kn?oY<2e7 zG;#1CHvA65dve*ZS3#P1I#(T6kT2HEV>2zsrHQ%Pa21AIv|;7(X~H1YG=7wrHiRuZ zH$F`~p$+e!kS5+el+A`Fq=CBf38RFk@!d})6O+WM!_*TK`Xrl*Oc#{cC2LSo=dZ9QAOT==_BZKYTb% z=%!XY+%H+uE*iI2AB=LU8)oOIyJw|{4O+8d`s@_3TpKQ$og#$P^|MEbUGHPCA%!X8 zm)h_>3>SOYZ0k8Gf?ds;GfF(`WfONjk|L@;Hk^%NTR$6qhv83tRhXMEZVIrOH|C~@ zy@G7ma$bs<&|baza8O+|ufF(Ndv)i$eDRS{YTjen>expi*RgE)35NB?W0<4f|5%E! zP|bY|$4+J&XU|Vm)90s&zG?bneR26Twc3Il^|$#DC>`dDvu3cFQwuQj7#p^G9Cx43 zhR;2oA`DT>9v>xkU%)2jE=&=ZXu}^cd{-OxTa+SHQ41E05<5Q5mRX-j5$9{ebr^P8 z$Y!fNnIhb!nw}gbHaNv5K7TTW3WrkEZE=ct_a|)l>f#h(xLUq=l=#8tY(iZEg1%wH zzc375VZ%{HDMDYhuxOO{;}2}YSDYd~QNe~UU|4vS4ewc+BGgcorK7~kKVqVj`t?$i z_!AxGsDsoL@$>6!__mrN)KSl?qr|yCtHsN+)pg6##2&x0VU^`+LM63mc@K38M$<7G zC0c(2C`av4k|KVk4PVEw@9(OI^i^AuBwRF;j1v0byPsNlMUt?NjqYBPBz(z6=P=h) ztynQi9QP;N6nZL246$KyJd~1}VNh4jhJUdYOI9Wcqt*2*M~NwMYWLOI>Y!C=VqZQq zsz5HTr;mNrcB_-bujnveXr^YZ?#E!`1yxwvH<<>|XzY8~wE6>f|4E1Wf`92+wnJEm zK{f6aI5p)Ix^7*PkgArh8zuIa7}i*t-)7U*67<8i>Q||z=5FYxcH5AIkeRz-l<*gO zrj!Q^YPF~TPTe9lt^Tz!NjyP^`QqJ`aIc`+a#LbWC!GE+-SN{arP90MGk`BiO1&L; zLS=?w)uyEC#n{amQciD*&*N&@re5lEn-UYg*Jt|Np&r1p&RzBrhyj@y!x zsz%}Yu`0y^YVM|>>J-FxUDgrCs|8znu}xL5km6gENVmkr{nRv!k7hL##PJon!k{~K z&;)(ggbra4J)G|1M}5^Z3`){LXXpT*lYPRVYIvl(zN2!)XM27al#E9TO0P}D&P-Q&QT^v-lCk$fK z05#Be9X%KZakb<;{QjLVh^r>Q*ZH%m`T5&R@~^955SJw9{53(nup_9R+niW46C^|n zd!SCvushk3Zab3HA2uf@9MD6}8)=x%u3^KjiHeLQYoYsR?sURrYyim zse_F<40JCZDQJnl>F10vsCEqK(dJ=Lx(=G6?@F>wd&agC%Pjs zA&-g_pJ&_Asp^zy&L>V;f||KYyAId*w{<=|)sb#u*P+@>ud_xcY-pD-h#Lc^S;!89 zxH0V35l+nsgSatpgiZT~LEISluA>9PAZ`qN*Nnko5H|*Xt+WTjpu2S9tLS7rGb#*9 z(LtQ}U1P!^YE<;f9MpJ17*sr^Kr-VT@br9F3)6>JCdvp+|aQUn-h$~X2jyOpwLAAN1+&pP&07*r>Q`0TY| zPy-#ruY6%+7}QV)HPr95aZ4D~C zopV_8QTOS)xE>}|4ujh2AkL^031LvX7|^ym!=OwZ#Lt?W90qxGP#0Y&H&eqPpAOoq zt4;fR!yvy7`bY-}b;BSkEBc3X{^N#W5Ra7HA5Lx>2JuMADQw(Qy>Lw92G5jBVRlU_tLS)_q3h!4R=0p-cQ3n7Eq+@IEwN`lpccKYg_hV&xqiBdg%)}W zy*VeePKPjvvWbE?q0R1Rlu-4ECY0~|zN_ka_x88H(LD@`B}IB542mV?Q137(mX!DU zsaKERdKP!6MT5d1?*GblR;CYCH z*I&n%J1Gp}H?FEvv2R)!#1V4P+cU!;eq#M`lj8ZR9!pR6N-Y5qTs=6zSgh`RKPQz$fmZ4yzP6l#)Y+#J6YA+xy`BoM=2Y|5 z(^rQ|14Uy_s>4Q{G~^WxMw z7qV;8pnE&;6B58Vx7``4#CE!4c2=j<<8v{dfvH1}M$Ey#RH5J+GyvZYoTw_F_qyd+ zzOhac!%GA0?KV0PA8{WVY;Om?KZPAj1Mcm>x$5~ZZatQ>aZ(z?OJnZsHtxAcE&eK- z31MxN1S@oAyn8PNs}EjCO88ozdd-BXoK(7+`y>w9RF5H}oQ(z>b&)M<$dEmEF)4vh zsg2px-JeIMRy9*Smu|(+sd>63!%tawJN&AJA?x==wRl~#SJ~MH%GBuF-K&F3-RjkE za#GhtUFEoLChwyE`CU%x`Y6ymdR=^0q35ZCC`+iha8Noro;rx$nSxg9yPie|R0q-1 zqj$CIpmzWM_Gi7(F${`5tNs095I>8P@pk7hDE6#wUBe*miTJKl-NGR5i8!cN_b`aN zOAh)ZI}DiiQa41gxQ;HE2YXSF`rhTl1U|K(UwAby zwK?e7L2PyF?<1?<8WLX3Ilxzc_h1;rIlw`QqZy*vR}vH4Iwj2u*wlBJ;;V*F3?tw- z=Aijg!yq2tIB4rkwc7PtZ!7C(94o{wjZe|c;NW-XsRw@2Omt%uuY6P?@Hw%7f?30b zg6S+JtDg=|QOkbnl}aJJ*T6T9eG(gU7>M^8IB3_BFo^3G2mMs6j{60{xFRv0Pr1~B zUwWylDiRa;%#0Gch@s}f;-LL2!k}2x!YYRP+||ScPQ8B(o4Ws61oygiVFX-FIqr)a z*y`VYjI3_3Nj-5hy9O=Wo(2!N_Aa0Ud`76{H+!l5eo0K&Ns-}G@jN!WeqLNI~kl8xISNvscLgW>LN_-25^pCdH|d8~99yE!n5e7$=K?7f1TDFECJO$94)0azRybFe z=lT8w3eQQ6-n&|d6;;*t(kOmAc(W7@PQ&=^;78LKyauH`8s1nB4?{_&B=llObKdZy zpR7x+%D5KIYqmyRYad;RPvb@!oT_9r{AWE-eA)O`cwMZca{oi$|4CB{&mmO>Au)j? z{ip?-Or;3vI=Uf^G7O((<_L^iBj2~(7J>0LC5Mf0Mqu1`)YNg-Zxw-Y=fU^2y)Ode zol3s%X1fTCHyt@F#TS9`t|N!F2u5JM?a0sT(2>E&jA(|)og*9W1`{Yl_=d8s5m;Ib zY-aZetY!?%)iVOC6$87T6M^xrBbQidp9qY%9XTz}_m9A+?ncu&a!>@89s_GII07@p zz%C4p!0N=n);t)2)r*1k$&bJq=&*QQ;ME_Bz#7Kvt6dO*HPT@p>)Lu|d<2#evv2pL z2#mW*&X=)MBQV~aG2#mKO z`Mzq8M_}fd^WI$)f$<(C-}m_92#m)94hs}VV7yDoVZyQqjJGK{?6r~zjQ1%yY}!*1 z7!NQUW?vnFQT?NTxZz!08-ekZhVQGgF#_Y^hr^C+qOk0mv=)f=avVPQ88YW?IPcrR z+HGTd$*ZD}6!vhxZPyS|j~(shIKt2i#9RYzv8f~^#`DPuM5zHc9lf3lwdG41K3YuN zjtJwPTjAWRa@2?RYH(UxMDOQDU-%liP&4L&+?XCNi@;*>KK4cgMs1G@gVXFiOp0p> zIn|@jL!}f=XC^q;hG5B>28eF26~rK)$3aZY1nHFu;@?UtWHn${DNQeVN61%Og|2I{ZDFJw?u zIk$zivunqUtq)rEf?a!ofO9QK&%tMnC%h;r^>zzB_Yk20PN0(Ko6l%_;~IM-FnTvi z8HY(e3PTEqeYe~DX$(Aef5=aEHpKq@IP|rsvpM0#0SeDar7*5$V|BVdWU%a-W&f}@ z7}Rhd(BZNBp9qq?4B*}m-1I~5HII$r;(m*QQE)VDcKgV_7j;;^zEA29frVoBJro7w zwD9w;M!~q2a@eGf5uBWV9QJDz>`mO0(#dIgxDz?h^dIi`brdZ2exvS>?2EnM4^gn# z`}OG@*%y1iPorS5_si=N*%y1iFQZ_w_Z!)j)M*KaU!|pxBA#Lo`C>+vHu*W7ywF{H z=%(OdeGl#7Rr=8X0dhhS@eK$(!#y@USO(IEeDS+M+T@RPa$BDEFvyOF;X|~C zx9LNZVdR1x%ZCluCZBd-vg|?ap{f%Pc_Xxk8T6syNcM1BnhuZD?EVFpkVv|@gf#K% z{P0YDamX~{anq3L2A*^C=|jFaVSzR&wZdf8$F+yC^x;|UA@vAu|1EAzm2D!uIzGOI zY$1bP#xsRYr2u?FQ7{^9DXa$t;L~!Ew(s32jutXVT-+mz$c8o`Z&4c@EG^9Lvn-AnZ+dheMSIM3Gj{*J|Dr$;}R@8z&1Q80e)R-K*i7gL(D zYhH~xm+yUe>8ZBIhYedE*~ic0u-YXN7{B8^l#%#+SV9g2W6pa(hg~BP7(eevZChOXr!?OEr1O@a z$@QVt%3I;F_k4CG8P`ESm*eJpe~5y`?i;vD!~08&O!?kTG4NQK-L;z3=@fHc&ig)5 zFn%tV*}B!*xxdDo%lEclb1R(lnbY-T3_O;u-`9{6_x}T3-n9`J=QF2kK@^PB%xO~A zkvUyraB`iP90lY2=dhORBm4My9Cj%R#_z~=X~PC$?iO<%*QI?MBQSm**QIKkG~WI3 z54t38z7-yO&k36~7yoLOP+xpyGr5ojx4C7%Hu+a~M1pnQ5eYiH9-gT$ei3;{A~Uk# zO&=>G#o3_#9gqh?n1|w=ta~5=23PtSiiuhqc_EcU#@ zgXHQ1|FG|H6fAaM;v12Dv24Sy!%&kJ~-LMr+RjfAP>hqjeR3DZcw zc9qA5j<>74S`a3NiUtZx48kO08Y)ZxY}rs@iZCUVI7}ddFqv!`E;JRUhRTNvmFeP- z9u$6{KaY+S`pNiNe~h438cy%~2b#ANao$H5@5dkd`^S_=oTi4j6n*A2@n`y%m{wt) zKTpN;&Zy^UcwWYypSgFEP)is?Y8MOl8D7I*kD3INlf@eaW2p9Wp>PT5&{J$kax%o)WMTtRA)7M9O!7qo%$9%~|I3jN86OtAsE+(hgu4A928O~v|T zVusj)>}o1{$rl+wq>K;~Nd0EmkgF}KcmoG5Z6>A(dBoEP*v?SkU=5hrT&yJ^wd*7{ zCkva4UIBf%KLiiCvxT^TTyF}@hgtyh&}P7#dj^PXEyeo6gWBf84+Y~L-ngN0li~{E zCV&A*`Y58ZmOzBOE?aaH#VJlF=bsjhWWORN3HjQJ-xaJFrD4ghB{m_8&0;HIv^KGx zuKw99CJPT~6SW(Odm#yS{RpbDFc$zkTk&dT_Z@NjCq0Ngf z%+J>bj6*qLE@<;b9GUkOI*I>_ul9h9ptnVjIY!RjQ6|1__M14 znA{3;%jhE$=*d=M8j;<2OlmFmCll$Y;4$$|vc5GG=~3;Zgf=+oF>O2@W3s6gmgT-L zB#_H(aPR`{V5m_N8GN6ZB0L^N@}~Ph@IP~30` z{t5kzwm9!eZTu}AFQ%;7P0qIyn+Z!a?Q4?>3rJ}TI*L|;j_sMyr(%lq0b!|zo5{bY z2NF`X32g66zVZOyat(Km7vmCbY&syy`C& z#Xp1x$l?IZXC*n&8_Z7(f(NU#GsC2a5IDj@%BSO+ZBL1k{H*U>*^anuDdI=#`$Pn05#a$m)(*wTWUH zBy6S&#*$?nz>U%mK)~@%qJ_vE@tFBN9$VZm-YIM)!u_JtU;&$-WkXVWKd!8Ff<9cl zA2)kWJ0`m`#@jVgn8s{>8*1}bXR)F1JXN-_!VZ$xMSOs~ct3W2(FLnZbz@J$!h)_) zqh(mFQSxU;=#sG;gtJRS-?tk!?AFk)PsD~DZ$NyfyFpAZYO~Cv8S9FP#FPcPU!t?k zN&hS{LwH%ku`3HWLfUHPO-6JO>qWcGwW5uzkQz%kWw-FLn}6YyPOy03cu153{8Mu;@A+l~aGwa3E;;P(#8T)v|%2L;8r@#}@-dMfg}h zgZhTC5aJjn#54M)8qk^PgFxpeq z9=`y8UG|<(nA;O^Mymifx;Ks z!qlPI^rc1`v;D`0!uG$?fJZ6tYi;Zr2J5}V@40N4=n%fqAU6OJzSU6V4i~e8?`X6h zD_kaZ9u!9k-)oT42gSa^6)ldp8UbQ{(B{{VfFG#PbSn}fu4+#5;z%sKMvrMpvhy+i zQ9H6MA4gu-0-t3RM0I)u90okzMbi0E@dLsnb96KqRPYd@>aLMcs-q8qsde))a*e_6 z8OlCltu1Y^WDL>z_Wr1w~ybW;nNhsVN{e$!4(F2KIunRktxwfsDF8WRyY za>m2j|In5$9gn4dYOI$h0Nr02u@f;yiX@V&o5h`cYi&Uw)n>s*?3)M@hmMEbnUyu0 z1cNwDAIDD;I}`r|v0-=%d2s@6ygyysK~tvGk|}U+l}O$zU{uZ&oL5=HcxVdfFp{00 zV%{+o^YP@u6Buuy;{q3f9juont zIkUtrLMnY~!0ySQcaxpZ0cEGzK$)g(tr&r=!9uvMq*)MWNg=S-WZN`*fh(vh+@nn( zxEe{$9B`+WHo*eQwmA^hy-{0$EsHoF0itv|+nj8nW0Q8Bw7EFDjy7*P2u3WN3r5t{ zCVrlah4mO=p@IVOxS+|d$z$-4^@-yw66%SNG1#BgOG-rOb*Y7A|IX0 zt$y-+xY6JOB#Rl8GtCK5>Khts$CWJ*ZwNvYP3o5xg2<+nrk14lB8;2S!&{Q0blg1Z za25~_J%NDGf}T58Xi2(1DGm@6x>sZT*(V_uGkYec#qcl|ZOpgUCmF9I%s>t+w1nM8 z;mv))IA5GM&Jkyh^JCjt_Nv9>a zqMLa3LINw6Kmx5aEG*!5_#RrGRD=lBTAO7aBc}*nt&Jv)eMR8geUvpVNwZ?Hh0s>B zqJ_nnZ$~$^Bsb|eQ{!{~Qj9&CvYw%1FJ04|WaYyXcUEz}Pn+1ILSg*cIAa;c0Zo7_ zmthlLgitd~SdMXfU3->eZwKujm+82pCQMXEsboi8q`#$g#KnX$CxM7Ap_7KYfWVn} z2@K>s9ql4etPU$gztBb7UwVNC5n7gHJ_Sy7)pjj>3KVst;|Ao~Q{o{ZOB=H_-8I%^ ztO9k}r1&$@L$<9FR|`Efswc0;d{1pXGA{?xOooTK^~^Oe${aFe4K%J-WWHoA%=qLQ z(3bQe98&gL*g)O2c!XColCrg;jVz^)6$qx4`^VLRZVeyf7pr1Q;*aRaV2NISA%1LAWo*|0$jpbV_KU#wBGQCx~DkP%7~FH*J< zc$aR(nJfXnxe=M&P_~pbd>RTfOk2zR$mpkGzQeT%tgeZQkRd{KmL`nQ#)zs3Bx4h> zjQktpX>xmhGjQb7wMdaSLsIf)oDB>{vSmMXef(xILra6%%7<<><@)5xW~?0X3Kspm z1q>Lgsp;@%FfP!ro_+=l7)Q0tOgd}@!^Ue&I=U5CpP;Q-@GRC$)F`fa7Kzd%ZOnL( zwGE!9?lzFcI8?MvOhiSFA8ao`iBGq*V_H^@*fI zsaPO9qS49hciYzpPuEM4XwTJ-?6ea{&eK*f()aEJ>5ppCJik*si>fdp`EPdtIA0^Y zY&5uH1$&pi2m^S6GNUo|! zA0<`ofmCo}++>uCli=;1)GnX>5>@(_aLKZlApfOwq`Zug_%cT8>1h1R$V-w#Sa*@m z6^1~Js!=NM5hvqUO&E)}?!i17>ePCZUJ;w1IHWp$2T~69pBdjM4_|?tR?yfs7Uduu zQOfng>9~JA<)I?j7t^48Q zrtYWqK-)x@_XFEzy0$s7y$%Al&}FO=O(dnSLwe6>h>#l_$+xdV5w>cpGt0ol@a*d9PFha@5G&bcR*!jG+YtKQ<@6b@1-T*sa(B`MUf%#Hxe2I>CYUAFA zFy5tUvDUnz#q5smFsI$xim%?piWlj)0ZrhMnj8j^FKNK-hXH(98`nC5aYzgNPaHum zu}9m)L~`Z``d!k_1GnRNWVM##leIO_xL-0ag(ocgDsI0xxy868#pioDSAzSx$?@8faf`v6R& zqvQ`T`ht!gp`)H3V04X+4$;xz4>7WRh|x(p+C)d*k1$I42-4m5k=TLEqocyp2qJYq zhW%gr2uq4S#*)Dwi!DmdU~m!xf{Kq8a?Cc))7f2TFq`!WMs+^{hCQF4gjh;P1@8ct z?JRJ~XR&1CSuB}&762|{BdPf*9>1V-=%po+@t;D}muX-bi*l~cXZUf2TFY(}ad0Lr z$;5NO=08W*(+(LFHkovN0N&!NW>o(3;v=ZznA%@H52yO0CY|0Fz~SpO$!bnUoIxZx zdjS^ylXi>x7jdJX>9{2+xrl|okPk14?+G_T&wMVb7bJU}gPhxEXkYTHERzLqN_E-H z^KVK+Nai*vl{7poWsqFI+|^)3mT3(gNH)X^f{pAH4Ng+jLCPkXZ%8SU4M}HSg4~!4 zZYO6Dx%I|b(zHkZ4G(oRad1oGM2QnE&g@g1EKqP!)^!fi+?`9R7f;~N-KLWORri9m`T zmSw?C4s4Pdk@Y8{cax^F|240b` zG3YC#{IG<75r`aUF8wN5!8VUus!qyeLkijQoqQ)*ZIx@2+_^Yr>xWVznfj@8o-FGl z)g`4r$?uSTZ%T+bN2I=zBhE%noRjh}uoLrDv14e~d1<nmoN%&Q4#DqXhAK~h5T?$TO9w4_SNtNYh2Kl|SUxb+=Bl(& z5^zS5+znYAWVP5K`5~+2l#>*H)|XPlm&ZuQ1rX^Z#r37TNcjyZjcos3YC<{DpRE5> zdXePrFvw))M7eLM@FqAYIpf@<_@;P&==dagJdVAN)$GKxe@I&-a`lBW1kqfnCI|Y#gH>IW} zmE|_X+fHf{0&#UEk}u0mBCKgfvI9V-u_jUO#8^WLtI5A}?QTl7vk58uUF;21;9>$==CQkd$AOlfvpABxUst$>iV_T57kFT9E|_aw2IW$vw%6su;ahNvc`0Sw0!c z{ZX1Fkgdrug@VCSRusE&nwy-cD>Y)=Cbg<#+sgV{fUe90$ z*$T<)B%czLP_?yk7lD)yhNkqbr5%tRI-f3^1af){_?>l!1o707=ZV-1i8l)6)|5{Q z#Je1vPHHHpVfw@@sZl74j>)e1z>$?E%O!Q>hEy}NQ0bm%F27HHZy+a-P7R>FyB5GQ z3O7M!!yDnQ>-$Ps#F!y}M2bqK$#f20^8`jQb0=qkoS4N;n#-xUjhSrtUA~JfXlh6# z3u{QV4K|d)X0r2paVN>lg#TKWDfQJxrk1jiBoN6@iZbP7@`V69RB9O7lBAlTyi-d# zLt~}sPUvR7Rc?ste8UN83iQfikAND~E@%I_xCrcQ0Sp)o0H zEoVy>2&J0c(1RrPms^nnlU$!94Uin9bb_2p&Nq^pkqRe>qB;|T&eW2yTliJ3PO@5K z`jG*03hCsKSCfrH4Bq7xQVR8wDI{}?G?cVz4HQ}Fa;jiuY}Xiap6 zl9I4M_(rTpGQY$d1{;);xrAF8mfH^dmg18Cf?+wNtSwessFL*c7!t_J>*xh!W@GMP zhM_M>pmX2Wl3U<1u&EP*Ei`VJ)D7IC+YSwf@Yr$NR)b|{4N`u|ddzQs5>IX4lK#Z5 zu_L6`q{SEVWb&;Cv#TG*S7A_2L)DGVH+sUA_CE|y1WoQl4px%t6H{04CAnNK$6>+| znIFbzED6d@C@C3+e*c0tth{+UfxC?nIv}#72c1agLBNa5DgQ%{TJ%U`i|h$>Ni2b*}DIp zbEzPL+UCFHUB!<`R^RCc`&fBQs;!-Q(jZNQ_BcbZVf0axhDcsgu>|4YJBWJP%5e5| zEsz8>G?^4V1S;n(k?NLQ#(P#LIZz28*+oK}x?7yM_`6%3TF4pmB|q z4Ujv7ElV6y9a8&S@e;V|MASH!E8k6a^v6C>lYqBTIJB@A4)DGpjV48T^6|fE_|9*^ zd}d_uXD!Hz0dPTZn9QHm7D(Sg)Hmt=tgna{A8;4j)&lw7EkJI{1M<_~;U48hh7lzD z5rYY@LZswS;WJV)Y^oXVdc_V+WDEZsEKk-QaSY!WxMV1Ie}7}0gnk_{SB6XezjJN` zS^ppqQKpgdL7=bZ2=Gwnk_&F;ud%X+JTa25sThMbC$~X*`WiR%lW}tWT7l8Om(vygH~P7!Ek(u8DAk()&83tK*V1}@flhHN5b4}*_|Hxc2K z&`!S`FOc(hz_pk6rn$*lcr>> z$j#S)hwT{OICe)(@<%K`B<=9U@kO6!5fs30ZaDR<5GG?`$rQX~u4;oyG} z61xlJ+YLB=`yfLtlC=r9Zn6pNUA!8PoMXLF*;%6^mlnSbm_%8(A&Z7p7QWYS11tVP zyY|ZK$&Tmc3~0-oWK=&z@5voVc1J{p+#eC6_m<+&(UoLV$&2##P~Bzl_)+pp-Tfcs z2ZE6?L4p67oT=pU2AoOn%~ls*N2T;1Z_GB1dsF@&$802)BIJnw^417?Hcd~M!)fsf z$_(VqsR9rj7!I~E^;x-Jz9qGQW!lItkLqhE;eLSd2=C5cF}7lLw#CNr;=Tw!9kMFN&CZ< zF)lD?l6*f33~3k1y^bV4tB)bM%7D0Ladq*s%Ry`JlPF3jeh)v#4%ptufK0NEAptnt zR*frN#ppe88Mjf_lGQ^%x17&_xDp#xuwX2gQ`WxO{2TuRm# zR68S&)#}%zufznh@C-B^3Ac$Zv>nPA6$6fc!4a*JPmzNDNTOKSzj6uP9wwLa@4%MxU+W|u@EG2tD~6L< z-y&yg^9{fED*SqHc~wI*t&K$Wx_e&{abw%gf-;$EgO<`9q&+kH$_>FEon^r z7yc5j>dhK-b)00u5AtSn#~b#*0rO>N!CeM|z1X8#nK zn+k+`geZT>Pmt_CBl12%l4=+RlD&T+E{z^3*J9h2-vl*bhBNvdln*zl7KuPRe!P_2 z6jONJU01jFx_Hf97gn!;W!jt*Kk1wm>H@JkNx5W@muEw&mqaA{t}jKZ31(8qqQl6w z%xEC3+PX_kX{RWO)J0Q@oPS0dOv-+QkB7Wlpg={hER{C*(9M!T^5}E2=37qGmvpy4 z&m>>u$aPEd4IM~fCBr7{{YNPqKo49K>-Y6G8jzOS_JO3#4&d_Ecn}@!o9G!PDCjkz*h5?OE|Pf=?4O!qxRd5E922z% zdR}GeKJ3EE8K_nqWWzSOdX!hEAk82sY?;(8=9t{}l<#N|GaTru-KB44Y7CvtCCJ_z zGH7uf-AuwJ9=cJ(fY$Q1%7(;Ht=@*7=!eR1Dao@9waMNaRA-t(8t{NAWJL`Fiv)x@ zztVdRlZn?YB?GaI6sLe^t!jhs{R7b@iwHi9<_PUNR-{cvTq!qt5fiGrd~9q>^|(;lmHZNT6>j*IZFx}V0+jZARaFv z=RbjTb>a(t66^B`+L*m{r{=}~@0%1EC0*_6@Zhu;s-0P>k*>wmm&4Bq|GOvJ4w+RS zLtT=PL9r~w?a`Nvmf^AtU4|g%Cvv8#j{QQqG%8f^h#^O$oJWFl3YuI4 zbVD~Ok6daA=ACH{U#!>-kC7b?0|Lb~$wtad;CYb^`!{vu&NQ^aY&a%r2pMRhSwHiC z<6@#?WMG%Z!T-IX$Z5zV7Dx1jk`@`zFF}7_CMifv$oTK^3ziNNHUjDy$eC8S&D!Ns zSCZQrln=c^bFizDi8UXYW|h z3stl+{4S8yZNQ-3eIe3IZQ%f7TnPwbJ*0BK{4G0x1^^r$+XrP`BE@59!u0cpOY*&1 zS2bdvD>EUgzS)LEpg}(bLF{j>roS~)tCOuBT_f^Z%GFU||J&|!<`3df($J^NhAU8S zkLRJpi|GhdPKW>o6-?9wB?X_MsA3RqJYa5AD=Mb!=T^#}Ek(S|ESD8~I?0NI1OAp;notO+W zb8s`LQ(aOx4R24FcG2!*)Fad=nG{Tu+Jq{s(q+x2@tVm=sMy(IdEbcDHGPIpa7j;> zTte$Iwh5-$^6mUzSs%k$k~IYGUFmNa%Dg=Sx*O?7wQtbSr|uruqGE~glHuLkdeZa# zqk{sxcrLk^BiBa`(TXH}iI*i;25?T-m&S$m&y@~|#=G^Z6!w`DEeFKY=mfv{)7o1qQqG&R-(UozP`0Sd?3z@~|YeX(p{r~N#^P)?LB zXdDcjV<;k(CK)n9rIQVxiDcnq1TogmO!HGfdB98}d@fHMl# zOW+E7E?OAH8oaq%@uXoY0c*aB?Qyf!$`T|TtebpGj~itiE7#E7(&dLYU$@GSZKn;7 ze`X0=a(*di$!E(9CFF|wUoV?Q22M6KA>)^8(g!cUBAk~+8=zX`@=EQBmo&B%t~NB$ zIf5a&%xgJEwB>0V{(&QGb?L_c#gP&Mgfa)wn^zFCRC~HMWUOOK8+WN6|Z95<-JH7TGc|0D{e>o+PDu?&uW0Vq#^Q9P`z^` z-aM5$v|eQ={KhCB!LP%uEH&U4eZu{0)72IBYh%&1SZHeGb1h=yZ5p9<$5q@jBe0 ztk%Y9g2}D~tv<8YZwug$$LF{BgEp_nZS_0-E|=e73Dwzc#2b{dmc|;yw8_}RRMN z2R$C2!xyTSX}nJ$uY8ekZ%8m1R|_UrP%(S_9<$8_JT8aTW_DYZpxf!P1ROTAS0PC+ z8)uV>9>xqZw63vjx+kDm+yS%S=CxY=xP!&x3RrzEUl5lyD}J(Lu5mA!QP0@cI7DM07T$$o68pTIP6}J%dJ=g zL5s!d52ZISD!81@=5_kqKAX>_fUj0N&?`QV1^@Z%Hcx;YXm5Olj5vvRdpem(Ss`IlT_E)9!G)0(P^{qd-OcW|z|y z>Z}+iVwu|uwE)7PTd{c+YtU|o4tl&$D7(+WCj-3p}SG5hU)D+VsKzKruoFNblm z$!_(V1NNZB7O+`ePOsHrb(n367eY5%e6FB{eD5%RXYvGXW{bmY1;lOv%wlu;17=WR zvpB(c2l@1lctQ#;R*^%h%a{OGdA$}abJ}b+1v=|8`@tZnlGX0w4?jZI80x8G&~&gQK;gk})U`LhCz!lJmts}mv;uaw(`^sB?M^GTS+m39@p^(mZVXUfn^SSxEIzAW z3AkN~;`i7+K{uEUr)bxW0qh6q;Jy>~>VvcL*sWHF%MCdP?C_7&7$ynnW~<`yT7l4K zw>sc5TsC-RkIx*0g#`l47TOA-)!mFm&@D$m@j9J;o7)YM* zF;e-S_!RO}A6x^W$zry`)mq(((}MUAbohN%546Q+ zhI@70Vt4@`Bn$uQ_F7>QUYpx)Q(&M@mk;;wIYOo9j57sO0O3P1Lo+Q-w-u+tGbnB! zd|?2_?G8FZZ3h}>3nmY4W3$?zu2wq&rPl%S9BwbT8t^OdqNMnu@vczCAmdoU6of9A zVTm@26_i=cV1NQ{z}Hb1Yz`3R3nN}G&osJ2$McMKA>HS+d4gUabQeCv;|w^xa40Us zU>_vwFcak~V>g1OACs!HjonRdfPzk^7Xn8V4fui{aLw)YKmi?ywq{Z|+vp4ZIn-Dx zrYl~b6>uA3uq}v1P-Yl5wA6{n;=^mXmyPpD&k^vIe(J;!^KBjkPrJ*GK#F5vQ9&>K zjKfQ9xtQeMVZ`4aTMertBaMSi0So+@&*y{NvRmxFfYobt1{9YaZWr#{ud}6DzHyCU zf`$3u6I^gbh#f&hOE8e?i``58y){~RKBvQCHT$8{;2RCnf!hv|3+2OZY{K%dZ2Ur36bS*Xqy^s;|kboZ?a#7~uKe#=s zf?UKBAkgB@B`u*r8Pkn@O@0dmW(^`1I26Cb@9;SNc2~d^a9Au*Q42Dhh&EebF%}DK zG+?#Dmf*=?oiwRLHs{0~)8-Jg8OZ_sB*HNKt{GVo{^x_ovA8`@BEO%iUda5FaVki~A}EMkfhyWmeLj;OFpAA$?`6 zPM)kV?k2x104YBBF|&g*6>-)a@VNZuARyH_gcyDOKQkLser9yPJAsGRkiVt+Tk^5WiW+mtf1T;89)$# zcR(=o!C8{B_9!&M$$q-W4U?jYi<1%wjR9}0P$xUQB_cxTyOqYiqA-O7*C0Vd{6jvD zR24SmgtIn#oqng!i?oq4+wBj1vWBMoP*{fpxh4WK@)(pY0XO^#E{WX2ZgwK}MG8Lz zB(u+ty2yii$BRJXMDB?I2h9mW;hefMI4yoyyf1)!(;h&kj_e;ZG$%4UEoQe8qYORM z5mG%atJ8+;Nr5WDDt+LZ&jO>i!l7uokdBlQ{I&Y z??C9t4&$AOj!2L}mfr@4jreGDC@@jQ4NpP+t}DuZd#A%WL8Xz8ATve*2q8eVy-pWO za-{e{U1GSdVnJY_9t_?_fo6GOo+#Q;5Fo-+iJ^*wmq6hMYqSKcb|+OmFU@BCpv7T^ z&Qh-aVM1IApfs`Bd|s!;iqsPIEF8PX8Fa%MyiSdmUxmOR)WFaj)D9?{k=nxy{Gh{a zb_dOfrN~HWGz=jcK8jSyjx!M^;RAh$#?UYa&Az}`C@!LXw4%Zypc^(c4ZO(p5a-QM zXcQYLdmPBpz52CLYeB&12LzD?2ZBM^0*W#>s&T6sIk%Hu8!9zoKh3t`*5I9RKFW23 z)Sv~qxeG-y{2N@S-KnY6x-tke08fhj2-@g2_^j@r;&A!lMG2XY7%z(` z9Bk-ixUtNGWCbBGVDWp9fCga)$g7z(>HU*0-ZHjJSJ2=ISRLR$tkV)i(oAb6WD@=W zN&{U1etR3&hwdO$IZzt`sRO4!M-^y6(g|jG9SVLWAi8VSgr&A{q;Aw=XwJas;U-brqs@o@L=eTVBjCQppiwwj zP>MnI(U?O@?1UA;``Cj>xM&pAb6dOOu>bJW%&x5VxABkxB#hRO?Bo1WW(u~2Dr z+Yl(caEH(%cK{_Zj1->Ghpe6DwhkW@f#&vb)@sSTYLv-OSI`_#Y;eOq2o)(ZJcbL!j00_2ct1ubIQLrlLWFcEYA>jZ=QOCH^O7jHtgqQY* z6ioQxfKWEW3Q^g^Hz6xRTjQ1{9L;SUv||kqA4KaAoj5BZAg&Sgpm)h5CV~WF3ECBK zDkvrt)Gw&|(NRIEf?C@gljHO-1<-SV8-R(R!;Nke@)C4lkjMG07`tq|35Rg+hh?I> z3SL3Bei*3Ng>EjA2QMmL%~!m86FQNO3m~^awSffEi=5Tr@gWxhryVdsvzt_X*;uHx zwR3+#yJpxQ#w3#Whp|aIVrdYj>PF#fLplrM(K<%8h9UzMze{UyvppmJgg~g0n9+iQ z?xW2Y@FJ%%y8|w?x6o6C{%9%BbALghf+$X`Ae7b%F7!^^R+^tdL=L2NNE0I&@bZiC zZB1qrZb+0VUesyszHoT5YiQ!g3h^uOa)0DoFuyG zexKhPL}`rhVhf#EM`K{u7RD@-0vmCn@~1AZ74rZeDGAWXFR{3tMBS+*d08?;N^Rv?R4Cf-Xb z4kX$`55>o~71GfHKpzUN1h_;n7nb8g-xx0~JQnmctfcr6E~4>O;@hPoy?`4KW2N2#Z8YSH2+wE~Ynw}sUC zt4c~}f7SRANXU>?!60CJPQ1rJ!s<0!ky%1*{fJetl&5Z1nI@!bRWzDKRtNerc7*wW z4+p!k6EV;oGXGx1BZSgZ;*n#~ycfZmR^9MG2q_2yR9*;VXx=IKec-C`cM z-inoQMZu6gExw^$m>lZgCBBSytKzv&ZIkz-Efjs|x{1DQ8LHs28I82L>%^#0n z+R%nKYCZGDKR9e+LdP*v#*QC7)Z`nHH$HF3#9`x2zOfG#j2$y<%tUftjju;Ox)Gn9 zLSM~|XgYXwE7PJbrJIxI)L&eS$!ImcFR7S=xd)bEu4rTYgQ2YD@jZHL z3zM#3vit(T^&UbeuF??+x0Q8wmURK({IQ%-y*()?*k?B6rqH zm=`ks7JpykDB`x)Phg^Xl5A~|(6{Qn5vlYTHhMT^|2^cX#qrb0;|&w;tDX#Sk0Hax z3^T=YIfTQ?%J9#LcHf)OM-y|mO9|64@z$k;JmUK%A&p6}%bJV5c4vLyU-R_!9Su4> z`2nGK2+jB=;bLzSnytv|kfWo6>2;#7i`o|bd6bq8)E8!J=wWY_yq8UOq$Up9mqm}< zi&QLtH=aH_3KRqf1V%GcbluL-q(F-t>7yOlmlev2*AiCrX=yj!iNs5{GY66j+Va3_ z2e?C*pN0cOYM6x8i?lxUS#mt=Z2TWpU}p|58nJjIW`m8RB1ZiR<3x`iy>z_u^Z2#n zVP}abrR`{+(_CKhz}}JmqnJUFY(_z;AVm6J%1gWpX=~7iH&Dn^>02Z-@-w`a3c@R( z_6Z=dvk=%arr zEq}lJ6EFPUW+lwRR#|N2?e~FK=R223;8|_1n#n?tdhH zN(x#gwj!UNPV|wpoAqcwezPRjuTK9B={x%*-uu-DO}cIvIi~oP1uwWJ5t}vf2m=|W z=j}>6B>A5E`SsT4LTe9A3MJVR-xjLVe`@-({Abn$PYvj}`SSKV&%Jf01;6KD$2JN& z+34I1Z;#QwS6>>CeCpRjV4t(et#vH)1lt<-@Gleti4S%De&jT=uU+Ct%&1G+C(aAy`xBM7g*l;BRqsd9ry-@9r?(DlurBL;>JJgN;2i7A!3IG5A delta 41154 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 == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) { - UWorld* World = GetWorld(); - if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE)) - { - InworldCharacter = NewObject(this); - InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); + InworldCharacter = NewObject(this); + OnRep_InworldCharacter(); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - AddReplicatedSubObject(InworldCharacter); + AddReplicatedSubObject(InworldCharacter); +#endif + } +} + +void UInworldCharacterComponent::OnUnregister() +{ + Super::OnUnregister(); + + if (IsValid(InworldCharacter)) + { +#if ENGINE_MAJOR_VERSION == 5 + InworldCharacter->MarkAsGarbage(); +#endif + +#if ENGINE_MAJOR_VERSION == 4 + InworldCharacter->MarkPendingKill(); #endif - } + } + InworldCharacter = nullptr; +} + +void UInworldCharacterComponent::InitializeComponent() +{ + Super::InitializeComponent(); + if (GetOwnerRole() == ROLE_Authority) + { + InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); + OnRep_InworldSession(); } #if WITH_EDITOR @@ -76,18 +100,6 @@ void UInworldCharacterComponent::UninitializeComponent() Unregister(); } - if (IsValid(InworldCharacter)) - { - #if ENGINE_MAJOR_VERSION == 5 - InworldCharacter->MarkAsGarbage(); - #endif - - #if ENGINE_MAJOR_VERSION == 4 - InworldCharacter->MarkPendingKill(); - #endif - } - InworldCharacter = nullptr; - #if WITH_EDITOR if (GetWorld() == nullptr || !GetWorld()->IsPlayInEditor()) { @@ -109,8 +121,6 @@ void UInworldCharacterComponent::BeginPlay() { Register(); } - OnRep_InworldCharacter(); - OnRep_InworldSession(); for (auto* Pb : Playbacks) { @@ -573,7 +583,7 @@ void UInworldCharacterComponent::Handle(const FCharacterMessageInteractionEnd& M void UInworldCharacterComponent::OnRep_InworldCharacter() { - if (InworldCharacter != nullptr) + if (InworldCharacter) { InworldCharacter->OnTargetPlayerChanged().AddLambda( [this]() -> void diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index f096dd3c..2cfef3c5 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -163,7 +163,7 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() if (GetOwnerRole() == ROLE_Authority) { - InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))); + InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass())[0]); OnPlayerTargetCharactersChanged = InworldPlayer->OnTargetCharactersChanged().AddLambda( [this]() -> void { diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index 334a0728..ecb25026 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -22,27 +22,23 @@ UInworldPlayerComponent::UInworldPlayerComponent() #endif } -void UInworldPlayerComponent::InitializeComponent() +void UInworldPlayerComponent::OnRegister() { - Super::InitializeComponent(); + Super::OnRegister(); - if (GetOwnerRole() == ROLE_Authority) + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) { - UWorld* World = GetWorld(); - if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE)) - { - InworldPlayer = NewObject(this); - InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); + InworldPlayer = NewObject(this); #if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - AddReplicatedSubObject(InworldPlayer); + AddReplicatedSubObject(InworldPlayer); #endif - } } } -void UInworldPlayerComponent::UninitializeComponent() +void UInworldPlayerComponent::OnUnregister() { - Super::UninitializeComponent(); + Super::OnUnregister(); if (IsValid(InworldPlayer)) { @@ -57,9 +53,13 @@ void UInworldPlayerComponent::UninitializeComponent() InworldPlayer = nullptr; } -void UInworldPlayerComponent::BeginPlay() +void UInworldPlayerComponent::InitializeComponent() { - Super::BeginPlay(); + Super::InitializeComponent(); + if (GetOwnerRole() == ROLE_Authority) + { + InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); + } } void UInworldPlayerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index c1e4af8b..7ac44627 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -28,7 +28,7 @@ void UInworldPlayerTargetingComponent::BeginPlay() else { PrimaryComponentTick.SetTickFunctionEnable(true); - InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(Cast(GetOwner()->GetComponentByClass(UInworldPlayerComponent::StaticClass()))); + InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass())[0]); } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp new file mode 100644 index 00000000..2ba58f00 --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp @@ -0,0 +1,79 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "InworldSessionComponent.h" +#include "InworldApi.h" + +#include +#include + +UInworldSessionComponent::UInworldSessionComponent() + : Super() +{ + SetIsReplicatedByDefault(true); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + bReplicateUsingRegisteredSubObjectList = true; +#endif +} + +void UInworldSessionComponent::OnRegister() +{ + Super::OnRegister(); + + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) + { + InworldSession = NewObject(this); + InworldSession->Init(); + OnRep_InworldSession(); +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + AddReplicatedSubObject(InworldSession); +#endif + } +} + +void UInworldSessionComponent::OnUnregister() +{ + Super::OnUnregister(); + + if (IsValid(InworldSession)) + { +#if ENGINE_MAJOR_VERSION == 5 + InworldSession->MarkAsGarbage(); +#endif + +#if ENGINE_MAJOR_VERSION == 4 + InworldSession->MarkPendingKill(); +#endif + } + InworldSession = nullptr; +} + + +void UInworldSessionComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(UInworldSessionComponent, InworldSession); +} + +bool UInworldSessionComponent::ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) +{ +#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 + return Super::ReplicateSubobjects(Channel, Bunch, RepFlags); +#else + bool WroteSomething = true; + + if (IsValid(InworldSession)) + { + WroteSomething |= Channel->ReplicateSubobject(InworldSession, *Bunch, *RepFlags); + } + + return WroteSomething; +#endif +} + +void UInworldSessionComponent::OnRep_InworldSession() +{ + GetWorld()->GetSubsystem()->SetInworldSession(InworldSession); +} diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index 19087b24..87d9c071 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -40,6 +40,8 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession.Get(); } // ~IInworldCharacterOwnerInterface + virtual void OnRegister() override; + virtual void OnUnregister() override; virtual void InitializeComponent() override; virtual void UninitializeComponent() override; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index f040f53f..4e5bf243 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -40,10 +40,11 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession.Get(); } // ~IInworldPlayerInterface + virtual void OnRegister() override; + virtual void OnUnregister() override; virtual void InitializeComponent() override; - virtual void UninitializeComponent() override; - virtual void BeginPlay() override; + //virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h new file mode 100644 index 00000000..460dd76c --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h @@ -0,0 +1,34 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/ActorComponent.h" +#include "InworldSession.h" +#include "InworldSessionComponent.generated.h" + + +UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) +class INWORLDAIINTEGRATION_API UInworldSessionComponent : public UActorComponent, public IInworldSessionOwnerInterface +{ + GENERATED_BODY() + +public: + UInworldSessionComponent(); + + // IInworldSessionOwnerInterface + virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession; } + // ~IInworldSessionOwnerInterface + + virtual void OnRegister() override; + virtual void OnUnregister() override; + + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; +private: + UFUNCTION() + void OnRep_InworldSession(); + + UPROPERTY(ReplicatedUsing = OnRep_InworldSession) + UInworldSession* InworldSession; +}; From 1937344991286489cd808a064f3b8c4cbe6f7025 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Fri, 26 Apr 2024 15:11:11 -0400 Subject: [PATCH 24/45] replication fixes --- .../Content/Dialog/BP_DialogMapPawn.uasset | Bin 133207 -> 136429 bytes .../Private/InworldApi.cpp | 1 - .../Private/InworldCharacterComponent.cpp | 3 +- .../Private/InworldPlayerComponent.cpp | 3 +- .../Private/InworldSessionActor.cpp | 102 ------------------ .../Private/InworldSessionComponent.cpp | 9 +- .../Public/InworldSessionActor.h | 52 --------- .../Public/InworldSessionComponent.h | 16 ++- 8 files changed, 27 insertions(+), 159 deletions(-) delete mode 100644 InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp delete mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h diff --git a/InworldAI/Content/Dialog/BP_DialogMapPawn.uasset b/InworldAI/Content/Dialog/BP_DialogMapPawn.uasset index 4f3d9aa58704bf78d9bdf12b225109ff3e5ddb42..99f4e59e3e04c663439fc489b0a3c61a1d84128e 100644 GIT binary patch literal 136429 zcmeEP37|~%_rHTAQc|ddhq7efx8m&!Z;?G^8Sl;G)idvznP;o?EJY!O5>gT+WDiB5 zUz@b}wU=b66lq_S7XS0P-|v~b%$=D#&ph<|ce(G*obPhJ=X}rhJ@?3{e{!@r$8 zd2(o3MX6XuQI63SM@2gK6@AgTVe(@KM!#KU(a}$u*1w2g*X$hJ;g8hM%YQ#bd3wUA zs~eOfSg%1JU!R)Ry6V{L$8MQ^WJ_TMg57y(t)Wx0a#nr%PW2V^ zaao6tUDtg@qfMKi2dv(EeI9x~tHJW*bL-CCGijrOsNs|Xf9c;Sc18P8q0d{xyc<7(vWzmj0zj9B~mk@&ek zSNgcslDMtO%^MNyou&@u9J*!}xLtH9r<8Xn%8zu`rEjg0TPAdB*`Z_GPVpVvC$($W zsa;&lR_!__Cw1)Du1%}N)>K6tDRkM`P*F1Ix~it4EKgDt>O(odhoW3UXG=QodHuQ> zj#i(>t^e`IyXz;ubm^Y;PdNIe-<>-9!2Hq0<427|ee{C?U_@n=1+`)wRq0ccCVi9I zHR4{RLd3R+a-;Ilv5-1Xw>I@OoB3-@E^H^rcig##GVB8&k+otakQn+ zEz;a$3OxBaacM0Q^PKqw!&}7n93nntI176^$GDrD0m_9NHkYkLZR4_i1)hX_r`N0W zZS}~G3joT==~K`z&o!p7z~fVPy>ffUi&f}or#st~(=*SVnCC6bcaBpg)cEe)^H7wZ zpIMOO@+v2*eHpLz;PE)e_4E`Jx;(ydO4{1b^3F%KG0r?+dVw>?m81NA?9JU55^NZ? zEf|wXjPm6bxRsMXT<~=@fD;Nvj&!+w@kPUi<+})_o7#+OepPy96sCC-3fx{_a*;b* z>GaFSmmtXmOmq8Oo?K_PE5VtcugsbL@;YFpf}TYlmss4kwbz>Ju{4hDtpWk2C79_>z7r6>Od2U}yQC^Pn*14DWy-W{P zal4)QeZ8(Mcm6o#&I60DtD&#Zdz{zj8rjd~@q*5YzVn(GdhIi=(50Mz(d_+@qhSRF z`AYLjIY&WlJbm%AvP!wNcSF90WsP=uJb5`PSt{qM{Ce*V)lt1?Kc^?pNnA^Gd9yuv zg=*>T)f$|Csi8E(<#Q%Feaq@m9@QH`MJbgpKGj78Fuj2b(a8HzdUb| zGe2*C#-lzZ9_IKPSx*qih|&plkZY5+R-0*sLW;>1PgYH$wBIV% z#@~N99goEE4Lo~^KwX>i@p@mhQcuV&g{Fg3S!phPZ6tpVctL6exd> zs}6sF)+r?89um+Tp{93M7|;hc!DNw@va4EOhh77WuQKR($^f_vDluD4<)+!I-&2u* zSidV({yy}ls^98}RmZwy((cjzirR=b%yjlDSo%KZF<`+vmTsYYIitMcH0S0_MdR2a#;vh_s24Gs|EJvCcgI^Q6WBK*{-l`i;^EV`h)#qHRBl`O z`TbW>Cp}ujddQ%HE##1_A|H8j{;Jel``NRI_qej^G*lfP!tvd1SN~6dfIJ4VImfFc zG|SwGQKnN|V6=W-<^0-Z_Q3pPII}$k!U`PCy!a_p*Fc)ot{wDJF=iV>X5XhwIC9%H;E@1oXeMlWrW;HJhjej> zzLj3NRX>0=CLJischOSB>B}4KQVn%sz3EPfa|SuVy!1R;MlB!SZ7=WvxqqmWeyq@4 z1-izt5POxSkN>a%`~vsY(f@ZPR@ymZ5~GCIKZiYNIS7s3QI@hZ>!y)YlD ztUCCg%f3|kT>4U=dJ)CdW8O)~qjW0Fv$(w*jy3_zg= zLswfgk@1;Di*L7NW@6Y`ZYi!q2b@0-UV{OQM5)zfXbVvw<4zIT<|v1Lnb{2PE6Z&x z@VAWld~!BsT8QZovXn|n&d3ES$wtXNf8^{8Op&Mw3-xm4PikQ{vc|Y6Hj^HG^|DXD zLJ-)~nSHZ!IBXu`bed@q6L|~CGAUJkfE89i#81EXM=f)tEiMI`V4R*7at1v$=TO~n@9}2cloq@inkStDK?l?F# z<=lnu&c;~vONz&Q_3j4a5UvS#N5S{qTVW1ta4| z78H@14XHkJ7i6+`_6XNVr*d-Z^f4G0g##4mxN_K?s=^;Ped%GVLRE>oyqwz~lJ2Et zhB9QyOx4Qkq6#$xd9LH^+puoyjl~SvF1V~AebcarOd6|nxu)%ISa>S!Si9s~6QJFPkcuz^{g z99mTMx%lf5E$M5EBsVF8s|CDHfyW;u^>TR&iagmaZ;ReOr#r{#$x(fcSDC*xV*?h% zy7Ui)ktP%AU%4s|rvA3Mk+Hf(wn&q#*FRWUwtm?9$Sx@vbt-;qUA4bIuoc0L^2V0) z|HLe{5aQXwPo{9ENA}*D2zScG2?ZWkU&*%L(wcR}ymOggmvU$99ci$E43-RtOG5-k zVxz7bJ#Vxh265*~eKS&&_Je+m!DQ=Tg7wO(!D(N>Ncl_LLAj(;o62gQ#h)!QM%9fM7B&-k7%e~N=lGBWW!~+#9{^%M*JS=qS(*0w z`;aDc0kv^WTk{#x1tI31YL(f%q#I;T_$uXsZA))Nc1EsMhXgD@sL7RS^FD=X@z=q6 zp^$7f$)PVV+p9cw&($x0^Zp7w^1LHmK9TB5&l~1(QpRCZqw`zBHux*45_8V%q(L!y zs1Of7C%JWc<4@8+oNVo1a1TjI${f-!u2))Ie0q|ydcu@cu#Fup+i2zDB`xPcOXccT zDOa#@5Gu;=!o&~h(OTKE^TEoHtt8{xq3X=WPr%A0xr;_B{r+=D0lc>wKnigkw9GLG zTJJ~b`SF>%;8e`4TKvX{VbE16oWkwuLvgE29*OC|n-@LPnW$Xj2vNEX^wd`?!r=rb6^&5KY-(X0!5e=Pu2mtsGy= zRG+GG$LB459j;4PCIS#Yug-a-!_{zoTtkiK{C#(PsqQ=azSUA`L{hH#aExw9A{nGk zi?Tm;{~S0g*{J|}?-*DUlFUGL^-VESZ`Y_IHKFpt2gqjef$5C{|EBZ(bCyGS5OGH|M0yh0OADLHWFR z;~WgizZ`%SLYcY= zf;lCUWoRRp4Dli}vS?h>MJisS<9z=4YPF!qh!mtmRsQ<6(HM%^Uy&L7; zJ7lBYGeqyNHtRXCC4r7m@`wJ)+N^huje1+Czpn(^ka#y!y+1?L`#_dqe($nb?{15F z>@QizsJoM&S=3|w-7CwWzaNLF$2RH+)mvbr-WOD_ug!Y>ZPfdm`Wt1lUMPB*4)k}@ zMt`4BwI^)U+e`J_HtKyq^>|;4m7MbU-lKYZZ1jhEk6YAZIba)#`F%S?J+`5!_l`w9 zmY3gT87|M+toOXldfRQ*+iA1j3pVR9ZC3N4rfd8${&!cKBMwxO`Q?^*Qs6~QG~y}Tj6RHCc8U4gFH z^~DE1Y2O&CUAc_9HS~)bUlQyy9sEt%>^!(@GB)@aTCsU}ovzLVOKePf8v>cVFq@LZ}8@pG(`Ddw+Cr{ciGKhY1II2CfN` zuI>*;2N#}UqHfg#qVOf1jO$lP*Q*Ol4;TB&?<8H%KO7xg@0#fPN=Mh-(#}7%Bs#c` zn{XY`;Tk9D>ae2pa4`>i%K2LRRO#UYIgrD2Ntd!VI=Fr{@$jgQhl?d$=^LVh>lYKQ zuXVWUNV<+a9UWXh>u|xB;QkeQ1`qF*C@MV@9b7-@a6y-G4~%ium3DsNv!#cN<&bf0 zd%pB=u^ck4eJ?}@*N-M1eyihQf|SF*UoJgdOc&#d+f{nFIJRM2Q+AggE{<&&*DG(7 z9xje;7+1wTrH2c8jFWL?yj^;@IJUV#%Hh55MhDjqCYi^*Zr0_6(r$eHespksZ^DK9 z<&2AS4tMS?JzT6`jH};)=-~R!L>KPwqi4v*aEYS97tz7>tqB+Q2rw>sG+I4o9xgpx z5DC!rmz2YqM@kPD+o)QSuDg$w9xk>~+az62d{=t7*hcYuW#hT}2oDkif9%dptz?63 z6wg=oFQtczZ4~1g`djJY;`LWGDI0_Shz_oAbbN)ZV{Z+51|Ro9AnEY@U3$3KM!h6) zWtEcxDNx(`Yb6_B>*zu!zssJ`d#+p)U4oZc$O9DGq0$Q1K^-pi_`dA3F zEQgG1?8VW+wO_|W^thZ(o-e*XHQ4k<4yqFNpl$=~Ayf$S1U<&*1Ui|AfJ5xrj+Cd* zuwNJpXh%Jqo2cJ5bZtOq9XdPH*@ezpbk?R5GJQ3j_2|S7U2KHKCg>~Z>_lfXI$O}$ zlFo*7wx<)hS!@MHF7r}4>(kkU&bD-3NoQp`W9Yn`&YE;yMCVm>B3E6PPK+m(&gOI? zr+h7)*U;IK&JJ`Ue_n&mZgk?_TRS?N(usS*t?2}fjpP+P0PP!z&cEsWi%!5m`v&@q zE51YS&<>yZN*~n&yv3L?c8nL}iJ=pG$5=299y{uSN8lCu2d}^*@EkDk5#_)Oy1`p~ zMtk&y&!9P$PK+D8#Jm8BQ3vBjJB$_IF<0O}=*M?l!4tso9rA$s_2hTR&kOV&;{!h-OQ;808qf*4Kx+)0 z=m($c(g_|wX3-C50M9UYkTu`{jgU9ghpb`z_2qZS7vv0hFjuI9zEKDAh3}9R$QM3i z92gJE8`6pPEbkaIWC&$|p&T@UPk@29fME_XPT&M?j0OGRJIf?+;ydI3bTChw(`U>< zES=~Rbb&t1Q#}d8XTX31<>&`;j`>6XXoo&9r|1u~Vg9Mf$vt%9J7`B8j05t?e8Tvl zR~R$k%$r#HjJ}y?;4_bhxcn?|I9KBm-_T_ zLw+t#JOS7oJv3D9a3(#NhKJnoyu5hOIZPu6ac0p-e(0E9ZzY}}!3!lYWi3^+;U`T0 zP9-W;arz4r=|&M8AkA7$_Rpbsm1xS)phi(km>?e!H z{czK)(ZRHmKm|||}AZsj2BAd_3vek9!d?yk|i-`6SDlf)US-A3Z zWqTf>HJ>ZUT7^osax?XxLs%RnyV2n)kFlq&_eA3EFp^0~Ww>(YVQ3nv$k7^Q#Vjcm zqeK&rsXI{+PjcxcYA_$c;FY3;mw5%ey=kU~)9IzNfaVOE7OtG_Lug)JAV-^|Vi-m? z2fEOoXcYEG!xOq6)`BcmPcc63Idr?462EaS&3a##B8NhYuSU%XSs=2eGNQ&7uBA@iru72W&(X0L7xkh>!j>DD9jRAtjd^DjbDr- zGLOqRG!Mnx(ePW9)sSOjt<^ZG|HNF?&!JuyHO`zW9qj2?Qc`KoZz9=q(BegKF|dTK zVrUxb$@ZNnhHXVzfnI#cK$uAOPsiJA^t z#fp)fDy{6*^tMo&wa}&PYeLh^mM@t&sM!!bzM%@{)InL3=+MO0A(femX! z7C-d(Svs|`gOZ!b=0f*c=)A#Dn!OInIKoytN|dli)+p&ic*hf6xoRYjSkq3OI&wUr zDP`ZGr%%J@P-3D)6-$*y72<`FDnB)=Y+YK{79}lYt;S>-yV9(*Af3|wH6uB+f+ko( z<1L`@Z>-Cws)5{I#7tQAiD)bsynd8sfukm|K7wZngj^|cg_avG?MZgBi1ZDA>yov~ zRpoR9MORpPIVejP9sOoc01U&a_rMrCe2oUSC}Vq%7y~+|(bCXXd*)~^Sp}>O9h9jR zJmA0KqZE$Vu!0>)|N0QUB0FJ@FEkH$9n}?Un<9!1{#WCc#*EoQ_B2b7L^9t-_1o~^@bM|+uagPdmOi(pZ*5c`4zC}t`u`Lvg-7q8esfS> zUf^Th*Jd=bNQ^BkJUJp&tXDLz&URj3T31)z)E3q3*Rhrk9eXyD{n?j!9)BwJT|`kV zVp(ncn#V&aq}y0SAB!_5jWrN~hn`c8fQ{>Dj;FEiv|8gfx5YVL85t!KIRdQahS9nf zwnotIAm0^<47MZrOCjlMLuV)Y+>T@m*G?pP9c6Ucnm)(Vw*->9wgii(e~{c1s^y>* zupN9He`@i3caj3E{#sCP$bum{vf@!ITm3WD!h^T6^x%LZj^=;Oh@!6atp(BBS_cj0 z!CTuJ2~%p6gu4E<6=cCWpMsbc|4KvB+S=-yeTP}Ltny#&WRI*dCAB@AGl0cPpe#Fd zbQsAOEYUEfFP$R@6Jx1IaTM1~B6xdSba4z6n6p403VMXh4r@{xjl@O&5LqRYCq_o+ zCaQrL-a-0dXO=jk06lJ*dD8n12kDcYe%SWv`@vdB+;MQI8W>(?*gooe(d=VqTO+aR zLtE)~vDF9Pi-@P%*F@AJfofkHQ46ekyGGOk^3=^%3!dFHPM;!ha5#2tze?6Wys*e z;s^7JkdE*&&FiU-WVt)3{wkS#Qb#q4YE9o;lT}Bw1kV+(=1$tvwGDl0P4IZt>vd4I z8L|}~AFuw66v2|ia_DKYw(gL}@K{cTZ;;>c7&x~H%jzZD3JGx#N9?ratW^Sev!Nud zh(53mAEDkI9c96bp#*afukG|cP}T~x(ui%4CkB@xH!kXx?`k!o2*fxi@$|i=VRS9Y zv)CPRiwNq1I;_xA<;Vq<_*+dv>}F{>17y74FrI7z=%rT(6R)#X`n{CT=|U9xRNLcK zV|6cK<7_HQ#QhtsEKQCkbY#I}*4q+LDAtjItDWw)dSyLLBt68+M(Ao1>1i7}TNAgj z25LhRC^DI-lR%%_tC}27HQG~oJHpk&7Cz28={boQ6Ki2jYH&BC1<9o`JI^txgEEYE zBsMVWG{%?68zH{zL^K3Ooox-!U{Pm=t&wo%Ay6(dZMA2QhDfi7xZ)*!t82IqnI-#S zAFepcNC@Xjky{x_d`0f2r!B0U@5m+_f{dPnv{cg}@rk9~ zDx_dM(S>~)W9fu{<)~L^joq7aj^8-?KDK(}Sz!)3C<+&&2p4y-Z%I%s74DSh zQA=xRKU-trxiQ+L?i6wLrM^Xk&NA2ER*yV4$hCB!6A=MyQak$BndTv0owF3OR){82 zs1C{#R9!`l_Ub2iv;ns8ab_Uc{Qy0$v^xUV+v=NbzKA}>T?W3h%ic6lUwM9uXqK?Y z$)Vg}3mdoV>u-0Xt#)i5QgrrVkgb+HSFK1Vphbw}5YfSRV4m==9esk{hBBzOQ8dE9 zb*qDRB--hhrQ5n+{pcM^zO5d4UIOJzjFux2A!&#cjsMto+Kmx8M{6ZZUC0(9`-fdi z96e#*8+P|<(k<%LC0HTxGO(W87Ts)}JCfx^ZoLgzT;$%{k;aK!1@ah(Opvb-cZcBB z@EO^TM5>LolY^wr&ddd_SAY*YOArN#``lQsAmYJF4Py~m^1yrI!PYB{18pNiT2T$?68?p@S?qtH+mHdDY^BLyr1IBX_Mo?-fmsjp znjg99A~n|`?wMzj?1A2)NF4pq6zto9pp&WNKvEo5o?V#w>4*zS&T9ME{##Ya4 z$@Df$WbZK3Mw>gl=Emj2NXcah$~eq%L@>^O9@ld7jlYAxt&M=EtF#kTM< zCj}+pDW7PoSB~QK{Ruk-n+DC8WUC+M2J8@4h{(0!D(++>=h%jLf%Ofz0&aja@NCGm zAm`GG>cSgLmiSnX{t5S4STA93gjeXRau0rLN<{oau1e%KaK9hf*G|MaaHb7?f>j4! z!9}bQ0mbSN@dLP)L`eTy8*u{;U4EAbSU>kgb$tqD++iJL}u-% zZ$xbHCxD_HD-zgE>_EqwM8tNjsJt!VniUZ~j9=_bhfP5|m`MLH2H0lcLpBfJac>CT z4HgG>8d=#C!ga62r%3@vNqQ;JcHkp+^w8`gV=SKEV#^R%a-S_)cnzt?hvy5#&P~XX z$ixQrKigLSEDP8p4jyz?=LL2d5`lbPJpIKiq!4G2!GpZO-y;VK8;*Nwu*-97;bVG& zW$w&$Xt}$&w)*G!;k4-qfM^c+@iKa znP+R%);58Ab|??p>V@S1`B-5Upp#f_CD7a_(@Z1cLo9=5KswO3B+^}IP+Q_KBA!kJ zizi(3ZQM~jLa$|76zvV0(eBs5<<^#faum>74m z5Csbh-cH7Bs0ryoY$xJihw`v3e4Hy0G-woai{T#Xe!&cWXs92KPh}6X5Y~;wZS}x2WsCz8$;V;u7M_~do(Og*t8Dej zGu4@9rlZs+>>v_(Q>?iW4~qP12daZS2KF$B9VOVg4{bzz^^`4qytgq}>}O4l76God zg@q$-@ERFBjnivvwdV-Z*mkY0w#-rZyEgO>krHefBpY!Q>=v>cka<`zk>?PW3@a1t z6v2wjp{$emIGPBbCE}P8ai^Q;#?v*p4{m%yj7QjyxRXsj3U8vRtCO9&6dz!P>Lw_j zV8Lg8>x}lc0pvl;$Px0|Hdx*8_pw>F1GU5IdA;=#FGmR4Nc5jL8)DR#(7f4Tt7qmQ zGy(fXkj+ArjQbA4e<3;+>nGer!wL!>4l8Ns57yI&mmSJRTlm-GC-TP=BJ;wd^A zMstm)l8jQl$yPs1F`o8@e8LwYQwOhvRU*6*sK>eie??YUJVA!l0U}0F?@%_|!ly-R zJZ|Htx5!@X>xR}N?zskPMQzz*f~7`?yRT=bHaugCqpV>@Z4h@w1G(|6tv*>QAoJ}> z5@6Tx?f^)FkaOg6VFSe;IMfl(dm+05y=YBWL~mOqK5ga4HdsGi?Y$rR{WgK4XQ|iM z(pxx(vdtEK))qwHYas6DZ1v2XgGa?(P3-yuZ;6wqAPe3@kE7-=G3^SS<7wgu+=ZeRN8J>%}?*N)dO=; z+*tt+VT&M9u(7x%5kCrQnsg0u(DVi!Q*ryTrWy|Z2uz9G;kJD`BrQ@{U+VV757Dj9hX8 z;dXj|6h-Hkq0Px34I>b+xIFwgy^~s#UPDx=KAldN2$jad# zu2>m@1F#liPfa3yf*e5$@DzYU*<}k~Rapx(7%4E1|213v@%Y6a4G}AdnH6^v5G!N- zA=ZMJUBpb{J}T}Zi`}E}6uTqB2TLk;SYz)I@FH>%dqp5ofC$-v4+9TT1D*`rjVD~M z+rp=}4E!{Mcr(u%w%W6e)qA_4beD1%SzE;4SjS?Ohc`oty9#gG>X-QrYltWenOodh zfyEJPINVtU-LRaTdfO+MPsh9@P!DQ%6n z#}=mYvKHS5aVY<_)sABWaFpK&V)Tk{N7xUZf)YDbj5Gg^?1yc1`1Kp#0~UD<^P2&9 zCz~iOowp0{3euQ2FEB65qB6lM-310zAb!g2eoXuwuitdH6PgOkH?QZ7`!^HGIC_F<}b`UE^p`Su85l=gm4rK0xKkQUqtvsE==t60q2nY1s}0~gl>q@h#U*#5_h7( zedJHDU)iC2Y75^GSt~lbR!Vkf=Ev&L6_kfK|i$TGh6t0XM>=^NP{^#_}o^Hy!wY% zz)mPHWt|c2=2Gh~Z1unyyHKMM&&r^8)H35aEb-Xar!ya+T_(pIifXK0&F@hD(iTry zuEc&Q_#R|Yur5QK00|R2fe{yA=MSPV$P#n}wi()lmAOOts>HlKbMZn+d3z)x-eQG? zH7GO^{6ho*3xv!%;y|q75dmTahR6`nE7orCj@Vt{P>x2-TaJW6-~Hg(Kb!6hovK&( zI>Na@Oo7M>*+j^_kZ|N%g~TI9M&=1M#FMKcMnOb^IQdva_(b*!GYl^zGMC7Hz{eow zLj(rTgLMIRLEta4m{`dp59Xj>@fFs~US>_~C4g6euRyi~y#ojCJt zAc+02R&XfaMuZRdGjTUl?CTIaF7eC`EC<#%h+GjLBf1pt&H-N3M%;&J`8$bEyEAa9 zghaL{jQx!{Ywe@nLX~|VfS)r6`uBe5-x{pFPgKi-V3&!{|D*@6g0NGjko*!dJ9t7K znRVXFiM)?^gSz&{a(lIZkRuK)5geBU>l2ZQehfd_>eV`rW#)OZ>WlGy83+A(VkGh_ zcIrY?5UoL9#IqQPf1nkRDdYu^;ew_>XCU9OrtoPF`X_7RNse8r6l32degOdQctKQm+!lr_Wv$3D zSkeBQEu5U?!QDLVy}gis@iwU5#8t7w|94ycF~_wYtj2Z=yu{alYE zwI2O;SUr+fl+`0C7T?>+@9pLH4)S|P`Ms0+J(u2}kWUd|v? zO%0fFmp(Gwh)P6@l3*VsMkHzpbAq8jrE-gX=Lxu-OcYCXZqBnTMJLTk$=byfNxd zG-2P?sTke)DHznUVj9(}K~+ zWt!Il9`pt(S<+FH(BnO zPfR_JhBXbj2Ya{%N!_uM4d_%Pnx@yndPFUv9w9MUZ3mMLE)x+D*B6vp>i}~>aFkp8 zf73p_E`jr`V^%!lGJTss{X?#p^@{Zm_hA^u`iJ}&qwZnYoXK}YhgbJm$QW6UYdaMIFWY{kZ@W!D8N2-^p9POJFWPGJ9h#{ z=(sbw{K1|frr(M`$TV>|^M|?2++hy09YKD^9=D7(>vYTok6oJ!+@oZ^vm7DQ#W1GQ zN>;HykL!h!Rb(VYJ^PUo*AK>Z?1>U}!pWqO%g9Tb`$m3Jz?fS55^wCilV93HtzCEo zk&PTV9P`L|K6%{sxniZM+*@erK-O1`BebUeD;@B%`dICsEFH*p^Q^OWN9n%g$Ho>RGHe(pOI7fhvBJk=iX0zHr+s|(*9Asx2X#Dl``FNmWjP#m zfi@hiS!y&ZZWV8#Ci+KI8QPB9jks_hmL)OJ&uhAhdMus)JK9>3ND=&EPK29lvuueh zwOA9dbpT&kpIBP~v#Tvu@`Rl*EG2CBt>sC}N}qmtVvYIVktfU>YjR}P!|rScN)+3J zNbqU*6(W^jVV}$rtlg8)Bv|BdQB(6d*a0HsG8|qjsTL9{Y+q=p*2gY9B0Y>pWYM58iGFamNPizXlpl-6y1b-O7_XMtr-BxY6|{uY4x=uX zuHIW)$4KVFo_#!<=Axvl;K*mfKBiNj2e!ST{nWqn02`}WBj}@8>j#e(u=AI#5J%Xs zLM#v3z6?NF%R|otYO;;c;sq@((V_({t_aLTl+-$D);2O*gi&j;Jg?Q64{VE1rFXVG z!J{1ey<6#&wr@r6XSAIu`neSQPlWej+N{<~rKeNKSg>9P=LpLYYHMCn?1!=AZ>;zv zq9Z{&%e-~21ka7Ic7)=R-Bl&lefDy1c!pnKKHYl25+8g{>`ST9+hYy`bpTL~gqX+R z67xxmGDP%eXV#5)OSV21`-bdbJ2e@@+YA1cF_t=(fN0B@h~qJvjN#17*r`QO_N|zH z?-^5XW$XX7VphA(&3A``S+V~;3DfUI4DBbiJ%gbm!{|$xw)60R$4{0dL#0J|kw(2G z!KQIN95yT8sM$SzoGSKIil|JB^z{4oLfI}nVWIg^F)HgFd7;)E`n#XnPC#qP(sCZ5 zA|;OE!tu!%v9LD`)iXy@k@YN|FXPBE*eb{VzN*0a#k)i}o?)wDwR;UC!HkL-4>h;{ z?ocxOpnviXCCt0Fs$vNNlyybFPStj~hW0F_w@zhgj=nCIUe6`5=_R)(ut3n_P#og9 z4P~ubQSLm@p5XpEuLZ;V3%mQ1A#c(37vc6O|5N;h^$b{L3H6p<^VoV@AIhr#tFgGJ z#P;uhO=GPryxx!N<%KOz>09_n;yc)#@Rp6~)Us4st5CL1-0jp$04!2?eD3#_-F+HBh0b#8YhsKtnZcL?;esqK5Vj@D0~era)x z<`1O3q0n9}REF8wQetc@YtfHe&^xcOg7?mz{nS@7dj1E;SJLA*?;W`pV0mnJ!w)YVh-y&6p`GjN3H29d! z63H?gS-cjWf|BA9E9|rXO+Mfo?jT_AgV1iP-ORjaJ5*USYL8uJ*a;~1Pw=j7J3G9g zKlq0Xq4*V(PI6qluiFYYmo+2pf$n3M9%3$h5>)XUeym#yf8LC0BVI)ehx-p$p9;@` zJ>HN->z(Xe7VY-|MY1a#mV>1@w2g^I%wg@J82>+6TOlow5q*RgXy>h?e5~i$_J@l4 zq8sHyS2R0`IWWH&Cj7jV)X$b)&!;1gV(r!0(raE_zo%L6(>WRot#762)3tfWsH685 zP26J>zCh@K(P~EeUM%)2LMM!U8OtJn2iCuStFv;p`7KDieJ$dM?O!coT@W_htS4Oh zuNGxi=qs5 z84^B=p*WoI&v@y}i_ zYx>OmkIZ)9E-}X&!E-(Kb|G2s=Y+iQ*ffc;&bkOG2`?|v-EV*qvR|>zhS{;O=!LTg zJS%|lnkce)vD$UOT;zNdkD0OA#blK$5#CR5Uek5!J0RMV-J!L*^n5FGB9z41<%Tgw zSb9BccY}hD+B~BrjR?Y1QF2U!{vp{U!8_siPW?UzdV?Lq&H+SDu!!8Z&}=K8%6Can zA1AB3$%lta?9}10^Yxhdm!RI4EDH05q ztTVFOJ@qqXV@g+F2mPx>Bn$s)kk-JTR4^J>Z$tTpl5> zK+ev1^;G9Uv#Y%F($QJj-O&O8-VhZ6&M!Z9nb4zu0ekcH275c88nI&|DU8elv4fdyfQG zH;{nN^vkT`x9GqZmUy$KYwf~~%4h?DMe{F_U_?tEMdUa&9gY+y%Ud{{;J%_mzw!A+u0l_q+h;0mqg;&Ao4&8iC8HpxDBqRo9O+W&F%L@}tEkh-k}#m}`q;|g5@(zDO?J(GrH z7I;QF^OX#$a}vjQbk@sm@woJ!9%1Nq+Ad&{6`X%Ilr-x|b%xP?rk~K+~6=^7{&T zg<`1(#-HXMQ{c(ZiRta~dh-h0%9XNgmAp2WS4HJUW%|}5&pXoP>zzHqHPWd<6J5E^ zqI{p>^MkV426^@K@*F8`56OaJa|Nbop)9!ER3T1&r>#HYfEmFdr&lRfzbOjOl8TTk zF|dcMR9#*JE-fXbSYG`E+%5sF^@Y6Un~3Mzaz%hnMK z-xG;dS5B^-l6lu{eak$2U~i{W7QT<8A$(+R#DRG=315ug%Ks~dl1rys3>!$itV~zP z@5S<}l%)@?r*e)J--HxWq~bH>fYaKN(Qd1gJsZ z`+8lTgaWsh6f)aK_D#5O6@)Yv$ZKBWvlHahXfg-rd8jL?_GfhmL>&BFI>$7FiS` z>YFbM$I5F*c`cS#9-jIY6x}Qf%r^8U2{$`-{V)+MK?5q%39nI}PB;e)1fLn%TKbH` zp~T3mqNx0d5#Kf6pgc`oGSzu%Wzh_(gY!xW13LD`fa7~P`YWc=KgdsX-Hnhp>Sub9y+16H{0IWPTm zgct>c1BZWp^o|yz&Qyzq1kIG6(FoFn1J~*5Co$y<VVW;#zR&ycG3jR=N!Nc+}VT^I;oAGB+;>RYY zVIA?JU3o=GUriq})po4zFc@Sw1`bi7JRm?XyUu}5Zx%hO8U(8in7&%gezHRKOVlzR z9J(0s8jU)jMfJf0&pi*_;M7;AVK~`OtA#KykZ$x>H>jjW473~N z0kmGG_OEZj)bk+F)G#UlELaN75G=j%R9VVh5ve?LM5>U4dXjdPxZNO*W3uex6Sr2`w%+UjAtYRYAN2p_c9b;7| zvbvln_5~=uEM^0hqZpE>FS+6+G>m~aP|Nh45*Z_Qae=;3-7a!~{^3YSBJYe>`D*XWnnbkvOTQERnwH|OKjUZ!i z`fW5n1IuqA)(svg#H6llg}!SR$S;0L(URic@aaWRmF>-|J+!)j! zbX24havDP?4%E8h6(Xkk;3UH!V^B&5DyY_~JmiRiNJlYU<>B`$44^A|XU~LX0S>@$ z;EHoDzNm-42jQ8nCLq=uG-)}gsGl;mCHDxo$noti;()FAmfEPR7{s}-y`Zhu6J)bO zwuXg9OB?~Q_4zbP(YitfzpM5WMJ@E7u@b|vQe2c|dA(I$11`5n$TWF{c~uXH-+1}C zSYG|;StJ?tWLbejdw(x$sbEU5!iz{;Cdon`Fvl=ANO-_y@H73!^%`Fxb7sHxk6ig^ z^D#UGRAjW6!g}4mn$YlScid|4!hTa?x74zNW$1cWCxB=c6Ok@U^u6mU8<}n>2=PVj z8Zw9DN;-QS>)m_LTb)wwT>0s5&sTc68{jDCI{0orK*zd`pO)|5|AF*}?mWNytVer$ ztYA;+8X9PGls;|nHucw3J(#?+Q{0_%TijFkzIv@O96PjqGWENMe!hHr_sQE{dG(cq zwj)5B8MYLi(V@yCRIEqq%z_-3nj46BdR-X_iLQLtaJp;U+m)Z&GtaHw@kPZxPS0?c zPrav#4wR|tUu`-e^%5j5K?T52%lO4G&(~5}{Ovt&zq87`#EEZAYVyuq7pSqj9bT*} z?0R_f+wGI4?``}2H)%~~sPk-sA-93U%!|tiMwBOe@?7qm{Bg_>pUR5zRH&w{HBNA* z)j%){;mMID>)FhOQyR>vd%;Af8PY7CMhz-0!0%6L+WI(`EVn zi+26A#R`^zM)EMIwNmqQCw-uj|d@zXUJLu+wI;?!u@o4iFOTFmR$S)w=$cU41IVJ)ZnPZ(omJ z`tO;ChM_poOZLnWO|twRc?kAiD3kTL?3Rs5P?J?m3yUeTazK0r`x9{pcKZthn;u%8 zlR4u=mx;e_Y?jGG0Fv?&6GHh%ce`I&*JyW-HD%7JR;kyy+pJ(`(w-sK{N(WDzV&~Z zoit<1jR`eZJ)o|ULd`D7108?-)N$ljV>Txh`|kbo+ATjHwt}4rdxr7hutUR=3Xksk z^xc;dw!YSI^Wh(_KMESmuwZse7fk6slEA9^6A)KHl+|(ZAHB>lEZ7y<50n{t2u2{_ zI6%yX1!Eg`8T@+I1K*Dvbj4jm9oZg|0! zG-J+?hkrYF;UHiLMjK-X9hEN~Ijz#oD|<|z(f6BWtD0YI1)2w4$FZf+t`i{8 z3{$y<4(Tuw2-f0YIeV)l1R|A@SddxZOE1X2Sxszc-_+jek3l3t(G@+v@Bz^hG?YaO z1_u)!)Grj$iXo_9_`a;T(Ttuh#~(U)^{>W703_lM9T7W_2kVv{eaV0&J)ZA+vis~^ zhfeZX(HS`;^?-5y>%gT?4jT{~_t<$){n;?}f>BnmGwDF;(HNg@6w~*~uSRCh{i8eW zNEoIvE0h?3I4j3v1v?WCgjE;nW_I8hyB*qmpT6+<{Hbx>?;N}L*4z{Iz6EV&Sd<(K zbOFQiA9`8x1H*hU*epzH`mWW@Js)Hw6(8Gt=ic0yHfV2$@Ppg4bDuwy8@G1+fbVx4 z9X$_(n_=6~nLLa(%PFBjNeEiN{m~Wr-%|c%uz^Ft=)hPj$rhYll|=p0nz2%2v!`2CCAYK!kpozm=$ z9lIZVaykzIjlgRh*o*Q?YQ;D9#ZF;!Bp_+wGUuah5LpE`Nlq=WUXV2ii`T@AAB!1@|T(4ht`5be~z<>_y(GvDh{ zml@&{7pv$%2M#3plQy}P8`|{kv8ma6O>o_ zH|QfAqDMDT!}A zQLLXZiWbxZvuw_ySivlvHfFbC(pXnE*AE!vOEC$LQR1*e$>0wT+%RQvT-K)8cUph4zRpfiVunR- zv}#c=BGFzE`S+NtVK=$5eKEaUxh{HIE1SfTmsZ?2#%nnA!euB3@x``9>m@s3y<|O! zT+=b3I3m{c?yhV9$m}*DdCug|Gy0cl+29m3J(kp(DG1PXNI}G!?k$-0(Moql+{#WD zuJk;zH%31htm*L06;j$Azi>}N!nOlR6$bM-sS#+2nrgH_LbeT z{0EIXi)l7eWaR)A#7sr3f~_yRdgyJ(S0&88Zt2P@lMg+{LjaQU5)-x;PWU-_O8xt* zrEY#@&6YgZv>H}0OBF;Xr_I^cA!HY1o&4VU{g$+Ql7`jzVe@^e0EH7`Q1eZXi>Gux z_I295Q-AV~I5D`670gl*H4017*@6Nb-RQi-d2~gOD}GA2<4~I#*WLKaJizTx*yQM; zH|y@rOMmvFt5W}NxS}m6G{YiS)5g?`biyh0ymMi`b6iYsA3f8Y?G53OS`;3A^G_KTTVA;D+g0V(eh5m< zFg-#)rMXlwF56e&iBX>`uc-U11y~g;s)aEHxiO;LR}hn%=gw&!lTqaL#SC-Bcne+G zdAWJ6oEYlKNY*IZE=N#dAON9=M6?ev4kcWeyB)fT5v5eK+3 zY~V+So>+fh=Cl9F{b^LaM-N)TESH^F(f4xsiahR^eolHjLB;rcIv4-Og2I5A&`AwU{?=_yacWJyWg`4|@lVPFqqm8L?|Twr=JR8&}_uyx{vv-QJrz{Hn>tUm@>JTJis;S$Co?(RpX7! z729iM%=u!DtvjorV|=lD_q@(eBtG)_+c)1{rhA4JEOK`U!u`um7MauUh@j!P>4 z_U&I;4<)v{pnI7q)vaKbUe1z+)9=49UgyQDYF*W5Q}@}kv%lY8q0D+Km|lqe{!67H zs-6Yg?9ppPo(1FGmo=tt{4-aiPFdXd;$uy}Qw7Zov-B*$7GVB)7${T^7Bc>B=V~zj zU8qIhk;!qNG}xN{%&R~DzGPF)Omq^;K%8yne`vW7<{$U^A~yezbhv%i0$2I?l{^1# z^7*cpR_WQy<{x{g&F0?})pw7_Zs< zTfxp|^N;bGO}!QDOq&0eG{)7RHTNF=txJywtL#}&u>b8t1PZA{CAoiF5uMV3?4bT| zDA98!cmy?QnysJ2%9cEMnvHsyA}a@^*{&yfi`bbgnp0dSGi`P9-1}GUEVpS^3myWH zl#!T_nt$_$VXq}#Uy!k(%SF>_Ubg09D_G=4sTK7sQ#9sG%7a z{eOsks@yGEH+9}L(+Xy(RSDGCuv`ydiRms<#fm8|pLsFDuC%qr;o1Z@2 zyY!;-ls-#&2pA5&U<9YU2i9@pL4SBizAQx z*9vwf;xd)_HfiY6W{vakx%XyHbiMjfldlgafd(@ya#N>{z??CIDD%+Nt6pXd1tGo| zELUf$I5%XX9s%KISVMFs z4;3*{AV@IN_9+)|^;4z|%faLg^X9&IT~_>KYcBnv%y~i$?S%`*4a|9ihky~WLBcNK&i~!LF5{LC zDU<3BuX@GUy}PYoQ4;vmpKk&&Q+`hU{k>&BCExYe3wM@Td$5BQ>}+0eV7&c4fBn4m zmD;3FJ)XF}?Ubf#tzZvOJwA-e>6Bo-2yjjH8ni%H3-MryHdb;U7_)h|zZJ|fJVGY{ zIj879k$_#l=BFl9)Ig697DsR+Lr)&5M`~&$a331E&r$2l2h032*ulTnWEK24l`k`<~ zBA_G>H-pG0Ge&$;>HT9VGv0jpfi7P;hFigct3p-k0f(Ng0wVtgEzs2}PoHh=C#^{p zf7@Si`>rp&-M9Sim|ZWiZX5Iy%J-T*EQ?prJ8|RDBOS%+UrH3otN)FG<0N3EyoTMo z+;dmaLk});W=*S-fAQM!&-KD$3`d|oGPi;%NHNJQQxLHBhCoNGAfq$C+c*C5x=Htc zwy5v4vEKK22pC{F{GkJUH@`^03TC-r!0ev3EiRP_nfbL01PUo3Cczj$|g z6)V`;zPP}c$Mh;*^T=&4q)eW8SCen9Y*N+=7CfRd&qeeX7xie2D}SGSbwSId?o+$% z?lr`hrP`1)ZDc+t9}_hA8l?)V7H9^Ikk*zB5g`qw!ibH`zG?5gGJAbo{I++_JvO)6 zi9UKGL;a}-d}H5P)jwQOV^PAamW6{RO@I1QD_E3_3|J*Gi;I3th60N(FUZD*9)e9i z;5b0c%2#Udu71JLq-85lcHXq)we420v)RaCyw7i*^T?PVYR9ko@Z1@7`qgP<1zQAy zIXnU;Mq9ie4BdT}lGQU?|01#&Db zFO%i>fOYo{Du~#tj6KkJU)(!gvlf5-(U0de_-qJc0TT8qb?9@^x~DpHpSm_>>UI4F z3^`}Q^;R&;bvHUX4Nq`3AS{>Wbs9M9^3`b@5|$l*?^yCrz#Pn>pbQ7-Fh7i91+!dn zqk~dhYqQhCCU^6rJt}IT$A=&X=xDY)zxu)0G0E%7PnqAjb#g~5Sd^?uL{9_+8M3{7 zn;`lz*+a3s2IR+<$bu5*$AT)_0aDi~viATjL~1NzEgbRm3p>AR?}=Mb`}<0V2R~F^ zuZ7f~dc@G*lRKX(`}4>j)1EHp+J2-c;T9bW7HXliRm0uOtY9gulhJnj(opsOktioCcD7xR%>>vXzaJQzhRQcQ{d?w(>FS3B3Jhz zF~{rQyS;bvee<6EdEmO-pY@`|>Ry-l^6l~~s$G4TH*wxahq{f=pY^L1?0-((L8SRD zi&n6Inz~;=beZ3MNuZGG9#k0*lnV1Sy-dO{ z;HXEZc_+6O>`VrN*tl!n5s$Gu|{uNzZxH&fyRbw#Lxj;ym~87*VrgA9}bI4~J7D-w3BKreVPtx3{6{ zWXI&?(96=B2R=6!{nW5ksv6|k;n%$U$t!v-SCSS@|NYA9zwLV#{4&G3pfh6~V2wPPPOXpf=X}b*yi1a7u=A#exrNy z$%<2oK%*U|4SI6Ju3`5sk6-ayogOEXp12oGGsCVyXY%kfEsX#=s-+YeIffrx56vvm zERa*ISB%!ShKA-;d+KlIOFw`7@DD#_+Fkwp&5>KuH>J*=I8IEumk+Q*Vt(A9hW~VbErV zRYqs>FwR?53Drvl*Ho`T3kY->u8IL(C zBSeSlFN5M*j6Zbv^E~Cn_uy+%>_ZBaEu$>_?zo$#jX0}yVQm3DdU+i2xXi?(o zCG!R*f4pR)73>tWk|{S2N0MWCQD>J+Ld_!TV7%sEqp^aWN$rEAnSa#>V-H7LP(wZw zt?8H|F8&`TEhoRLU5AvXWLcAQ9J{&YEA%1D-P`5$<`uX_QX(gsd5*xo&z@X|IlpA3 zGglFRo}r)V$+`Wrltap%GCT;ua zrbQzg4eX6Z;p7c;T)MnYgVYatd_GpS41y}Eb)yL~oI{wVJLtxs+| z(0RsU0)?fm2P)CQ29y;b=pEajJG&yf1BUw{I084WvU3P5iP+X({`EOicHH+?{Bv(S zJfZ2F=L~NpXItNZ29cZn_=o)$yq~`1`{OUaxN5~pD_9BT7EIy0e=5N?|3qZ#F<$eH zGb`Acl+QXeM)M6w@FJY8(L=vA5JZ_+{Mko-M21nN_DX#$kuHOP>5|P>;LDrWg16yXH}6R~P6t!$2FGhSN>vO8)e^mKu`D$rBsV3cT<-q+_k^{v-W}z-zIUz_>`a(3Nq@+>K%JoGDwbl<=$fl( zS7rZn;pzp6(_OcFF6^7uQ_oTkc&*gM3U(&Vm6h26E5oTY=rHeTvw~5&(|;ILIyyV@ z&!NtJo+20CizhxXHWe8Qx7F@IRJ22-`K5B8(hOszP{XHlse=3kP5-F;AJ`L}25XH+ z@6E4mB9JYjKl^RzGZp@toV@z_YG1y5cm4zrZHC38Gdj#fmnWF{F|gA>wmKI26KYO_ z8i>UdVgxl12zw&7xt+)Fc69%Cb^OXnEf#G*Q0bVJfw1y9RFN7k^6t-mZI_jSXhK-c8FDMwnKTgfX^iGO z4Fn3SI-tXxA-95^9R>nan(r^zrE<@wUo82f)=k~#zVOTY)0P(w0hMOhS!p1!mfhd* z>uwjs)<|9ccZFqlj(`0PyF@ST-}m0;+ulo@G2_$GD?XW=38Kxg|0M$v@|6c`$&W;A zAl`m;(v(}iI6rmCpsv$yyrAR9dIM1g(?Ca4Iv;(y7s;?mhaye~kCCHOsuD_>&zM#7}E_{qudk4gLNzHJ+q4pyNo>oQ-Q1#3dH* zeV|Q?KejKlg54)6z{NmYzzaU2PaBfj{kFA#X6S+R(Hd&EgY0$-vAa)QmoVUlbRAXwco6_mu1L zTe&jrhg-qyi_nJ@?MvFkMUU1{5aNs41K5ZI`+t1bUfE~BMKe?HdT`m5y+2AD19&ht zvj~9>^ADz4!R(7r^l7`0#%TWa*-*5hET{;@mJK07^GjldIzRUQuGWL<$IW^zdtc*L z#|-a>XAy#ne*LOZtE*h_ROa(LCf<3;&Q}&$!R(7r^xv(5L}iaFYd-S!!7>S}AAa+> z4ozRn1uMge5a@Vx+{9~}E~=6;wfv1EVhw9Rp>c^@m7eGw}0E-`S24}%qINzmBWMl7qj;?A_$7w1ju_N`|JDuxpw z&|%(KW(Bh^LeZzK9*xnw%P$mdC<`t^l<+WOo|Ye+~zkWgO%Y#$V&9AU}sWC>|gbo3rC!91+yEOEVgKXVAKsI;%yr+d zRXmdqTZs_j4D;)Ztzh;=DEjdN9_u&1S(-pW*~}tj6+>CU?2AzJXyZV_D((br*rHSW z)fruf?!P5@{gxT$|5CP5MZiOemb%8EIxA6;4i>e6;%ngF(GoOGUMX4<#~xCm0rGP| zAr$O-S;(lW$nQ7EYry4=Ch<8Z%buICdHL!aT`O8IU|Hlb2COdkP!~bfp-M?C>cS(6 z=c1>3CC&Kd%j0iWZr6&3fUz>=Ry(7tVCgyn4OZtgJoAel0k=cjllAXCasTc%Z~hmwnPDT*nLG@%orW8n zNWLupW5JDE>kN*cvFK2ZNmFiIfuY!;?a1U+7rxQ{aMIK5->*J2zHvp+W`^aXGkKgY z+8AFr8am60Y%h}K_sDk+!UT_(t&8QA4Zbo%0$8(Td$X+QruE_2q3 z=O+}8uF#){fDy5Eu}V-|!7?NnxEN;gG*}lTzRlTwj3e9(gAVgXGAr0q=u934+D?N8 zHYB{}4S5)f9oibt8S(eQXBH+s-sF~d=a>KbNzi77Ek$Q^sPcF&eUSSqE~k(2POpo$ zJj*B7@yqBv^W2&A+pG#I%2!{)wbHl1C!?Ylcz{+Mc)V*=-=&?tI9V}v#-2C+qulfS z7l7O0h4~2|@WKr1fX?VJ^Wrjs5#`CAJeNBse;hMJypWxL4%EMwA6QHY@Z(n*G%1f z^|kva)o4A6hky~WJ+ty?R z@WKo`ZT9RgjN0PBqy{@wr@*B*EM^+4?t6)M!%8x|&^J#}h+V%G}B0*Wyhg9%=$=xfN4ii;ktp&-N;1Dlb8 zHa|0swxQU(S$59MN|xUv4}ckJ%c7JN-Pm|^k$@{k(YHI@2xsqIuP>dvetqivq@ib{zfRC%=RUF#kL|2n$8{W>lbq<)1|=sQiZ&@o}O~5D+Qju+()Rz1 zIGFb9avzH=I%TD>`qd39n0=*){^A0L#{APJpdplOpd550wXak*cHM^9wY4{;_PwWR zc`I0yl!93b)as$Zt2AUk3uc+b(d>y$EArmn5|%(9hpuB*$0013~S)eajg*ibZ*hdNPgAOkjA zMSrJEGs0`$sf3{flMy*g%eM!CHuD>WqND`Tdo2e;^J|&_4@J0HITFx-j-bjB zRQ~fsL**0<``Yp$4EwOMC6MX6u0D}AYUW+ZYoDmKN?uqeqivlOV+LvKSE z7Vdfm3_CW;jF;momRAne|F6AkkBy=T;~T65dDYSoECpOlY)M=CkRG&9Gst;(pD^obP9frOKi$gibn8aUf*&adUKm7=VJ4p*baYkjyN`K z)hGtzdUB5U-x}TTjMYieLL}#*KUg&v00eX52bm()-L*&r7rgE!Yu0eC>OX~+69gU$ zn&z<#3cGWpu;a!QZByg#k@d@sC!_{N7St+!94|#99D?M221V#s^-^0N*baY#0&%>T z)HZl*=q=5OQ@M^a8=bqPXdxODM9*N;c<0VvKNhuoP5VF?yj1YR^p9OUe z*8j5S*8ESNsp;+O?^C6lu^s+|A909pX{BiYbK&2DyaX4t@VBeybk;1=>Ke;8OlceX zK65tX z92CgSunvj=Sn+rr6nH-n^q|OoZ1-;iUw^1`RxN!0%O!E6?t|h%9xp{b1!0~3YR8%d zH&u1R%jV@3^t~%Z3+K)(^E{*WYB#w>LkE&G#q#h$ABU%3yH5TK6~Zq*Q;88ENUvBirB=o38}P@0SHFXo0y&!^=(dFS48>e zbp19d+Ad5ixW6&PhpKoYc0I$vu^tEGveMzumy|NJ)x>{I+@ZG@qmhp!+Mu`4r7S}i zTUd_K8!>^NW*HlNew$-xEyK|ktC8_EcOQB|Kq2p8tB*%F?@_LeYR}glA`*VIo0RxeDuml)+s6FE(acqkF7}2!l~S)j`~2eeaZ&L z%fWYCYT1x~kX=_(uc`2ANP1%!=$X-Ch|pNF+a=-TQFT}`oa$S0> zwGS3rYrv+_tifJvlfo3Dc)g_#^`zu7&SuM?T*Us)CP& zSD7%rM9;Deo1%r{HFo$Zv)Z?$C=8s{o@}PNgp{a>?kQ>Ph=M@FSB^aws0iS$4ECgZ zPfv&I2=JtnP!~Zb33krP%#4M%wL%v%MX>mxO;$9z0w&GC>c5>uh2j4?1V z9`d`atNE)H61v1|Qq;yXc!CwRK$U<$Wilbf%^#>hnKP*&$E)*$5nJq)7G7OY)M5zJ zG^wi0)D;=&naYgi*)mzCOp%%<%g|(JWXP7Ksh^;54;5XsE4cgn@5wqOxzELkLYf94 zMCs<;CAh)F1K#L7B9%aVoR6ZYBSJ{7T}NH9oP1S2f1zef`qC2ap8rlESEmsA-RACS z`B)M2yhYbu7C%yUXPU_5!v81;3L4J3pfMbh@vAUk^(3!)x9YvYZBW20WhzW+yDRo literal 133207 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 z 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 G<^cfx3}s^g diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 401f0f16..d15eebcb 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -9,7 +9,6 @@ #include "InworldAIIntegrationModule.h" #include "InworldPackets.h" #include "InworldCharacter.h" -#include "InworldSessionActor.h" #include #include #include "TimerManager.h" diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 65f0256a..159c458f 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -64,7 +64,8 @@ void UInworldCharacterComponent::OnUnregister() void UInworldCharacterComponent::InitializeComponent() { Super::InitializeComponent(); - if (GetOwnerRole() == ROLE_Authority) + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) { InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); OnRep_InworldSession(); diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index ecb25026..5e816d66 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -56,7 +56,8 @@ void UInworldPlayerComponent::OnUnregister() void UInworldPlayerComponent::InitializeComponent() { Super::InitializeComponent(); - if (GetOwnerRole() == ROLE_Authority) + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) { InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp deleted file mode 100644 index c0f7fb4a..00000000 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionActor.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright 2022-2024 Theai, Inc. dba Inworld AI - * - * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement - * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license - */ - - -#include "InworldSessionActor.h" -#include "InworldSession.h" -#include "InworldApi.h" -#include - -AInworldSessionActor::AInworldSessionActor() -{ - PrimaryActorTick.bCanEverTick = true; - SetReplicates(true); - bAlwaysRelevant = true; -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - bReplicateUsingRegisteredSubObjectList = true; -#endif -} - -void AInworldSessionActor::PreInitializeComponents() -{ - Super::PreInitializeComponents(); - - if (GetLocalRole() == ROLE_Authority) - { - UWorld* World = GetWorld(); - if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE)) - { - InworldSession = NewObject(this); - InworldSession->Init(); - OnRep_InworldSession(); -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - AddReplicatedSubObject(InworldSession); -#endif - } - } -} - -void AInworldSessionActor::BeginPlay() -{ - Super::BeginPlay(); - OnRep_InworldSession(); -} - -void AInworldSessionActor::EndPlay(const EEndPlayReason::Type EndPlayReason) -{ - Super::EndPlay(EndPlayReason); - - if (GetLocalRole() == ROLE_Authority) - { - InworldSession->Destroy(); - if (IsValid(InworldSession)) - { -#if ENGINE_MAJOR_VERSION == 5 - InworldSession->MarkAsGarbage(); -#endif - -#if ENGINE_MAJOR_VERSION == 4 - InworldSession->MarkPendingKill(); -#endif - } - InworldSession = nullptr; - } -} - -void AInworldSessionActor::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const -{ - Super::GetLifetimeReplicatedProps(OutLifetimeProps); - - DOREPLIFETIME(AInworldSessionActor, InworldSession); -} - -bool AInworldSessionActor::ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) -{ -#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1 - return Super::ReplicateSubobjects(Channel, Bunch, RepFlags); -#else - bool WroteSomething = true; - - if (IsValid(InworldSession)) - { - WroteSomething |= Channel->ReplicateSubobject(InworldSession, *Bunch, *RepFlags); - } - - return WroteSomething; -#endif -} - -void AInworldSessionActor::OnRep_InworldSession() -{ - if (InworldSession) - { - GetWorld()->GetSubsystem()->SetInworldSession(InworldSession); - OnSessionCreatedDelegateNative.Broadcast(); - OnSessionCreatedDelegate.Broadcast(); - } -} - diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp index 2ba58f00..b9696903 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp @@ -1,4 +1,9 @@ -// Fill out your copyright notice in the Description page of Project Settings. +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ #include "InworldSessionComponent.h" @@ -76,4 +81,6 @@ bool UInworldSessionComponent::ReplicateSubobjects(UActorChannel* Channel, FOutB void UInworldSessionComponent::OnRep_InworldSession() { GetWorld()->GetSubsystem()->SetInworldSession(InworldSession); + OnSessionCreatedDelegateNative.Broadcast(); + OnSessionCreatedDelegate.Broadcast(); } diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h deleted file mode 100644 index 5b21372e..00000000 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionActor.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright 2022-2024 Theai, Inc. dba Inworld AI - * - * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement - * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license - */ - -#pragma once - -#include "CoreMinimal.h" -#include "GameFramework/Actor.h" -#include "InworldSessionActor.generated.h" - -class UInworldSession; - -DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInworldSessionCreated); -DECLARE_MULTICAST_DELEGATE(FOnInworldSessionCreatedNative); - -UCLASS() -class INWORLDAIINTEGRATION_API AInworldSessionActor : public AActor, public IInworldSessionOwnerInterface -{ - GENERATED_BODY() - -public: - AInworldSessionActor(); - - // IInworldSessionOwnerInterface - virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession; } - // ~IInworldSessionOwnerInterface - - UPROPERTY(BlueprintAssignable, Category = "Session") - FOnInworldSessionCreated OnSessionCreatedDelegate; - FOnInworldSessionCreatedNative& OnSessionCreated() { return OnSessionCreatedDelegateNative; } - -private: - FOnInworldSessionCreatedNative OnSessionCreatedDelegateNative; - -protected: - virtual void PreInitializeComponents() override; - virtual void BeginPlay() override; - virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; - - virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; - virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; - -private: - UFUNCTION() - void OnRep_InworldSession(); - - UPROPERTY(ReplicatedUsing=OnRep_InworldSession) - UInworldSession* InworldSession; -}; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h index 460dd76c..a19f2407 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h @@ -1,4 +1,9 @@ -// Fill out your copyright notice in the Description page of Project Settings. +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ #pragma once @@ -7,6 +12,8 @@ #include "InworldSession.h" #include "InworldSessionComponent.generated.h" +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInworldSessionCreated); +DECLARE_MULTICAST_DELEGATE(FOnInworldSessionCreatedNative); UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class INWORLDAIINTEGRATION_API UInworldSessionComponent : public UActorComponent, public IInworldSessionOwnerInterface @@ -25,7 +32,14 @@ class INWORLDAIINTEGRATION_API UInworldSessionComponent : public UActorComponent virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; + + UPROPERTY(BlueprintAssignable, Category = "Session") + FOnInworldSessionCreated OnSessionCreatedDelegate; + FOnInworldSessionCreatedNative& OnSessionCreated() { return OnSessionCreatedDelegateNative; } + private: + FOnInworldSessionCreatedNative OnSessionCreatedDelegateNative; + UFUNCTION() void OnRep_InworldSession(); From 3e4c7bdb717969d9d8052bbe4230d1de61d7b1b1 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Fri, 26 Apr 2024 16:43:10 -0400 Subject: [PATCH 25/45] backup for inworld session inworld api Add InworldSessionComponent to GameState if none exist --- .../InworldAIIntegration/Private/InworldApi.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index d15eebcb..e7ac1e25 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -9,11 +9,13 @@ #include "InworldAIIntegrationModule.h" #include "InworldPackets.h" #include "InworldCharacter.h" +#include "InworldSessionComponent.h" #include #include #include "TimerManager.h" #include "InworldAudioRepl.h" #include "UObject/UObjectIterator.h" +#include "GameFramework/GameStateBase.h" static TAutoConsoleVariable CVarLogAllPackets( TEXT("Inworld.Debug.LogAllPackets"), false, @@ -321,7 +323,15 @@ void UInworldApiSubsystem::OnWorldBeginPlay(UWorld& InWorld) { Super::OnWorldBeginPlay(InWorld); - if (GetWorld()->GetNetMode() != NM_Standalone) + UWorld* World = GetWorld(); + if (InworldSession == nullptr && World && World->GetNetMode() != NM_Client) + { + // Backward compatibility for calls directly to InworldApi without some sort of session actor + UInworldSessionComponent* SessionComponent = Cast(World->GetGameState()->AddComponentByClass(UInworldSessionComponent::StaticClass(), false, FTransform::Identity, false)); + SetInworldSession(IInworldSessionOwnerInterface::Execute_GetInworldSession(SessionComponent)); + } + + if (World && World->GetNetMode() != NM_Standalone) { StartAudioReplication(); } From 21bb12b3fc3a59103e27c0f66d218c4ed498b5ac Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 29 Apr 2024 09:24:15 -0400 Subject: [PATCH 26/45] add checks --- .../InworldAIClient/Public/InworldClient.h | 26 ++-- .../Private/InworldApi.cpp | 120 ++++++++++++++++++ .../InworldPlayerAudioCaptureComponent.cpp | 56 ++++---- .../InworldPlayerTargetingComponent.cpp | 11 +- .../Public/InworldCharacter.h | 34 ++--- .../Public/InworldPlayer.h | 30 ++--- .../Public/InworldSession.h | 32 ++--- 7 files changed, 218 insertions(+), 91 deletions(-) diff --git a/InworldAI/Source/InworldAIClient/Public/InworldClient.h b/InworldAI/Source/InworldAIClient/Public/InworldClient.h index ac74c550..be1fe13c 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldClient.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldClient.h @@ -40,35 +40,35 @@ class INWORLDAICLIENT_API UInworldClient : public UObject UInworldClient(); ~UInworldClient(); - UFUNCTION(BlueprintCallable, Category = "Inworld|Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) + UFUNCTION(BlueprintCallable, Category = "Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet); - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void StopSession(); - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void PauseSession(); - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void ResumeSession(); - UFUNCTION(BlueprintPure, Category = "Inworld|Session") + UFUNCTION(BlueprintPure, Category = "Session") FString GetSessionId() const; - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void SaveSession(FOnInworldSessionSavedCallback Callback); - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void LoadCharacter(const FString& Id) { LoadCharacters({ Id }); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void LoadCharacters(const TArray& Ids); - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void UnloadCharacter(const FString& Id) { UnloadCharacters({ Id }); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void UnloadCharacters(const TArray& Ids); - UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + UFUNCTION(BlueprintCallable, Category = "Load") void LoadSavedState(const FInworldSave& Save); - UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + UFUNCTION(BlueprintCallable, Category = "Load") void LoadCapabilities(const FInworldCapabilitySet& CapabilitySet); - UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + UFUNCTION(BlueprintCallable, Category = "Load") void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile); UFUNCTION(BlueprintCallable, Category = "Message|Text") diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index d15eebcb..b2a03a39 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -47,6 +47,11 @@ void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensure(GetWorld()->GetNetMode() < NM_Client)) { UE_LOG(LogInworldAIIntegration, Error, TEXT("UInworldApiSubsystem::StartSession shouldn't be called on client")); @@ -85,6 +90,11 @@ void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& void UInworldApiSubsystem::StartSession_V2(const FString& SceneName, const FInworldPlayerProfile& PlayerProfile, const FInworldCapabilitySet& Capabilities, const FInworldAuth& Auth, const FInworldSessionToken& SessionToken, const FInworldEnvironment& Environment, FString UniqueUserIdOverride, FInworldSave SavedSessionState) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensure(GetWorld()->GetNetMode() < NM_Client)) { UE_LOG(LogInworldAIIntegration, Error, TEXT("UInworldApiSubsystem::StartSession shouldn't be called on client")); @@ -107,36 +117,71 @@ void UInworldApiSubsystem::StartSession_V2(const FString& SceneName, const FInwo void UInworldApiSubsystem::PauseSession() { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->PauseSession(); } void UInworldApiSubsystem::ResumeSession() { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->PauseSession(); } void UInworldApiSubsystem::StopSession() { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->StopSession(); } void UInworldApiSubsystem::SaveSession(FOnInworldSessionSavedCallback Callback) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->SaveSession(Callback); } void UInworldApiSubsystem::SetResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->OnPerceivedLatencyDelegate.Add(Delegate); } void UInworldApiSubsystem::ClearResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->OnPerceivedLatencyDelegate.Remove(Delegate); } void UInworldApiSubsystem::LoadCharacters(const TArray& Names) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + TArray Characters; for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) { @@ -150,6 +195,11 @@ void UInworldApiSubsystem::LoadCharacters(const TArray& Names) void UInworldApiSubsystem::UnloadCharacters(const TArray& Names) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + TArray Characters; for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) { @@ -163,16 +213,31 @@ void UInworldApiSubsystem::UnloadCharacters(const TArray& Names) void UInworldApiSubsystem::LoadSavedState(const FInworldSave& SavedState) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->LoadSavedState(SavedState); } void UInworldApiSubsystem::LoadCapabilities(const FInworldCapabilitySet& Capabilities) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->LoadCapabilities(Capabilities); } void UInworldApiSubsystem::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->LoadPlayerProfile(PlayerProfile); } @@ -183,6 +248,11 @@ void UInworldApiSubsystem::SendTextMessage(const FString& AgentId, const FString void UInworldApiSubsystem::SendTextMessageMultiAgent(const TArray& AgentIds, const FString& Text) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) { return; @@ -198,6 +268,11 @@ void UInworldApiSubsystem::SendTrigger(const FString& AgentId, const FString& Na void UInworldApiSubsystem::SendTriggerMultiAgent(const TArray& AgentIds, const FString& Name, const TMap& Params) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentId must be valid!"))) { return; @@ -208,6 +283,11 @@ void UInworldApiSubsystem::SendTriggerMultiAgent(const TArray& AgentIds void UInworldApiSubsystem::SendNarrationEvent(const FString& AgentId, const FString& Content) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensureMsgf(!AgentId.IsEmpty(), TEXT("AgentId must be valid!"))) { return; @@ -218,6 +298,11 @@ void UInworldApiSubsystem::SendNarrationEvent(const FString& AgentId, const FStr void UInworldApiSubsystem::SendAudioMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) { return; @@ -233,6 +318,11 @@ bool UInworldApiSubsystem::StartAudioSession(const FString& AgentId, const AActo bool UInworldApiSubsystem::StartAudioSessionMultiAgent(const TArray& AgentIds, const AActor* Owner) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return false; + } + if (AudioSessionOwner) { return false; @@ -256,6 +346,11 @@ void UInworldApiSubsystem::StopAudioSession(const FString& AgentId) void UInworldApiSubsystem::StopAudioSessionMultiAgent(const TArray& AgentIds) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) { return; @@ -268,21 +363,41 @@ void UInworldApiSubsystem::StopAudioSessionMultiAgent(const TArray& Age void UInworldApiSubsystem::ChangeScene(const FString& SceneId) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->SendChangeSceneEvent(SceneId); } EInworldConnectionState UInworldApiSubsystem::GetConnectionState() const { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return EInworldConnectionState::Idle; + } + return InworldSession->GetConnectionState(); } void UInworldApiSubsystem::GetConnectionError(FString& Message, int32& Code) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + InworldSession->InworldClient->GetConnectionError(Message, Code); } void UInworldApiSubsystem::CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds) { + if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) + { + return; + } + if (!ensureMsgf(!AgentId.IsEmpty(), TEXT("AgentId must be valid!"))) { return; @@ -338,5 +453,10 @@ void UInworldApiSubsystem::ReplicateAudioEventFromServer(FInworldAudioDataEvent& void UInworldApiSubsystem::HandleAudioEventOnClient(TSharedPtr Packet) { + if (!ensureMsgf(InworldSession, TEXT("Inworld Session must be valid!"))) + { + return; + } + Packet->Accept(*InworldSession->PacketVisitor); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index bc61bdd2..ce16fa79 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -164,30 +164,34 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() if (GetOwnerRole() == ROLE_Authority) { - InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass())[0]); - OnPlayerTargetCharactersChanged = InworldPlayer->OnTargetCharactersChanged().AddLambda( - [this]() -> void - { - PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); - PlayerAudioTargetState.bDirty = true; - EvaluateVoiceCapture(); - } - ); - PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); + TArray PlayerOwnerComponents = GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass()); + if (ensureMsgf(!PlayerOwnerComponents.IsEmpty(), TEXT("The owner of the AudioCapture must contain an InworldPlayerOwner!"))) + { + InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(PlayerOwnerComponents[0]); + OnPlayerTargetCharactersChanged = InworldPlayer->OnTargetCharactersChanged().AddLambda( + [this]() -> void + { + PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); + PlayerAudioTargetState.bDirty = true; + EvaluateVoiceCapture(); + } + ); + PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); - InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetOuter()); - OnSessionConnectionStateChanged = InworldSession->OnConnectionStateChanged().AddLambda( - [this](EInworldConnectionState ConnectionState) -> void - { - EvaluateVoiceCapture(); - } - ); - OnSessionLoaded = InworldSession->OnLoaded().AddLambda( - [this](bool bLoaded) -> void - { - EvaluateVoiceCapture(); - } - ); + InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetOuter()); + OnSessionConnectionStateChanged = InworldSession->OnConnectionStateChanged().AddLambda( + [this](EInworldConnectionState ConnectionState) -> void + { + EvaluateVoiceCapture(); + } + ); + OnSessionLoaded = InworldSession->OnLoaded().AddLambda( + [this](bool bLoaded) -> void + { + EvaluateVoiceCapture(); + } + ); + } PrimaryComponentTick.SetTickFunctionEnable(false); } @@ -303,8 +307,8 @@ void UInworldPlayerAudioCaptureComponent::EvaluateVoiceCapture() const bool bIsMicHot = !bMuted; const bool bIsWorldPlaying = !GetWorld()->IsPaused(); const bool bHasTargetCharacter = PlayerAudioTargetState.DesiredCharacters.Num() != 0; - const EInworldConnectionState ConnectionState = InworldSession->GetConnectionState(); - const bool bHasActiveInworldSession = InworldSession->IsLoaded() && (ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting); + const EInworldConnectionState ConnectionState = InworldSession.IsValid() ? InworldSession->GetConnectionState() : EInworldConnectionState::Idle; + const bool bHasActiveInworldSession = InworldSession.IsValid() && InworldSession->IsLoaded() && (ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting); const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasTargetCharacter && bHasActiveInworldSession; @@ -437,7 +441,7 @@ void UInworldPlayerAudioCaptureComponent::StopCapture() void UInworldPlayerAudioCaptureComponent::Server_ProcessVoiceCaptureChunk_Implementation(FPlayerVoiceCaptureInfoRep PlayerVoiceCaptureInfo) { - if (PlayerAudioTargetState.ActiveCharacters.Num() != 0) + if (PlayerAudioTargetState.ActiveCharacters.Num() != 0 && InworldSession.IsValid()) { InworldSession->BroadcastSoundMessage(PlayerAudioTargetState.ActiveCharacters, PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index f4da658a..8836cbd4 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -28,7 +28,11 @@ void UInworldPlayerTargetingComponent::BeginPlay() else { PrimaryComponentTick.SetTickFunctionEnable(true); - InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass())[0]); + TArray PlayerOwnerComponents = GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass()); + if (ensureMsgf(!PlayerOwnerComponents.IsEmpty(), TEXT("The owner of the AudioCapture must contain an InworldPlayerOwner!"))) + { + InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(PlayerOwnerComponents[0]); + } } } @@ -36,7 +40,10 @@ void UInworldPlayerTargetingComponent::TickComponent(float DeltaTime, enum ELeve { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - UpdateTargetCharacters(); + if (InworldPlayer.IsValid()) + { + UpdateTargetCharacters(); + } } void UInworldPlayerTargetingComponent::UpdateTargetCharacters() diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index 6f420525..3a5f2ad9 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -34,51 +34,51 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject // ~UObject public: - UFUNCTION(BlueprintCallable, Category = "Message") + UFUNCTION(BlueprintCallable, Category = "Message|Text") void SendTextMessage(const FString& Text); - UFUNCTION(BlueprintCallable, Category = "Trigger") + UFUNCTION(BlueprintCallable, Category = "Message|Trigger") void SendTrigger(const FString& Name, const TMap& Params); - UFUNCTION(BlueprintCallable, Category = "Narration") + UFUNCTION(BlueprintCallable, Category = "Message|Narration") void SendNarrationEvent(const FString& Content); - UFUNCTION(BlueprintCallable, Category = "Audio") + UFUNCTION(BlueprintCallable, Category = "Message|Audio") void SendAudioSessionStart(); - UFUNCTION(BlueprintCallable, Category = "Audio") + UFUNCTION(BlueprintCallable, Category = "Message|Audio") void SendAudioSessionStop(); - UFUNCTION(BlueprintCallable, Category = "Audio") + UFUNCTION(BlueprintCallable, Category = "Message|Audio") void SendSoundMessage(const TArray& Input, const TArray& Output); - UFUNCTION(BlueprintCallable, Category = "Mutation") + UFUNCTION(BlueprintCallable, Category = "Message|Mutation") void CancelResponse(const FString& InteractionId, const TArray& UtteranceIds); public: - UFUNCTION(BlueprintCallable, Category = "Inworld|Player") + UFUNCTION(BlueprintCallable, Category = "Character") TScriptInterface GetInworldCharacterOwner(); - UFUNCTION(BlueprintCallable, Category = "Inworld|Player") + UFUNCTION(BlueprintCallable, Category = "Possession") void SetBrainName(const FString& BrainName); - UFUNCTION(BlueprintPure, Category = "Inworld|Player") + UFUNCTION(BlueprintPure, Category = "Possession") bool IsPossessed() const { return !AgentInfo.AgentId.IsEmpty(); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Player") + UFUNCTION(BlueprintCallable, Category = "Possession") void Possess(const FInworldAgentInfo& InAgentInfo); - UFUNCTION(BlueprintCallable, Category = "Inworld|Player") + UFUNCTION(BlueprintCallable, Category = "Possession") void Unpossess(); - UFUNCTION(BlueprintPure, Category = "Inworld|Agent") + UFUNCTION(BlueprintPure, Category = "Possession") const FInworldAgentInfo& GetAgentInfo() const { return AgentInfo; } UPROPERTY(BlueprintAssignable, Category = "Possession") FOnInworldCharacterPossessed OnPossessedDelegate; FOnInworldCharacterPossessedNative& OnPossessed() { return OnPossessedDelegateNative; } - UFUNCTION(BlueprintCallable, Category = "Engagement") + UFUNCTION(BlueprintCallable, Category = "Target") void SetTargetPlayer(UInworldPlayer* Player); - UFUNCTION(BlueprintCallable, Category = "Engagement") + UFUNCTION(BlueprintCallable, Category = "Target") void ClearTargetPlayer(); - UFUNCTION(BlueprintPure, Category = "Engagement") + UFUNCTION(BlueprintPure, Category = "Target") UInworldPlayer* GetTargetPlayer() const { return TargetPlayer; } - UPROPERTY(BlueprintAssignable, Category = "Engagement") + UPROPERTY(BlueprintAssignable, Category = "Target") FOnInworldCharacterTargetPlayerChanged OnTargetPlayerChangedDelegate; FOnInworldCharacterTargetPlayerChangedNative& OnTargetPlayerChanged() { return OnTargetPlayerChangedDelegateNative; } diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index d4576e80..e5eed193 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -37,42 +37,42 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject // ~UObject public: - UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Message") + UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Message|Text") void BroadcastTextMessage(const FString& Text); - UFUNCTION(BlueprintCallable, Category = "Trigger") + UFUNCTION(BlueprintCallable, Category = "Message|Trigger") void BroadcastTrigger(const FString& Name, const TMap& Params); - UFUNCTION(BlueprintCallable, Category = "Audio") + UFUNCTION(BlueprintCallable, Category = "Message|Audio") void BroadcastAudioSessionStart(); - UFUNCTION(BlueprintCallable, Category = "Audio") + UFUNCTION(BlueprintCallable, Category = "Message|Audio") void BroadcastAudioSessionStop(); - UFUNCTION(BlueprintCallable, Category = "Audio") + UFUNCTION(BlueprintCallable, Category = "Message|Audio") void BroadcastSoundMessage(const TArray& Input, const TArray& Output); public: - UFUNCTION(BlueprintCallable, Category = "Inworld|Player") + UFUNCTION(BlueprintCallable, Category = "Player") TScriptInterface GetInworldPlayerOwner(); - UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + UFUNCTION(BlueprintCallable, Category = "Target") const TArray& GetTargetCharacters() const { return TargetCharacters; } - UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + UFUNCTION(BlueprintCallable, Category = "Target") void AddTargetCharacter(UInworldCharacter* TargetCharacter); - UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + UFUNCTION(BlueprintCallable, Category = "Target") void RemoveTargetCharacter(UInworldCharacter* TargetCharacter); - UFUNCTION(BlueprintCallable, Category = "Inworld|Player|Target") + UFUNCTION(BlueprintCallable, Category = "Target") void ClearAllTargetCharacters(); - UPROPERTY(BlueprintAssignable, Category = "Engagement") + UPROPERTY(BlueprintAssignable, Category = "Target") FOnInworldPlayerTargetCharacterAdded OnTargetCharacterAddedDelegate; FOnInworldPlayerTargetCharacterAddedNative& OnTargetCharacterAdded() { return OnTargetCharacterAddedDelegateNative; } - UPROPERTY(BlueprintAssignable, Category = "Engagement") + UPROPERTY(BlueprintAssignable, Category = "Target") FOnInworldPlayerTargetCharacterRemoved OnTargetCharacterRemovedDelegate; FOnInworldPlayerTargetCharacterRemovedNative& OnTargetCharacterRemoved() { return OnTargetCharacterRemovedDelegateNative; } - UPROPERTY(BlueprintAssignable, Category = "Engagement") + UPROPERTY(BlueprintAssignable, Category = "Target") FOnInworldPlayerTargetCharactersChanged OnTargetCharactersChangedDelegate; FOnInworldPlayerTargetCharactersChangedNative& OnTargetCharactersChanged() { return OnTargetCharactersChangedDelegateNative; } @@ -101,8 +101,4 @@ class INWORLDAIINTEGRATION_API IInworldPlayerOwnerInterface UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") UInworldPlayer* GetInworldPlayer() const; - -public: - UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") - FTransform GetInworldPlayerTransform() const; }; \ No newline at end of file diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index a2be1943..e4fe14cc 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -58,43 +58,43 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject UFUNCTION(BlueprintCallable, Category = "Client") void Destroy(); - UFUNCTION(BlueprintCallable, Category = "Inworld|Register") + UFUNCTION(BlueprintCallable, Category = "Register") void RegisterCharacter(UInworldCharacter* Character); - UFUNCTION(BlueprintCallable, Category = "Inworld|Register") + UFUNCTION(BlueprintCallable, Category = "Register") void UnregisterCharacter(UInworldCharacter* Character); - UFUNCTION(BlueprintPure, Category = "Inworld|Register") + UFUNCTION(BlueprintPure, Category = "Register") const TArray& GetRegisteredCharacters() const { return RegisteredCharacters; } - UFUNCTION(BlueprintCallable, Category = "Inworld|Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) + UFUNCTION(BlueprintCallable, Category = "Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet); - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void StopSession(); - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void PauseSession() { InworldClient->PauseSession(); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void ResumeSession() { InworldClient->ResumeSession(); } - UFUNCTION(BlueprintPure, Category = "Inworld|Session") + UFUNCTION(BlueprintPure, Category = "Session") FString GetSessionId() const { return InworldClient->GetSessionId(); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Session") + UFUNCTION(BlueprintCallable, Category = "Session") void SaveSession(FOnInworldSessionSavedCallback Callback) { InworldClient->SaveSession(Callback); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void LoadCharacter(UInworldCharacter* Character) { LoadCharacters({ Character }); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void LoadCharacters(const TArray& Characters); - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void UnloadCharacter(UInworldCharacter* Character) { UnloadCharacters({ Character }); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Load|Character") + UFUNCTION(BlueprintCallable, Category = "Load|Character") void UnloadCharacters(const TArray& Characters); - UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + UFUNCTION(BlueprintCallable, Category = "Load") void LoadSavedState(const FInworldSave& Save) { InworldClient->LoadSavedState(Save); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + UFUNCTION(BlueprintCallable, Category = "Load") void LoadCapabilities(const FInworldCapabilitySet& CapabilitySet) { InworldClient->LoadCapabilities(CapabilitySet); } - UFUNCTION(BlueprintCallable, Category = "Inworld|Load") + UFUNCTION(BlueprintCallable, Category = "Load") void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { InworldClient->LoadPlayerProfile(PlayerProfile); } UFUNCTION(BlueprintCallable, Category = "Message|Text") From db96dfccfbbbb5322d976bcd1ad80a453c6a24b5 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 29 Apr 2024 10:19:00 -0400 Subject: [PATCH 27/45] 4.27 fixes --- .../Private/InworldPlayerAudioCaptureComponent.cpp | 2 +- .../Private/InworldPlayerTargetingComponent.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index ce16fa79..1c8f2194 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -165,7 +165,7 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() if (GetOwnerRole() == ROLE_Authority) { TArray PlayerOwnerComponents = GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass()); - if (ensureMsgf(!PlayerOwnerComponents.IsEmpty(), TEXT("The owner of the AudioCapture must contain an InworldPlayerOwner!"))) + if (ensureMsgf(PlayerOwnerComponents.Num() > 0, TEXT("The owner of the AudioCapture must contain an InworldPlayerOwner!"))) { InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(PlayerOwnerComponents[0]); OnPlayerTargetCharactersChanged = InworldPlayer->OnTargetCharactersChanged().AddLambda( diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 8836cbd4..2c1d56ed 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -29,7 +29,7 @@ void UInworldPlayerTargetingComponent::BeginPlay() { PrimaryComponentTick.SetTickFunctionEnable(true); TArray PlayerOwnerComponents = GetOwner()->GetComponentsByInterface(UInworldPlayerOwnerInterface::StaticClass()); - if (ensureMsgf(!PlayerOwnerComponents.IsEmpty(), TEXT("The owner of the AudioCapture must contain an InworldPlayerOwner!"))) + if (ensureMsgf(PlayerOwnerComponents.Num() > 0, TEXT("The owner of the AudioCapture must contain an InworldPlayerOwner!"))) { InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(PlayerOwnerComponents[0]); } From e9d5f69a7c1bcdf12e6fde56e344de70e68e9808 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 1 May 2024 17:38:30 -0400 Subject: [PATCH 28/45] multi-agent-merge --- .../InworldAIClient/Private/InworldClient.cpp | 104 +++++-- .../Private/InworldPacketTranslator.cpp | 18 +- .../Private/InworldPacketTranslator.h | 9 +- .../Private/InworldPackets.cpp | 21 +- .../InworldAIClient/Public/InworldClient.h | 25 +- .../InworldAIClient/Public/InworldEnums.h | 9 + .../InworldAIClient/Public/InworldPackets.h | 46 +++- .../Private/InworldApi.cpp | 93 +------ .../Private/InworldCharacter.cpp | 106 ++++++- .../Private/InworldCharacterComponent.cpp | 157 +++-------- .../Private/InworldPlayer.cpp | 119 ++++++-- .../InworldPlayerAudioCaptureComponent.cpp | 54 ++-- .../Private/InworldPlayerComponent.cpp | 29 +- .../InworldPlayerTargetingComponent.cpp | 2 +- .../Private/InworldSession.cpp | 258 ++++++++++++------ .../InworldAIIntegration/Public/InworldApi.h | 23 +- .../Public/InworldCharacter.h | 72 ++++- .../Public/InworldCharacterComponent.h | 14 - .../Public/InworldPlayer.h | 41 ++- .../InworldPlayerAudioCaptureComponent.h | 11 +- .../Public/InworldPlayerComponent.h | 8 +- .../Public/InworldSession.h | 86 +++--- InworldAI/inworld-ndk | 2 +- 23 files changed, 753 insertions(+), 554 deletions(-) diff --git a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp index 523456c0..b54ef82b 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp @@ -57,6 +57,26 @@ UInworldClient::FOnAudioDumperCVarChanged UInworldClient::OnAudioDumperCVarChang FAutoConsoleVariableSink UInworldClient::CVarSink(FConsoleCommandDelegate::CreateStatic(&UInworldClient::OnCVarsChanged)); #endif +std::vector ToStd(const TArray& Array) +{ + std::vector Vec; + for (auto& Str : Array) + { + Vec.emplace_back(TCHAR_TO_UTF8(*Str)); + } + return Vec; +} + +std::unordered_map ToStd(const TMap& Map) +{ + std::unordered_map StdMap; + for (const TPair& Entry : Map) + { + StdMap.insert(std::make_pair(TCHAR_TO_UTF8(*Entry.Key), TCHAR_TO_UTF8(*Entry.Value))); + } + return StdMap; +} + UInworldClient::UInworldClient() : Super() { @@ -293,16 +313,6 @@ void UInworldClient::SaveSession(FOnInworldSessionSavedCallback Callback) }); } -std::vector ToStd(const TArray& Array) -{ - std::vector Vec; - for (auto& Str : Array) - { - Vec.emplace_back(TCHAR_TO_UTF8(*Str)); - } - return Vec; -} - void UInworldClient::LoadCharacters(const TArray& Ids) { Inworld::GetClient()->LoadCharacters(ToStd(Ids)); @@ -333,6 +343,16 @@ void UInworldClient::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfil Inworld::GetClient()->LoadUserConfiguration(UserConfig); } +FString UInworldClient::UpdateConversation(const FString& ConversationId, const TArray& AgentIds, bool bIncludePlayer) +{ + if (AgentIds.Num() == 0) + { + return {}; + } + auto Packet = Inworld::GetClient()->UpdateConversation(ToStd(AgentIds), TCHAR_TO_UTF8(*ConversationId), bIncludePlayer); + return UTF8_TO_TCHAR(Packet->_Routing._ConversationId.c_str()); +} + EInworldConnectionState UInworldClient::GetConnectionState() const { return Inworld::GetClient() ? static_cast(Inworld::GetClient()->GetConnectionState()) : EInworldConnectionState::Disconnected; @@ -350,52 +370,80 @@ FString UInworldClient::GetSessionId() const return UTF8_TO_TCHAR(Inworld::GetClient()->GetSessionInfo().SessionId.c_str()); } -FInworldWrappedPacket UInworldClient::SendTextMessage(const TArray& AgentIds, const FString& Text) +FInworldWrappedPacket UInworldClient::SendTextMessage(const FString& AgentId, const FString& Text) +{ + auto Packet = Inworld::GetClient()->SendTextMessage(TCHAR_TO_UTF8(*AgentId), TCHAR_TO_UTF8(*Text)); + InworldPacketTranslator PacketTranslator; + Packet->Accept(PacketTranslator); + return PacketTranslator.GetPacket(); +} + +FInworldWrappedPacket UInworldClient::SendTextMessageToConversation(const FString& ConversationId, const FString& Text) { - auto Packet = Inworld::GetClient()->SendTextMessage(ToStd(AgentIds), TCHAR_TO_UTF8(*Text)); + auto Packet = Inworld::GetClient()->SendTextMessageToConversation(TCHAR_TO_UTF8(*ConversationId), TCHAR_TO_UTF8(*Text)); InworldPacketTranslator PacketTranslator; Packet->Accept(PacketTranslator); return PacketTranslator.GetPacket(); } -void UInworldClient::BroadcastSoundMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData) +void UInworldClient::SendSoundMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData) { if (OutputData.Num() > 0) { std::string inputdata((char*)InputData.GetData(), InputData.Num()); - Inworld::GetClient()->SendSoundMessage(ToStd(AgentIds), inputdata); + Inworld::GetClient()->SendSoundMessage(TCHAR_TO_UTF8(*AgentId), inputdata); + } + else + { + std::vector inputdata((int16*)InputData.GetData(), ((int16*)InputData.GetData()) + (InputData.Num() / 2)); + std::vector outputdata((int16*)OutputData.GetData(), ((int16*)OutputData.GetData()) + (OutputData.Num() / 2)); + Inworld::GetClient()->SendSoundMessageWithAEC(TCHAR_TO_UTF8(*AgentId), inputdata, outputdata); + } +} + +void UInworldClient::SendSoundMessageToConversation(const FString& ConversationId, const TArray& InputData, const TArray& OutputData) +{ + if (OutputData.Num() == 0) + { + std::string inputdata((char*)InputData.GetData(), InputData.Num()); + Inworld::GetClient()->SendSoundMessageToConversation(TCHAR_TO_UTF8(*ConversationId), inputdata); } else { std::vector inputdata((int16*)InputData.GetData(), ((int16*)InputData.GetData()) + (InputData.Num() / 2)); std::vector outputdata((int16*)OutputData.GetData(), ((int16*)OutputData.GetData()) + (OutputData.Num() / 2)); - Inworld::GetClient()->SendSoundMessageWithAEC(ToStd(AgentIds), inputdata, outputdata); + Inworld::GetClient()->SendSoundMessageWithAECToConversation(TCHAR_TO_UTF8(*ConversationId), inputdata, outputdata); } } -void UInworldClient::BroadcastAudioSessionStart(const TArray& AgentIds) +void UInworldClient::SendAudioSessionStart(const FString& AgentId) { - Inworld::GetClient()->StartAudioSession(ToStd(AgentIds)); + Inworld::GetClient()->StartAudioSession(TCHAR_TO_UTF8(*AgentId)); } -void UInworldClient::BroadcastAudioSessionStop(const TArray& AgentIds) +void UInworldClient::SendAudioSessionStartToConversation(const FString& ConversationId) { - Inworld::GetClient()->StopAudioSession(ToStd(AgentIds)); + Inworld::GetClient()->StartAudioSessionInConversation(TCHAR_TO_UTF8(*ConversationId)); } -std::unordered_map ToStd(const TMap& Map) +void UInworldClient::SendAudioSessionStop(const FString& AgentId) { - std::unordered_map StdMap; - for (const TPair& Entry : Map) - { - StdMap.insert(std::make_pair(TCHAR_TO_UTF8(*Entry.Key), TCHAR_TO_UTF8(*Entry.Value))); - } - return StdMap; + Inworld::GetClient()->StopAudioSession(TCHAR_TO_UTF8(*AgentId)); +} + +void UInworldClient::SendAudioSessionStopToConversation(const FString& ConversationId) +{ + Inworld::GetClient()->StopAudioSessionInConversation(TCHAR_TO_UTF8(*ConversationId)); +} + +void UInworldClient::SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params) +{ + Inworld::GetClient()->SendCustomEvent(TCHAR_TO_UTF8(*AgentId), TCHAR_TO_UTF8(*Name), ToStd(Params)); } -void UInworldClient::BroadcastTrigger(const TArray& AgentIds, const FString& Name, const TMap& Params) +void UInworldClient::SendTriggerToConversation(const FString& ConversationId, const FString& Name, const TMap& Params) { - Inworld::GetClient()->SendCustomEvent(ToStd(AgentIds), TCHAR_TO_UTF8(*Name), ToStd(Params)); + Inworld::GetClient()->SendCustomEventToConversation(TCHAR_TO_UTF8(*ConversationId), TCHAR_TO_UTF8(*Name), ToStd(Params)); } void UInworldClient::SendChangeSceneEvent(const FString& SceneName) diff --git a/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.cpp b/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.cpp index 44c7f177..792cc7f8 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.cpp @@ -21,11 +21,7 @@ void InworldPacketTranslator::TranslateInworldRouting(const Inworld::Routing& Or TranslateInworldActor(Original._Source, New.Source); TranslateInworldActor(Original._Target, New.Target); - for (auto& Actor : Original._Targets) - { - auto& NewActor = New.Targets.Emplace_GetRef(); - TranslateInworldActor(Actor, NewActor); - } + New.ConversationId = UTF8_TO_TCHAR(Original._ConversationId.c_str()); } void InworldPacketTranslator::TranslateInworldPacketId(const Inworld::PacketId& Original, FInworldPacketId& New) @@ -88,6 +84,18 @@ void InworldPacketTranslator::TranslateEvent(Original.GetControlAction()); } +template <> +void InworldPacketTranslator::TranslateEvent<>(const Inworld::ControlEventConversationUpdate& Original, FInworldConversationUpdateEvent& New) +{ + TranslateInworldPacket(Original, New); + New.EventType = static_cast(Original.GetType()); + New.bIncludePlayer = Original.GetIncludePlayer(); + for (const auto& Agent : Original.GetAgents()) + { + New.Agents.Add(UTF8_TO_TCHAR(Agent.c_str())); + } +} + template<> void InworldPacketTranslator::TranslateEvent(const Inworld::EmotionEvent& Original, FInworldEmotionEvent& New) { diff --git a/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.h b/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.h index e3693b2d..f671080a 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.h +++ b/InworldAI/Source/InworldAIClient/Private/InworldPacketTranslator.h @@ -23,10 +23,11 @@ class InworldPacketTranslator : public Inworld::PacketVisitor virtual void Visit(const Inworld::AudioDataEvent& Event) override { MakePacket(Event); } virtual void Visit(const Inworld::SilenceEvent& Event) override { MakePacket(Event); } virtual void Visit(const Inworld::ControlEvent& Event) override { MakePacket(Event); } - virtual void Visit(const Inworld::EmotionEvent& Event) override { MakePacket(Event); }; - virtual void Visit(const Inworld::CustomEvent& Event) override { MakePacket(Event); }; - virtual void Visit(const Inworld::SessionControlResponse_LoadScene& Event) override { MakePacket(Event); }; - virtual void Visit(const Inworld::SessionControlResponse_LoadCharacters& Event) override { MakePacket(Event); }; + virtual void Visit(const Inworld::ControlEventConversationUpdate& Event) override { MakePacket(Event); } + virtual void Visit(const Inworld::EmotionEvent& Event) override { MakePacket(Event); } + virtual void Visit(const Inworld::CustomEvent& Event) override { MakePacket(Event); } + virtual void Visit(const Inworld::SessionControlResponse_LoadScene& Event) override { MakePacket(Event); } + virtual void Visit(const Inworld::SessionControlResponse_LoadCharacters& Event) override { MakePacket(Event); } virtual void Visit(const Inworld::RelationEvent& Event) override { MakePacket(Event); } TSharedPtr GetPacket() { return Packet; } diff --git a/InworldAI/Source/InworldAIClient/Private/InworldPackets.cpp b/InworldAI/Source/InworldAIClient/Private/InworldPackets.cpp index ffdaa46b..04001b3b 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldPackets.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldPackets.cpp @@ -115,6 +115,9 @@ void FInworldActor::AppendDebugString(FString& Str) const case EInworldActorType::AGENT: AppendToDebugString(Str, TEXT("AGENT")); break; + case EInworldActorType::WORLD: + AppendToDebugString(Str, TEXT("WORLD")); + break; default: break; } @@ -220,6 +223,17 @@ void FInworldControlEvent::AppendDebugString(FString& Str) const AppendToDebugString(Str, FString::FromInt(static_cast(Action))); } +void FInworldConversationUpdateEvent::AppendDebugString(FString& Str) const +{ + AppendToDebugString(Str, TEXT("ConversationUpdate")); + AppendToDebugString(Str, EventType == EInworldConversationUpdateType::STARTED ? TEXT("STARTED") : EventType == EInworldConversationUpdateType::EVICTED ? TEXT("EVICTED") : TEXT("UPDATED")); + AppendToDebugString(Str, bIncludePlayer ? TEXT("IncludePlayer") : TEXT("ExcludePlayer")); + for (const auto& AgentId : Agents) + { + AppendToDebugString(Str, AgentId); + } +} + void FInworldEmotionEvent::AppendDebugString(FString& Str) const { AppendToDebugString(Str, TEXT("Emotion")); @@ -243,13 +257,18 @@ void FInworldCustomEvent::AppendDebugString(FString& Str) const void FInworldLoadCharactersEvent::AppendDebugString(FString& Str) const { - AppendToDebugString(Str, TEXT("ChangeScene")); + AppendToDebugString(Str, TEXT("LoadCharacters")); for (auto& Agent : AgentInfos) { AppendToDebugString(Str, Agent.GivenName); } } +void FInworldChangeSceneEvent::AppendDebugString(FString& Str) const +{ + AppendToDebugString(Str, TEXT("ChangeScene")); +} + void FInworldRelationEvent::AppendDebugString(FString& Str) const { AppendToDebugString(Str, TEXT("Relation")); diff --git a/InworldAI/Source/InworldAIClient/Public/InworldClient.h b/InworldAI/Source/InworldAIClient/Public/InworldClient.h index be1fe13c..f9f059f5 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldClient.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldClient.h @@ -71,29 +71,36 @@ class INWORLDAICLIENT_API UInworldClient : public UObject UFUNCTION(BlueprintCallable, Category = "Load") void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile); + UFUNCTION(BlueprintCallable, Category = "Conversation") + FString UpdateConversation(const FString& ConversationId, const TArray& AgentIds, bool bIncludePlayer); + + UFUNCTION(BlueprintCallable, Category = "Message|Text") + FInworldWrappedPacket SendTextMessage(const FString& AgentId, const FString& Text); UFUNCTION(BlueprintCallable, Category = "Message|Text") - FInworldWrappedPacket SendTextMessage(const TArray& AgentIds, const FString& Text); + FInworldWrappedPacket SendTextMessageToConversation(const FString& ConversationId, const FString& Text); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void SendSoundMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData) { BroadcastSoundMessage({AgentId}, InputData, OutputData); } + void SendSoundMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastSoundMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData); + void SendSoundMessageToConversation(const FString& ConversationId, const TArray& InputData, const TArray& OutputData); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void SendAudioSessionStart(const FString& AgentId) { BroadcastAudioSessionStart({ AgentId }); } + void SendAudioSessionStart(const FString& AgentId); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastAudioSessionStart(const TArray& AgentIds); + void SendAudioSessionStartToConversation(const FString& ConversationId); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void SendAudioSessionStop(const FString& AgentId) { BroadcastAudioSessionStop({ AgentId }); } + void SendAudioSessionStop(const FString& AgentId); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastAudioSessionStop(const TArray& AgentIds); + void SendAudioSessionStopToConversation(const FString& ConversationId); UFUNCTION(BlueprintCallable, Category = "Message|Narration") void SendNarrationEvent(const FString& AgentId, const FString& Content); UFUNCTION(BlueprintCallable, Category = "Message|Trigger") - void SendTrigger(FString AgentId, const FString& Name, const TMap& Params) { BroadcastTrigger({AgentId}, Name, Params); } + void SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params); UFUNCTION(BlueprintCallable, Category = "Message|Trigger") - void BroadcastTrigger(const TArray& AgentIds, const FString& Name, const TMap& Params); + void SendTriggerToConversation(const FString& ConversationId, const FString& Name, const TMap& Params); UFUNCTION(BlueprintCallable, Category = "Message|Mutation") void SendChangeSceneEvent(const FString& SceneName); diff --git a/InworldAI/Source/InworldAIClient/Public/InworldEnums.h b/InworldAI/Source/InworldAIClient/Public/InworldEnums.h index 99fbe71a..24b7aab7 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldEnums.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldEnums.h @@ -70,6 +70,7 @@ enum class EInworldActorType : uint8 UNKNOWN = 0, PLAYER = 1, AGENT = 2, + WORLD = 3, }; UENUM(BlueprintType) @@ -83,3 +84,11 @@ enum class EInworldControlEventAction : uint8 TTS_PLAYBACK_END = 5, }; +UENUM(BlueprintType) +enum class EInworldConversationUpdateType : uint8 +{ + UNKNOWN = 0, + STARTED = 1, + UPDATED = 2, + EVICTED = 3, +}; diff --git a/InworldAI/Source/InworldAIClient/Public/InworldPackets.h b/InworldAI/Source/InworldAIClient/Public/InworldPackets.h index 724001df..f208c646 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldPackets.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldPackets.h @@ -89,10 +89,10 @@ struct INWORLDAICLIENT_API FInworldRouting FInworldRouting() = default; FInworldRouting(const FInworldRouting& Other) = default; - FInworldRouting(const FInworldActor& InSource, const FInworldActor& InTarget, const TArray& InTargets) + FInworldRouting(const FInworldActor& InSource, const FInworldActor& InTarget, const FString& InConversationId) : Source(InSource) , Target(InTarget) - , Targets(InTargets) + , ConversationId(InConversationId) {} void Serialize(FMemoryArchive& Ar); @@ -104,7 +104,7 @@ struct INWORLDAICLIENT_API FInworldRouting UPROPERTY() FInworldActor Target; UPROPERTY() - TArray Targets; + FString ConversationId; }; USTRUCT() @@ -137,6 +137,7 @@ struct FInworldDataEvent; struct FInworldAudioDataEvent; struct FInworldSilenceEvent; struct FInworldControlEvent; +struct FInworldConversationUpdateEvent; struct FInworldEmotionEvent; struct FInworldCancelResponseEvent; struct FInworldSimpleGestureEvent; @@ -154,6 +155,7 @@ class InworldPacketVisitor virtual void Visit(const FInworldAudioDataEvent& Event) { } virtual void Visit(const FInworldSilenceEvent& Event) { } virtual void Visit(const FInworldControlEvent& Event) { } + virtual void Visit(const FInworldConversationUpdateEvent& Event) { } virtual void Visit(const FInworldEmotionEvent& Event) { } virtual void Visit(const FInworldCancelResponseEvent& Event) { } virtual void Visit(const FInworldSimpleGestureEvent& Event) { } @@ -274,7 +276,7 @@ struct INWORLDAICLIENT_API FInworldAudioDataEvent : public FInworldDataEvent bool bFinal = true; protected: - virtual void AppendDebugString(FString& Str) const; + virtual void AppendDebugString(FString& Str) const override; }; USTRUCT(BlueprintType) @@ -291,7 +293,7 @@ struct INWORLDAICLIENT_API FInworldSilenceEvent : public FInworldPacket float Duration = 0.f; protected: - virtual void AppendDebugString(FString& Str) const; + virtual void AppendDebugString(FString& Str) const override; }; USTRUCT(BlueprintType) @@ -308,7 +310,28 @@ struct INWORLDAICLIENT_API FInworldControlEvent : public FInworldPacket EInworldControlEventAction Action = EInworldControlEventAction::UNKNOWN; protected: - virtual void AppendDebugString(FString& Str) const; + virtual void AppendDebugString(FString& Str) const override; +}; + +USTRUCT() +struct INWORLDAICLIENT_API FInworldConversationUpdateEvent : public FInworldControlEvent +{ + GENERATED_BODY() + + FInworldConversationUpdateEvent() = default; + virtual ~FInworldConversationUpdateEvent() = default; + + virtual void Accept(InworldPacketVisitor& Visitor) override { Visitor.Visit(*this); } + + UPROPERTY() + TArray Agents; + UPROPERTY() + EInworldConversationUpdateType EventType; + UPROPERTY() + bool bIncludePlayer; + +protected: + virtual void AppendDebugString(FString& Str) const override; }; USTRUCT(BlueprintType) @@ -327,7 +350,7 @@ struct INWORLDAICLIENT_API FInworldEmotionEvent : public FInworldPacket EInworldCharacterEmotionStrength Strength = EInworldCharacterEmotionStrength::NORMAL; protected: - virtual void AppendDebugString(FString& Str) const; + virtual void AppendDebugString(FString& Str) const override; }; USTRUCT(BlueprintType) @@ -347,7 +370,7 @@ struct INWORLDAICLIENT_API FInworldCustomEvent : public FInworldPacket FInworldReplicatedMapStruct Params; protected: - virtual void AppendDebugString(FString& Str) const; + virtual void AppendDebugString(FString& Str) const override; }; USTRUCT(BlueprintType) @@ -363,7 +386,7 @@ struct INWORLDAICLIENT_API FInworldLoadCharactersEvent : public FInworldPacket TArray AgentInfos; protected: - virtual void AppendDebugString(FString& Str) const; + virtual void AppendDebugString(FString& Str) const override; }; USTRUCT(BlueprintType) @@ -375,6 +398,9 @@ struct INWORLDAICLIENT_API FInworldChangeSceneEvent : public FInworldLoadCharact virtual ~FInworldChangeSceneEvent() = default; virtual void Accept(InworldPacketVisitor& Visitor) override { Visitor.Visit(*this); } + +protected: + virtual void AppendDebugString(FString& Str) const override; }; USTRUCT() @@ -403,5 +429,5 @@ struct INWORLDAICLIENT_API FInworldRelationEvent : public FInworldPacket int32 Trust = 0; protected: - virtual void AppendDebugString(FString& Str) const; + virtual void AppendDebugString(FString& Str) const override; }; diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index d938e915..ba1600a5 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -245,42 +245,12 @@ void UInworldApiSubsystem::LoadPlayerProfile(const FInworldPlayerProfile& Player void UInworldApiSubsystem::SendTextMessage(const FString& AgentId, const FString& Text) { - SendTextMessageMultiAgent({ AgentId }, Text); -} - -void UInworldApiSubsystem::SendTextMessageMultiAgent(const TArray& AgentIds, const FString& Text) -{ - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } - - if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) - { - return; - } - - InworldSession->InworldClient->SendTextMessage(AgentIds, Text); + InworldSession->InworldClient->SendTextMessage(AgentId, Text); } void UInworldApiSubsystem::SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params) { - SendTriggerMultiAgent({ AgentId }, Name, Params); -} - -void UInworldApiSubsystem::SendTriggerMultiAgent(const TArray& AgentIds, const FString& Name, const TMap& Params) -{ - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } - - if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentId must be valid!"))) - { - return; - } - - InworldSession->InworldClient->BroadcastTrigger(AgentIds, Name, Params); + InworldSession->InworldClient->SendTrigger(AgentId, Name, Params); } void UInworldApiSubsystem::SendNarrationEvent(const FString& AgentId, const FString& Content) @@ -298,69 +268,24 @@ void UInworldApiSubsystem::SendNarrationEvent(const FString& AgentId, const FStr InworldSession->InworldClient->SendNarrationEvent(AgentId, Content); } -void UInworldApiSubsystem::SendAudioMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData) +void UInworldApiSubsystem::SendAudioMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData) { if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) { return; } - if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) - { - return; - } - - InworldSession->InworldClient->BroadcastSoundMessage(AgentIds, InputData, OutputData); + InworldSession->InworldClient->SendSoundMessage(AgentId, InputData, OutputData); } -bool UInworldApiSubsystem::StartAudioSession(const FString& AgentId, const AActor* Owner) +void UInworldApiSubsystem::StartAudioSession(const FString& AgentId) { - return StartAudioSessionMultiAgent({ AgentId }, Owner); -} - -bool UInworldApiSubsystem::StartAudioSessionMultiAgent(const TArray& AgentIds, const AActor* Owner) -{ - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return false; - } - - if (AudioSessionOwner) - { - return false; - } - - if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) - { - return false; - } - - AudioSessionOwner = Owner; - - InworldSession->InworldClient->BroadcastAudioSessionStart(AgentIds); - return true; + InworldSession->InworldClient->SendAudioSessionStart(AgentId); } void UInworldApiSubsystem::StopAudioSession(const FString& AgentId) { - StopAudioSessionMultiAgent({ AgentId }); -} - -void UInworldApiSubsystem::StopAudioSessionMultiAgent(const TArray& AgentIds) -{ - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } - - if (!ensureMsgf(AgentIds.Num() != 0, TEXT("AgentIds must be valid!"))) - { - return; - } - - AudioSessionOwner = nullptr; - - InworldSession->InworldClient->BroadcastAudioSessionStop(AgentIds); + InworldSession->InworldClient->SendAudioSessionStop(AgentId); } void UInworldApiSubsystem::ChangeScene(const FString& SceneId) @@ -430,7 +355,6 @@ void UInworldApiSubsystem::Deinitialize() { Super::Deinitialize(); InworldSession = nullptr; - AudioSessionOwner = nullptr; } #if ENGINE_MAJOR_VERSION > 4 @@ -467,6 +391,5 @@ void UInworldApiSubsystem::HandleAudioEventOnClient(TSharedPtrAccept(*InworldSession->PacketVisitor); + InworldSession->HandlePacket(FInworldWrappedPacket(Packet)); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index 2371ed17..d5f19756 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -16,6 +16,14 @@ #include "Net/UnrealNetwork.h" +UInworldCharacter::UInworldCharacter() + : Super() + , PacketVisitor(MakeShared(this)) +{} + +UInworldCharacter::~UInworldCharacter() +{} + void UInworldCharacter::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); @@ -25,6 +33,7 @@ void UInworldCharacter::GetLifetimeReplicatedProps(TArray& Ou BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); } + DOREPLIFETIME(UInworldCharacter, Session); DOREPLIFETIME(UInworldCharacter, AgentInfo); DOREPLIFETIME(UInworldCharacter, TargetPlayer); } @@ -50,47 +59,68 @@ bool UInworldCharacter::CallRemoteFunction(UFunction* Function, void* Parms, FOu return false; } +void UInworldCharacter::HandlePacket(const FInworldWrappedPacket& WrappedPacket) +{ + auto Packet = WrappedPacket.Packet; + if (Packet.IsValid()) + { + Packet->Accept(*PacketVisitor); + } +} + +void UInworldCharacter::SetSession(UInworldSession* InSession) +{ + if (Session == InSession) + { + return; + } + + if (Session) + { + Session->UnregisterCharacter(this); + } + + Session = InSession; + + if (Session) + { + Session->RegisterCharacter(this); + } +} void UInworldCharacter::SendTextMessage(const FString& Text) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->SendTextMessage(this, Text); + Session->SendTextMessage(this, Text); } void UInworldCharacter::SendTrigger(const FString& Name, const TMap& Params) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->SendTrigger(this, Name, Params); + Session->SendTrigger(this, Name, Params); } void UInworldCharacter::SendNarrationEvent(const FString& Content) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->SendNarrationEvent(this, Content); + Session->SendNarrationEvent(this, Content); } void UInworldCharacter::SendAudioSessionStart() { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->SendAudioSessionStart(this); + Session->SendAudioSessionStart(this); } void UInworldCharacter::SendAudioSessionStop() { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->SendAudioSessionStop(this); + Session->SendAudioSessionStop(this); } void UInworldCharacter::SendSoundMessage(const TArray& InputData, const TArray& OutputData) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->SendSoundMessage(this, InputData, OutputData); + Session->SendSoundMessage(this, InputData, OutputData); } void UInworldCharacter::CancelResponse(const FString& InteractionId, const TArray& UtteranceIds) { - UInworldSession* InworldSession = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->CancelResponse(this, InteractionId, UtteranceIds); + Session->CancelResponse(this, InteractionId, UtteranceIds); } TScriptInterface UInworldCharacter::GetInworldCharacterOwner() @@ -104,7 +134,6 @@ TScriptInterface UInworldCharacter::GetInworldC void UInworldCharacter::SetBrainName(const FString& BrainName) { - UInworldSession* Session = IInworldCharacterOwnerInterface::Execute_GetInworldSession(GetOuter()); if (!AgentInfo.BrainName.IsEmpty()) { if (Session != nullptr) @@ -186,3 +215,50 @@ void UInworldCharacter::OnRep_TargetPlayer() OnTargetPlayerChangedDelegateNative.Broadcast(); OnTargetPlayerChangedDelegate.Broadcast(); } + +void UInworldCharacter::FInworldCharacterPacketVisitor::Visit(const FInworldTextEvent& Event) +{ + Character->OnInworldTextEventDelegateNative.Broadcast(Event); + Character->OnInworldTextEventDelegate.Broadcast(Event); +} + +void UInworldCharacter::FInworldCharacterPacketVisitor::Visit(const FInworldAudioDataEvent& Event) +{ + Character->OnInworldAudioEventDelegateNative.Broadcast(Event); + Character->OnInworldAudioEventDelegate.Broadcast(Event); +} + +void UInworldCharacter::FInworldCharacterPacketVisitor::Visit(const FInworldSilenceEvent& Event) +{ + Character->OnInworldSilenceEventDelegateNative.Broadcast(Event); + Character->OnInworldSilenceEventDelegate.Broadcast(Event); +} + +void UInworldCharacter::FInworldCharacterPacketVisitor::Visit(const FInworldControlEvent& Event) +{ + Character->OnInworldControlEventDelegateNative.Broadcast(Event); + Character->OnInworldControlEventDelegate.Broadcast(Event); +} + +void UInworldCharacter::FInworldCharacterPacketVisitor::Visit(const FInworldEmotionEvent& Event) +{ + Character->OnInworldEmotionEventDelegateNative.Broadcast(Event); + Character->OnInworldEmotionEventDelegate.Broadcast(Event); +} + +void UInworldCharacter::FInworldCharacterPacketVisitor::Visit(const FInworldCustomEvent& Event) +{ + Character->OnInworldCustomEventDelegateNative.Broadcast(Event); + Character->OnInworldCustomEventDelegate.Broadcast(Event); +} + +TArray Inworld::CharactersToAgentIds(const TArray& InworldCharacters) +{ + TArray AgentIds = {}; + AgentIds.Reserve(InworldCharacters.Num()); + for (const UInworldCharacter* Character : InworldCharacters) + { + AgentIds.Add(Character->GetAgentInfo().AgentId); + } + return AgentIds; +} diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 159c458f..2425429c 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -58,6 +58,7 @@ void UInworldCharacterComponent::OnUnregister() InworldCharacter->MarkPendingKill(); #endif } + InworldCharacter = nullptr; } @@ -67,8 +68,7 @@ void UInworldCharacterComponent::InitializeComponent() UWorld* World = GetWorld(); if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) { - InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); - OnRep_InworldSession(); + InworldCharacter->SetSession(World->GetSubsystem()->GetInworldSession()); } #if WITH_EDITOR @@ -96,9 +96,10 @@ void UInworldCharacterComponent::UninitializeComponent() { Super::UninitializeComponent(); - if (GetOwnerRole() == ROLE_Authority) + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) { - Unregister(); + InworldCharacter->SetSession(nullptr); } #if WITH_EDITOR @@ -120,7 +121,7 @@ void UInworldCharacterComponent::BeginPlay() if (GetOwnerRole() == ROLE_Authority) { - Register(); + InworldCharacter->SetBrainName(BrainName); } for (auto* Pb : Playbacks) @@ -131,6 +132,11 @@ void UInworldCharacterComponent::BeginPlay() void UInworldCharacterComponent::EndPlay(EEndPlayReason::Type Reason) { + if (GetOwnerRole() == ROLE_Authority) + { + InworldCharacter->SetBrainName({}); + } + for (auto* Pb : Playbacks) { Pb->EndPlay(); @@ -168,7 +174,6 @@ void UInworldCharacterComponent::GetLifetimeReplicatedProps(TArraySendAudioSessionStop(); } -bool UInworldCharacterComponent::Register() -{ - if (BrainName.IsEmpty()) - { - return false; - } - - InworldCharacter->SetBrainName(BrainName); - - return true; -} - -bool UInworldCharacterComponent::Unregister() -{ - if (BrainName.IsEmpty()) - { - return false; - } - - InworldCharacter->SetBrainName({}); - - return true; -} - FVector UInworldCharacterComponent::GetTargetPlayerCameraLocation() { if (InworldCharacter == nullptr || InworldCharacter->GetTargetPlayer() == nullptr) @@ -308,42 +289,6 @@ void UInworldCharacterComponent::Multicast_VisitText_Implementation(const FInwor return; } - auto ProcessTarget = [this, Event](const FInworldActor& ToActor) - { - if (Event.Routing.Source.Type == EInworldActorType::PLAYER && ToActor.Type == EInworldActorType::AGENT && ToActor.Name == GetAgentId()) - { - if (Event.Final) - { - UE_LOG(LogInworldAIIntegration, Log, TEXT("To %s: %s"), *ToActor.Name, *Event.Text); - } - - // Don't add to queue, player talking is instant. - FCharacterMessagePlayerTalk PlayerTalk; - PlayerTalk.InteractionId = Event.PacketId.InteractionId; - PlayerTalk.UtteranceId = Event.PacketId.UtteranceId; - PlayerTalk.Text = Event.Text; - PlayerTalk.bTextFinal = Event.Final; - - OnPlayerTalk.Broadcast(PlayerTalk); - - TSharedPtr CurrentMessage = GetCurrentMessage(); - if (CurrentMessage.IsValid() && CurrentMessage->InteractionId != Event.PacketId.InteractionId) - { - CancelCurrentInteraction(); - } - } - }; - - ProcessTarget(Event.Routing.Target); - - for (const auto& ToActor : Event.Routing.Targets) - { - if (ToActor.Name != Event.Routing.Target.Name) - { - ProcessTarget(ToActor); - } - } - const auto& FromActor = Event.Routing.Source; if (FromActor.Type == EInworldActorType::AGENT) { @@ -357,6 +302,28 @@ void UInworldCharacterComponent::Multicast_VisitText_Implementation(const FInwor MessageToUpdate->bTextFinal = Event.Final; }); } + else if (FromActor.Type == EInworldActorType::PLAYER) + { + if (Event.Final) + { + UE_LOG(LogInworldAIIntegration, Log, TEXT("To %s: %s"), *Event.Routing.Target.Name, *Event.Text); + } + + // Don't add to queue, player talking is instant. + FCharacterMessagePlayerTalk PlayerTalk; + PlayerTalk.InteractionId = Event.PacketId.InteractionId; + PlayerTalk.UtteranceId = Event.PacketId.UtteranceId; + PlayerTalk.Text = Event.Text; + PlayerTalk.bTextFinal = Event.Final; + + OnPlayerTalk.Broadcast(PlayerTalk); + + TSharedPtr CurrentMessage = GetCurrentMessage(); + if (CurrentMessage.IsValid() && CurrentMessage->InteractionId != Event.PacketId.InteractionId) + { + CancelCurrentInteraction(); + } + } } void UInworldCharacterComponent::VisitAudioOnClient(const FInworldAudioDataEvent& Event) @@ -456,37 +423,13 @@ void UInworldCharacterComponent::Multicast_VisitEmotion_Implementation(const FIn } } -bool UInworldCharacterComponent::ShouldHandleEvent(const FInworldRouting& Routing) -{ - bool bShouldHandle = false; - bShouldHandle |= Routing.Source.Name == GetAgentId(); - if (Routing.Source.Type == EInworldActorType::PLAYER) - { - bShouldHandle |= Routing.Target.Name == GetAgentId(); - for (const auto& Target : Routing.Targets) - { - bShouldHandle |= Target.Name == GetAgentId(); - } - } - return bShouldHandle; -} - void UInworldCharacterComponent::OnInworldTextEvent(const FInworldTextEvent& Event) { - if (!ShouldHandleEvent(Event.Routing)) - { - return; - } Multicast_VisitText(Event); } void UInworldCharacterComponent::OnInworldAudioEvent(const FInworldAudioDataEvent& Event) { - if (!ShouldHandleEvent(Event.Routing)) - { - return; - } - if (GetNetMode() == NM_Standalone || GetNetMode() == NM_Client) { VisitAudioOnClient(Event); @@ -513,37 +456,21 @@ void UInworldCharacterComponent::OnInworldAudioEvent(const FInworldAudioDataEven void UInworldCharacterComponent::OnInworldSilenceEvent(const FInworldSilenceEvent& Event) { - if (!ShouldHandleEvent(Event.Routing)) - { - return; - } Multicast_VisitSilence(Event); } void UInworldCharacterComponent::OnInworldControlEvent(const FInworldControlEvent& Event) { - if (!ShouldHandleEvent(Event.Routing)) - { - return; - } Multicast_VisitControl(Event); } void UInworldCharacterComponent::OnInworldEmotionEvent(const FInworldEmotionEvent& Event) { - if (!ShouldHandleEvent(Event.Routing)) - { - return; - } Multicast_VisitEmotion(Event); } void UInworldCharacterComponent::OnInworldCustomEvent(const FInworldCustomEvent& Event) { - if (!ShouldHandleEvent(Event.Routing)) - { - return; - } Multicast_VisitCustom(Event); } @@ -593,18 +520,12 @@ void UInworldCharacterComponent::OnRep_InworldCharacter() } ); OnPlayerInteractionStateChanged.Broadcast(InworldCharacter->GetTargetPlayer() != nullptr); - } -} -void UInworldCharacterComponent::OnRep_InworldSession() -{ - if (InworldSession.IsValid()) - { - InworldSession->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); - InworldSession->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); - InworldSession->OnInworldSilenceEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldSilenceEvent); - InworldSession->OnInworldControlEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldControlEvent); - InworldSession->OnInworldEmotionEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldEmotionEvent); - InworldSession->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); + InworldCharacter->OnInworldTextEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldTextEvent); + InworldCharacter->OnInworldAudioEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldAudioEvent); + InworldCharacter->OnInworldSilenceEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldSilenceEvent); + InworldCharacter->OnInworldControlEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldControlEvent); + InworldCharacter->OnInworldEmotionEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldEmotionEvent); + InworldCharacter->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index d2b4aac2..e7c9e881 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -25,6 +25,7 @@ void UInworldPlayer::GetLifetimeReplicatedProps(TArray& OutLi BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); } + DOREPLIFETIME(UInworldPlayer, Session); DOREPLIFETIME(UInworldPlayer, TargetCharacters); } @@ -49,34 +50,63 @@ bool UInworldPlayer::CallRemoteFunction(UFunction* Function, void* Parms, FOutPa return false; } -void UInworldPlayer::BroadcastTextMessage_Implementation(const FString& Text) +void UInworldPlayer::SetSession(UInworldSession* InSession) { - UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->BroadcastTextMessage(GetTargetCharacters(), Text); + if (Session == InSession) + { + return; + } + + if (Session) + { + Session->UnregisterPlayer(this); + } + + Session = InSession; + + if (Session) + { + Session->RegisterPlayer(this); + } } -void UInworldPlayer::BroadcastTrigger(const FString& Name, const TMap& Params) +void UInworldPlayer::SendTextMessageToConversation(const FString& Text) { - UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->BroadcastTrigger(GetTargetCharacters(), Name, Params); + Session->SendTextMessageToConversation(this, Text); } -void UInworldPlayer::BroadcastAudioSessionStart() +void UInworldPlayer::SendTriggerToConversation(const FString& Name, const TMap& Params) { - UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->BroadcastAudioSessionStart(GetTargetCharacters()); + Session->SendTriggerToConversation(this, Name, Params); } -void UInworldPlayer::BroadcastAudioSessionStop() +void UInworldPlayer::SendAudioSessionStartToConversation() { - UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->BroadcastAudioSessionStop(GetTargetCharacters()); + if (ConversationId.IsEmpty() || bHasAudioSession) + { + return; + } + bHasAudioSession = true; + Session->SendAudioSessionStartToConversation(this); } -void UInworldPlayer::BroadcastSoundMessage(const TArray& Input, const TArray& Output) +void UInworldPlayer::SendAudioSessionStopToConversation() { - UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(GetOuter()); - InworldSession->BroadcastSoundMessage(GetTargetCharacters(), Input, Output); + if (ConversationId.IsEmpty() || !bHasAudioSession) + { + return; + } + bHasAudioSession = false; + Session->SendAudioSessionStopToConversation(this); +} + +void UInworldPlayer::SendSoundMessageToConversation(const TArray& Input, const TArray& Output) +{ + if (!bHasAudioSession) + { + return; + } + Session->SendSoundMessageToConversation(this, Input, Output); } TScriptInterface UInworldPlayer::GetInworldPlayerOwner() @@ -94,6 +124,9 @@ void UInworldPlayer::AddTargetCharacter(UInworldCharacter* TargetCharacter) { TargetCharacter->SetTargetPlayer(this); TargetCharacters.AddUnique(TargetCharacter); + + UpdateConversation(); + OnTargetCharacterAddedDelegateNative.Broadcast(TargetCharacter); OnTargetCharacterAddedDelegate.Broadcast(TargetCharacter); @@ -108,6 +141,9 @@ void UInworldPlayer::RemoveTargetCharacter(UInworldCharacter* TargetCharacter) { TargetCharacter->ClearTargetPlayer(); TargetCharacters.RemoveSingle(TargetCharacter); + + UpdateConversation(); + OnTargetCharacterRemovedDelegateNative.Broadcast(TargetCharacter); OnTargetCharacterRemovedDelegate.Broadcast(TargetCharacter); @@ -118,22 +154,53 @@ void UInworldPlayer::RemoveTargetCharacter(UInworldCharacter* TargetCharacter) void UInworldPlayer::ClearAllTargetCharacters() { - TArray TargetCharactersCopy = TargetCharacters; - for (UInworldCharacter* TargetCharacter : TargetCharactersCopy) + TArray CharactersToRemove = {}; + for (UInworldCharacter* TargetCharacter : TargetCharacters) { - bool bRemovedAny = false; if (TargetCharacter->GetTargetPlayer() == this) { - TargetCharacter->ClearTargetPlayer(); - TargetCharacters.RemoveSingle(TargetCharacter); - OnTargetCharacterRemovedDelegateNative.Broadcast(TargetCharacter); - OnTargetCharacterRemovedDelegate.Broadcast(TargetCharacter); - bRemovedAny = true; + CharactersToRemove.Add(TargetCharacter); + } + } + if (CharactersToRemove.Num() > 0) + { + for (UInworldCharacter* CharacterToRemove : CharactersToRemove) + { + CharacterToRemove->ClearTargetPlayer(); + TargetCharacters.RemoveSingle(CharacterToRemove); } - if (bRemovedAny) + + UpdateConversation(); + + for (UInworldCharacter* CharacterToRemove : CharactersToRemove) + { + OnTargetCharacterRemovedDelegateNative.Broadcast(CharacterToRemove); + OnTargetCharacterRemovedDelegate.Broadcast(CharacterToRemove); + } + + OnTargetCharactersChangedDelegateNative.Broadcast(); + OnTargetCharactersChangedDelegate.Broadcast(); + } +} + +void UInworldPlayer::UpdateConversation() +{ + FString NextConversationId = Session->GetClient()->UpdateConversation(ConversationId, Inworld::CharactersToAgentIds(TargetCharacters), false); + if (ConversationId != NextConversationId) + { + const bool bHadAudioSession = bHasAudioSession; + if (bHasAudioSession) + { + SendAudioSessionStopToConversation(); + } + + ConversationId = NextConversationId; + OnConversationChangedDelegateNative.Broadcast(); + OnConversationChangedDelegate.Broadcast(); + + if (bHadAudioSession) { - OnTargetCharactersChangedDelegateNative.Broadcast(); - OnTargetCharactersChangedDelegate.Broadcast(); + SendAudioSessionStartToConversation(); } } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index 1c8f2194..5ea186fb 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -9,8 +9,9 @@ #undef PlaySound #include "InworldPlayerAudioCaptureComponent.h" -#include "InworldPlayerComponent.h" +#include "InworldPlayer.h" #include "InworldCharacter.h" +#include "InworldSession.h" #include "AudioMixerDevice.h" #include "AudioMixerSubmix.h" #include "AudioResampler.h" @@ -168,24 +169,20 @@ void UInworldPlayerAudioCaptureComponent::BeginPlay() if (ensureMsgf(PlayerOwnerComponents.Num() > 0, TEXT("The owner of the AudioCapture must contain an InworldPlayerOwner!"))) { InworldPlayer = IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(PlayerOwnerComponents[0]); - OnPlayerTargetCharactersChanged = InworldPlayer->OnTargetCharactersChanged().AddLambda( + OnPlayerConversationChanged = InworldPlayer->OnConversationChanged().AddLambda( [this]() -> void { - PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); - PlayerAudioTargetState.bDirty = true; EvaluateVoiceCapture(); } ); - PlayerAudioTargetState.DesiredCharacters = InworldPlayer->GetTargetCharacters(); - InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetOuter()); - OnSessionConnectionStateChanged = InworldSession->OnConnectionStateChanged().AddLambda( + OnSessionConnectionStateChanged = InworldPlayer->GetSession()->OnConnectionStateChanged().AddLambda( [this](EInworldConnectionState ConnectionState) -> void { EvaluateVoiceCapture(); } ); - OnSessionLoaded = InworldSession->OnLoaded().AddLambda( + OnSessionLoaded = InworldPlayer->GetSession()->OnLoaded().AddLambda( [this](bool bLoaded) -> void { EvaluateVoiceCapture(); @@ -250,16 +247,10 @@ void UInworldPlayerAudioCaptureComponent::EndPlay(const EEndPlayReason::Type End if (GetOwnerRole() == ROLE_Authority) { - if (InworldPlayer.IsValid()) - { - InworldPlayer->OnTargetCharactersChanged().Remove(OnPlayerTargetCharactersChanged); - } + InworldPlayer->OnConversationChanged().Remove(OnPlayerConversationChanged); - if (InworldSession.IsValid()) - { - InworldSession->OnConnectionStateChanged().Remove(OnSessionConnectionStateChanged); - InworldSession->OnLoaded().Remove(OnSessionLoaded); - } + InworldPlayer->GetSession()->OnConnectionStateChanged().Remove(OnSessionConnectionStateChanged); + InworldPlayer->GetSession()->OnLoaded().Remove(OnSessionLoaded); } Super::EndPlay(EndPlayReason); @@ -306,31 +297,22 @@ void UInworldPlayerAudioCaptureComponent::EvaluateVoiceCapture() { const bool bIsMicHot = !bMuted; const bool bIsWorldPlaying = !GetWorld()->IsPaused(); - const bool bHasTargetCharacter = PlayerAudioTargetState.DesiredCharacters.Num() != 0; - const EInworldConnectionState ConnectionState = InworldSession.IsValid() ? InworldSession->GetConnectionState() : EInworldConnectionState::Idle; - const bool bHasActiveInworldSession = InworldSession.IsValid() && InworldSession->IsLoaded() && (ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting); + const bool bHasConversation = !InworldPlayer->GetConversationId().IsEmpty(); + UInworldSession* InworldSession = InworldPlayer->GetSession(); + const EInworldConnectionState ConnectionState = InworldSession ? InworldSession->GetConnectionState() : EInworldConnectionState::Idle; + const bool bHasActiveInworldSession = InworldSession && InworldSession->IsLoaded() && (ConnectionState == EInworldConnectionState::Connected || ConnectionState == EInworldConnectionState::Reconnecting); - const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasTargetCharacter && bHasActiveInworldSession; + const bool bShouldCaptureVoice = bIsMicHot && bIsWorldPlaying && bHasConversation && bHasActiveInworldSession; - if (bShouldCaptureVoice && bServerCapturingVoice && PlayerAudioTargetState.bDirty) - { - InworldSession->BroadcastAudioSessionStop(PlayerAudioTargetState.ActiveCharacters); - InworldSession->BroadcastAudioSessionStart(PlayerAudioTargetState.DesiredCharacters); - PlayerAudioTargetState.ActiveCharacters = PlayerAudioTargetState.DesiredCharacters; - PlayerAudioTargetState.bDirty = false; - } - else if (bShouldCaptureVoice != bServerCapturingVoice) + if (bShouldCaptureVoice != bServerCapturingVoice) { if (bShouldCaptureVoice) { - InworldSession->BroadcastAudioSessionStart(PlayerAudioTargetState.DesiredCharacters); - PlayerAudioTargetState.ActiveCharacters = PlayerAudioTargetState.DesiredCharacters; - PlayerAudioTargetState.bDirty = false; + InworldPlayer->SendAudioSessionStartToConversation(); } else { - InworldSession->BroadcastAudioSessionStop(PlayerAudioTargetState.ActiveCharacters); - PlayerAudioTargetState.ActiveCharacters = {}; + InworldPlayer->SendAudioSessionStopToConversation(); } bServerCapturingVoice = bShouldCaptureVoice; @@ -441,9 +423,9 @@ void UInworldPlayerAudioCaptureComponent::StopCapture() void UInworldPlayerAudioCaptureComponent::Server_ProcessVoiceCaptureChunk_Implementation(FPlayerVoiceCaptureInfoRep PlayerVoiceCaptureInfo) { - if (PlayerAudioTargetState.ActiveCharacters.Num() != 0 && InworldSession.IsValid()) + if (InworldPlayer.IsValid()) { - InworldSession->BroadcastSoundMessage(PlayerAudioTargetState.ActiveCharacters, PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); + InworldPlayer->SendSoundMessageToConversation(PlayerVoiceCaptureInfo.MicSoundData, PlayerVoiceCaptureInfo.OutputSoundData); } } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index 5e816d66..f036aa25 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -59,15 +59,18 @@ void UInworldPlayerComponent::InitializeComponent() UWorld* World = GetWorld(); if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) { - InworldSession = GetWorld()->GetSubsystem()->GetInworldSession(); + InworldPlayer->SetSession(World->GetSubsystem()->GetInworldSession()); } } -void UInworldPlayerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +void UInworldPlayerComponent::UninitializeComponent() { - InworldPlayer = nullptr; - - Super::EndPlay(EndPlayReason); + Super::UninitializeComponent(); + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) + { + InworldPlayer->SetSession(nullptr); + } } void UInworldPlayerComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const @@ -75,7 +78,6 @@ void UInworldPlayerComponent::GetLifetimeReplicatedProps(TArray UInworldPlayerComponent::GetTargetInworldCha void UInworldPlayerComponent::ContinueMultiAgentConversation() { - if (InworldPlayer->GetTargetCharacters().Num() > 1) - { - InworldPlayer->BroadcastTrigger("inworld.conversation.next_turn", {}); - } + InworldPlayer->SendTriggerToConversation(TEXT("inworld.conversation.next_turn"), {}); } void UInworldPlayerComponent::SetTargetInworldCharacter(UInworldCharacterComponent* Character) @@ -145,26 +144,26 @@ void UInworldPlayerComponent::SendTextMessageToTarget(const FString& Message) { if (!Message.IsEmpty()) { - InworldPlayer->BroadcastTextMessage(Message); + InworldPlayer->SendTextMessageToConversation(Message); } } void UInworldPlayerComponent::SendTriggerToTarget(const FString& Name, const TMap& Params) { - InworldPlayer->BroadcastTrigger(Name, Params); + InworldPlayer->SendTriggerToConversation(Name, Params); } void UInworldPlayerComponent::StartAudioSessionWithTarget() { - InworldPlayer->BroadcastAudioSessionStart(); + InworldPlayer->SendAudioSessionStartToConversation(); } void UInworldPlayerComponent::StopAudioSessionWithTarget() { - InworldPlayer->BroadcastAudioSessionStop(); + InworldPlayer->SendAudioSessionStopToConversation(); } void UInworldPlayerComponent::SendAudioMessageToTarget(const TArray& InputData, const TArray& OutputData) { - InworldPlayer->BroadcastSoundMessage(InputData, OutputData); + InworldPlayer->SendSoundMessageToConversation(InputData, OutputData); } diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 2c1d56ed..9c2261d5 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -72,7 +72,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() } } - UInworldSession* InworldSession = IInworldPlayerOwnerInterface::Execute_GetInworldSession(InworldPlayer->GetOuter()); + UInworldSession* InworldSession = InworldPlayer->GetSession(); if (!InworldSession) { return; diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index b48a28a0..ab925da8 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -8,6 +8,7 @@ #include "InworldSession.h" #include "InworldCharacter.h" +#include "InworldPlayer.h" #include "InworldClient.h" #include "InworldAIIntegrationModule.h" @@ -19,21 +20,52 @@ #include "Net/UnrealNetwork.h" UInworldSession::UInworldSession() - : PacketVisitor(MakeShared(this)) + : InworldClient(nullptr) + , bIsLoaded(false) + , PacketVisitor(MakeShared(this)) {} UInworldSession::~UInworldSession() {} +void UInworldSession::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + if (UBlueprintGeneratedClass* BPCClass = Cast(GetClass())) + { + BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); + } + + DOREPLIFETIME(UInworldSession, bIsLoaded); + DOREPLIFETIME(UInworldSession, RegisteredCharacters); +} + +int32 UInworldSession::GetFunctionCallspace(UFunction* Function, FFrame* Stack) +{ + if (HasAnyFlags(RF_ClassDefaultObject) || !IsSupportedForNetworking()) + { + return GEngine->GetGlobalFunctionCallspace(Function, this, Stack); + } + + return GetOuter()->GetFunctionCallspace(Function, Stack); +} + +bool UInworldSession::CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) +{ + AActor* Owner = GetTypedOuter(); + if (UNetDriver* NetDriver = Owner->GetNetDriver()) + { + NetDriver->ProcessRemoteFunction(Owner, Function, Parms, OutParms, Stack, this); + return true; + } + return false; +} + void UInworldSession::Init() { InworldClient = NewObject(this); - OnClientPacketReceivedHandle = InworldClient->OnPacketReceived().AddLambda( - [this](const FInworldWrappedPacket& WrappedPacket) -> void - { - WrappedPacket.Packet->Accept(*PacketVisitor); - } - ); + OnClientPacketReceivedHandle = InworldClient->OnPacketReceived().AddUObject(this, &UInworldSession::HandlePacket); OnClientConnectionStateChangedHandle = InworldClient->OnConnectionStateChanged().AddLambda( [this](EInworldConnectionState ConnectionState) -> void { @@ -47,13 +79,18 @@ void UInworldSession::Init() if (ConnectionState == EInworldConnectionState::Disconnected) { + UWorld* World = GetWorld(); + if (!World || World->bIsTearingDown) + { + return; + } if (CurrentRetryConnectionTime == 0.f) { ResumeSession(); } else { - GetWorld()->GetTimerManager().SetTimer(RetryConnectionTimerHandle, this, &UInworldSession::ResumeSession, CurrentRetryConnectionTime); + World->GetTimerManager().SetTimer(RetryConnectionTimerHandle, this, &UInworldSession::ResumeSession, CurrentRetryConnectionTime); } CurrentRetryConnectionTime += FMath::Min(CurrentRetryConnectionTime + RetryConnectionIntervalTime, MaxRetryConnectionTime); } @@ -91,43 +128,58 @@ void UInworldSession::Destroy() InworldClient = nullptr; } -void UInworldSession::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +void UInworldSession::HandlePacket(const FInworldWrappedPacket& WrappedPacket) { - Super::GetLifetimeReplicatedProps(OutLifetimeProps); - - if (UBlueprintGeneratedClass* BPCClass = Cast(GetClass())) + auto Packet = WrappedPacket.Packet; + if (Packet.IsValid()) { - BPCClass->GetLifetimeBlueprintReplicationList(OutLifetimeProps); - } + Packet->Accept(*PacketVisitor); - DOREPLIFETIME(UInworldSession, bIsLoaded); - DOREPLIFETIME(UInworldSession, RegisteredCharacters); -} + const auto& Source = Packet->Routing.Source; + const auto& Target = Packet->Routing.Target; + const auto& ConversationId = Packet->Routing.ConversationId; -int32 UInworldSession::GetFunctionCallspace(UFunction* Function, FFrame* Stack) -{ - if (HasAnyFlags(RF_ClassDefaultObject) || !IsSupportedForNetworking()) - { - return GEngine->GetGlobalFunctionCallspace(Function, this, Stack); - } - - return GetOuter()->GetFunctionCallspace(Function, Stack); -} + if (Source.Type == EInworldActorType::AGENT) + { + if (UInworldCharacter** SourceCharacter = AgentIdToCharacter.Find(Source.Name)) + { + (*SourceCharacter)->HandlePacket(WrappedPacket); + } + } + if (Target.Type == EInworldActorType::AGENT) + { + if (UInworldCharacter** TargetCharacter = AgentIdToCharacter.Find(Target.Name)) + { + (*TargetCharacter)->HandlePacket(WrappedPacket); + } -bool UInworldSession::CallRemoteFunction(UFunction* Function, void* Parms, FOutParmRec* OutParms, FFrame* Stack) -{ - AActor* Owner = GetTypedOuter(); - if (UNetDriver* NetDriver = Owner->GetNetDriver()) - { - NetDriver->ProcessRemoteFunction(Owner, Function, Parms, OutParms, Stack, this); - return true; + if (TArray* AgentIds = ConversationIdToAgentIds.Find(ConversationId)) + { + for (const FString& AgentId : *AgentIds) + { + if (AgentId == Target.Name) + { + continue; + } + if (UInworldCharacter** TargetCharacter = AgentIdToCharacter.Find(AgentId)) + { + (*TargetCharacter)->HandlePacket(WrappedPacket); + } + } + } + } } - return false; } void UInworldSession::RegisterCharacter(UInworldCharacter* Character) { const FString& BrainName = Character->GetAgentInfo().BrainName; + + if (BrainName.IsEmpty()) + { + return; + } + if (!ensureMsgf(!BrainNameToCharacter.Contains(BrainName), TEXT("UInworldSession::RegisterInworldCharacter: Character already registered for Brain: %s!"), *BrainName)) { return; @@ -154,6 +206,12 @@ void UInworldSession::RegisterCharacter(UInworldCharacter* Character) void UInworldSession::UnregisterCharacter(UInworldCharacter* Character) { const FString& BrainName = Character->GetAgentInfo().BrainName; + + if (BrainName.IsEmpty()) + { + return; + } + if (!ensureMsgf(BrainNameToCharacter.Contains(BrainName) && BrainNameToCharacter[BrainName] == Character, TEXT("UInworldSession::UnregisterInworldCharacter: Component mismatch for Brain: %s!"), *BrainName)) { return; @@ -166,6 +224,16 @@ void UInworldSession::UnregisterCharacter(UInworldCharacter* Character) Character->Unpossess(); } +void UInworldSession::RegisterPlayer(UInworldPlayer* Player) +{ + RegisteredPlayers.Add(Player); +} + +void UInworldSession::UnregisterPlayer(UInworldPlayer* Player) +{ + RegisteredPlayers.Remove(Player); +} + void UInworldSession::StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet) { InworldClient->StartSession(SceneId, PlayerProfile, Auth, Save, SessionToken, CapabilitySet); @@ -177,53 +245,62 @@ void UInworldSession::StopSession() InworldClient->StopSession(); } -TArray CharactersToAgentIds(const TArray& InworldCharacters) -{ - TArray AgentIds = {}; - AgentIds.Reserve(InworldCharacters.Num()); - for (const UInworldCharacter* Character : InworldCharacters) - { - AgentIds.Add(Character->GetAgentInfo().AgentId); - } - return AgentIds; -} - void UInworldSession::LoadCharacters(const TArray& Characters) { - InworldClient->LoadCharacters(CharactersToAgentIds(Characters)); + InworldClient->LoadCharacters(Inworld::CharactersToAgentIds(Characters)); } void UInworldSession::UnloadCharacters(const TArray& Characters) { - InworldClient->UnloadCharacters(CharactersToAgentIds(Characters)); + InworldClient->UnloadCharacters(Inworld::CharactersToAgentIds(Characters)); } -void UInworldSession::BroadcastTextMessage(const TArray& Characters, const FString& Message) +void UInworldSession::SendTextMessage(UInworldCharacter* Character, const FString& Message) { - if (!ensureMsgf(InworldClient, TEXT("InworldSession: InworldClient is null! Ensure to call Init() on Session."))) + auto Packet = InworldClient->SendTextMessage(Character->GetAgentInfo().AgentId, Message).Packet; + if (Packet.IsValid()) { - return; + Packet->Accept(*PacketVisitor); } - auto Packet = InworldClient->SendTextMessage(CharactersToAgentIds(Characters), Message).Packet; +} + +void UInworldSession::SendTextMessageToConversation(UInworldPlayer* Player, const FString& Message) +{ + auto Packet = InworldClient->SendTextMessageToConversation(Player->GetConversationId(), Message).Packet; if (Packet.IsValid()) { Packet->Accept(*PacketVisitor); } } -void UInworldSession::BroadcastSoundMessage(const TArray& Characters, const TArray& InputData, const TArray& OutputData) +void UInworldSession::SendSoundMessage(UInworldCharacter* Character, const TArray& InputData, const TArray& OutputData) { - InworldClient->BroadcastSoundMessage(CharactersToAgentIds(Characters), InputData, OutputData); + InworldClient->SendSoundMessage(Character->GetAgentInfo().AgentId, InputData, OutputData); } -void UInworldSession::BroadcastAudioSessionStart(const TArray& Characters) +void UInworldSession::SendSoundMessageToConversation(UInworldPlayer* Player, const TArray& InputData, const TArray& OutputData) { - InworldClient->BroadcastAudioSessionStart(CharactersToAgentIds(Characters)); + InworldClient->SendSoundMessageToConversation(Player->GetConversationId(), InputData, OutputData); } -void UInworldSession::BroadcastAudioSessionStop(const TArray& Characters) +void UInworldSession::SendAudioSessionStart(UInworldCharacter* Character) { - InworldClient->BroadcastAudioSessionStop(CharactersToAgentIds(Characters)); + InworldClient->SendAudioSessionStart(Character->GetAgentInfo().AgentId); +} + +void UInworldSession::SendAudioSessionStartToConversation(UInworldPlayer* Player) +{ + InworldClient->SendAudioSessionStartToConversation(Player->GetConversationId()); +} + +void UInworldSession::SendAudioSessionStop(UInworldCharacter* Character) +{ + InworldClient->SendAudioSessionStop(Character->GetAgentInfo().AgentId); +} + +void UInworldSession::SendAudioSessionStopToConversation(UInworldPlayer* Player) +{ + InworldClient->SendAudioSessionStopToConversation(Player->GetConversationId()); } void UInworldSession::SendNarrationEvent(UInworldCharacter* Character, const FString& Content) @@ -231,9 +308,14 @@ void UInworldSession::SendNarrationEvent(UInworldCharacter* Character, const FSt InworldClient->SendNarrationEvent(Character->GetAgentInfo().AgentId, Content); } -void UInworldSession::BroadcastTrigger(const TArray& Characters, const FString& Name, const TMap& Params) +void UInworldSession::SendTrigger(UInworldCharacter* Character, const FString& Name, const TMap& Params) +{ + InworldClient->SendTrigger(Character->GetAgentInfo().AgentId, Name, Params); +} + +void UInworldSession::SendTriggerToConversation(UInworldPlayer* Player, const FString& Name, const TMap& Params) { - InworldClient->BroadcastTrigger(CharactersToAgentIds(Characters), Name, Params); + InworldClient->SendTrigger(Player->GetConversationId(), Name, Params); } void UInworldSession::SendChangeSceneEvent(const FString& SceneName) @@ -311,40 +393,38 @@ void UInworldSession::OnRep_IsLoaded() OnLoadedDelegate.Broadcast(bIsLoaded); } -void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldTextEvent& Event) -{ - Session->OnInworldTextEventDelegateNative.Broadcast(Event); - Session->OnInworldTextEventDelegate.Broadcast(Event); -} - -void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldAudioDataEvent& Event) -{ - Session->OnInworldAudioEventDelegateNative.Broadcast(Event); - Session->OnInworldAudioEventDelegate.Broadcast(Event); -} - -void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldSilenceEvent& Event) -{ - Session->OnInworldSilenceEventDelegateNative.Broadcast(Event); - Session->OnInworldSilenceEventDelegate.Broadcast(Event); -} - -void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldControlEvent& Event) +void UInworldSession::OnRep_RegisteredCharacters() { - Session->OnInworldControlEventDelegateNative.Broadcast(Event); - Session->OnInworldControlEventDelegate.Broadcast(Event); -} - -void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldEmotionEvent& Event) -{ - Session->OnInworldEmotionEventDelegateNative.Broadcast(Event); - Session->OnInworldEmotionEventDelegate.Broadcast(Event); + BrainNameToCharacter = {}; + AgentIdToCharacter = {}; + BrainNameToAgentInfo = {}; + for (UInworldCharacter* Character : RegisteredCharacters) + { + const FInworldAgentInfo& AgentInfo = Character->GetAgentInfo(); + BrainNameToCharacter.Add(AgentInfo.BrainName, Character); + AgentIdToCharacter.Add(AgentInfo.AgentId, Character); + BrainNameToAgentInfo.Add(AgentInfo.BrainName, AgentInfo); + } } -void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldCustomEvent& Event) +void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldConversationUpdateEvent& Event) { - Session->OnInworldCustomEventDelegateNative.Broadcast(Event); - Session->OnInworldCustomEventDelegate.Broadcast(Event); + if (Event.EventType == EInworldConversationUpdateType::EVICTED) + { + Session->ConversationIdToAgentIds.Remove(Event.Routing.ConversationId); + } + else + { + Session->ConversationIdToAgentIds.FindOrAdd(Event.Routing.ConversationId) = Event.Agents; + } + UE_LOG(LogInworldAIIntegration, Log, TEXT("Conversation %s: %s, %d character(s):"), + Event.EventType == EInworldConversationUpdateType::STARTED ? TEXT("STARTED") : Event.EventType == EInworldConversationUpdateType::EVICTED ? TEXT("EVICTED") : TEXT("UPDATED"), + *Event.Routing.ConversationId, + Event.Agents.Num()) + for (const auto& Agent : Event.Agents) + { + UE_LOG(LogInworldAIIntegration, Log, TEXT(" Agent Id: %s."), *Agent); + } } void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldLoadCharactersEvent& Event) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index aa5f06a5..f7bd9075 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -124,16 +124,10 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem /** Send text to agent */ UFUNCTION(BlueprintCallable, Category = "Messages") void SendTextMessage(const FString& AgentId, const FString& Text); - /** Deprecated */ - UFUNCTION(BlueprintCallable, Category = "Messages", meta = (DeprecatedFunction, DeprecationMessage = "Will be removed in next release.")) - void SendTextMessageMultiAgent(const TArray& AgentIds, const FString& Text); /** Send trigger to agent */ UFUNCTION(BlueprintCallable, Category = "Messages", meta = (AutoCreateRefTerm = "Params")) void SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params); - /** Deprecated */ - UFUNCTION(BlueprintCallable, Category = "Messages", meta = (DeprecatedFunction, DeprecationMessage = "Will be removed in next release.")) - void SendTriggerMultiAgent(const TArray& AgentIds, const FString& Name, const TMap& Params); [[deprecated("UInworldApiSubsystem::SendCustomEvent is deprecated, please use UInworldApiSubsystem::SendTrigger")]] void SendCustomEvent(const FString& AgentId, const FString& Name) { SendTrigger(AgentId, Name, {}); } @@ -148,21 +142,14 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem * chunks should be ~100ms */ UFUNCTION(BlueprintCallable, Category = "Messages") - void SendAudioMessage(const TArray& AgentIds, const TArray& InputData, const TArray& OutputData); + void SendAudioMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData); /** * Start audio session with agent * call before sending audio messages - * provide Owner param to avoid multiple audio sessions */ UFUNCTION(BlueprintCallable, Category = "Audio") - bool StartAudioSession(const FString& AgentId, const AActor* Owner); - /** Deprecated */ - UFUNCTION(BlueprintCallable, Category = "Audio", meta = (DeprecatedFunction, DeprecationMessage = "Will be removed in next release.")) - bool StartAudioSessionMultiAgent(const TArray& AgentIds, const AActor* Owner); - - UFUNCTION(BlueprintCallable, Category = "Audio") - const AActor* GetAudioSessionOwner() const { return AudioSessionOwner; } + void StartAudioSession(const FString& AgentId); /** * Stop audio session with agent @@ -170,9 +157,6 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem */ UFUNCTION(BlueprintCallable, Category = "Audio") void StopAudioSession(const FString& AgentId); - /** Deprecated */ - UFUNCTION(BlueprintCallable, Category = "Audio", meta = (DeprecatedFunction, DeprecationMessage = "Will be removed in next release.")) - void StopAudioSessionMultiAgent(const TArray& AgentIds); /** Change scene */ UFUNCTION(BlueprintCallable, Category = "Messages") @@ -226,9 +210,6 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem UPROPERTY() UInworldAudioRepl* AudioRepl; - UPROPERTY() - const AActor* AudioSessionOwner = nullptr; - UPROPERTY() UInworldSession* InworldSession; diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h index 3a5f2ad9..7f5b9146 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacter.h @@ -25,6 +25,9 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject { GENERATED_BODY() public: + UInworldCharacter(); + virtual ~UInworldCharacter(); + // UObject virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; @@ -34,6 +37,14 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject // ~UObject public: + UFUNCTION() + void HandlePacket(const FInworldWrappedPacket& WrappedPacket); + + UFUNCTION(BlueprintCallable, Category="Session") + void SetSession(UInworldSession* InSession); + UFUNCTION(BlueprintPure, Category = "Session") + UInworldSession* GetSession() const { return Session; } + UFUNCTION(BlueprintCallable, Category = "Message|Text") void SendTextMessage(const FString& Text); UFUNCTION(BlueprintCallable, Category = "Message|Trigger") @@ -82,7 +93,29 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject FOnInworldCharacterTargetPlayerChanged OnTargetPlayerChangedDelegate; FOnInworldCharacterTargetPlayerChangedNative& OnTargetPlayerChanged() { return OnTargetPlayerChangedDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldTextEvent OnInworldTextEventDelegate; + FOnInworldTextEventNative& OnInworldTextEvent() { return OnInworldTextEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldAudioEvent OnInworldAudioEventDelegate; + FOnInworldAudioEventNative& OnInworldAudioEvent() { return OnInworldAudioEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldSilenceEvent OnInworldSilenceEventDelegate; + FOnInworldSilenceEventNative& OnInworldSilenceEvent() { return OnInworldSilenceEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldControlEvent OnInworldControlEventDelegate; + FOnInworldControlEventNative& OnInworldControlEvent() { return OnInworldControlEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldEmotionEvent OnInworldEmotionEventDelegate; + FOnInworldEmotionEventNative& OnInworldEmotionEvent() { return OnInworldEmotionEventDelegateNative; } + UPROPERTY(BlueprintAssignable, Category = "Event") + FOnInworldCustomEvent OnInworldCustomEventDelegate; + FOnInworldCustomEventNative& OnInworldCustomEvent() { return OnInworldCustomEventDelegateNative; } + private: + UPROPERTY(Replicated) + UInworldSession* Session; + UPROPERTY(Replicated) FInworldAgentInfo AgentInfo; FOnInworldCharacterPossessedNative OnPossessedDelegateNative; @@ -93,8 +126,38 @@ class INWORLDAIINTEGRATION_API UInworldCharacter : public UObject UPROPERTY(ReplicatedUsing=OnRep_TargetPlayer) UInworldPlayer* TargetPlayer; FOnInworldCharacterTargetPlayerChangedNative OnTargetPlayerChangedDelegateNative; -}; + FOnInworldTextEventNative OnInworldTextEventDelegateNative; + FOnInworldAudioEventNative OnInworldAudioEventDelegateNative; + FOnInworldSilenceEventNative OnInworldSilenceEventDelegateNative; + FOnInworldControlEventNative OnInworldControlEventDelegateNative; + FOnInworldEmotionEventNative OnInworldEmotionEventDelegateNative; + FOnInworldCustomEventNative OnInworldCustomEventDelegateNative; + + class FInworldCharacterPacketVisitor : public TSharedFromThis, public InworldPacketVisitor + { + public: + FInworldCharacterPacketVisitor() + : FInworldCharacterPacketVisitor(nullptr) + {} + FInworldCharacterPacketVisitor(class UInworldCharacter* InCharacter) + : Character(InCharacter) + {} + virtual ~FInworldCharacterPacketVisitor() = default; + + virtual void Visit(const FInworldTextEvent& Event) override; + virtual void Visit(const FInworldAudioDataEvent& Event) override; + virtual void Visit(const FInworldSilenceEvent& Event) override; + virtual void Visit(const FInworldControlEvent& Event) override; + virtual void Visit(const FInworldEmotionEvent& Event) override; + virtual void Visit(const FInworldCustomEvent& Event) override; + + private: + UInworldCharacter* Character; + }; + + TSharedRef PacketVisitor; +}; UINTERFACE(MinimalAPI, BlueprintType) class UInworldCharacterOwnerInterface : public UInterface @@ -107,10 +170,11 @@ class INWORLDAIINTEGRATION_API IInworldCharacterOwnerInterface GENERATED_BODY() public: - UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") - UInworldSession* GetInworldSession() const; - UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") UInworldCharacter* GetInworldCharacter() const; }; +namespace Inworld +{ + TArray CharactersToAgentIds(const TArray& InworldCharacters); +} diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index 87d9c071..7851f936 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -37,7 +37,6 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone // IInworldCharacterOwnerInterface virtual UInworldCharacter* GetInworldCharacter_Implementation() const override { return InworldCharacter; } - virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession.Get(); } // ~IInworldCharacterOwnerInterface virtual void OnRegister() override; @@ -133,12 +132,6 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UFUNCTION(BlueprintCallable, Category = "Interaction") void CancelCurrentInteraction(); - UFUNCTION(BlueprintCallable, Category = "Events") - bool Register(); - - UFUNCTION(BlueprintCallable, Category = "Events") - bool Unregister(); - UFUNCTION(BlueprintPure, Category = "Interaction") FVector GetTargetPlayerCameraLocation(); @@ -175,7 +168,6 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone FString UiName = "Character"; private: - bool ShouldHandleEvent(const FInworldRouting& Routing); UFUNCTION() void OnInworldTextEvent(const FInworldTextEvent& Event); UFUNCTION() @@ -239,12 +231,6 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UPROPERTY(ReplicatedUsing=OnRep_InworldCharacter) UInworldCharacter* InworldCharacter; - UFUNCTION() - void OnRep_InworldSession(); - - UPROPERTY(ReplicatedUsing=OnRep_InworldSession) - TWeakObjectPtr InworldSession; - #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; #endif diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index e5eed193..744e62c6 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -23,6 +23,9 @@ DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldPlayerTargetCharacterRemovedNative DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInworldPlayerTargetCharactersChanged); DECLARE_MULTICAST_DELEGATE(FOnInworldPlayerTargetCharactersChangedNative); +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInworldPlayerConversationChanged); +DECLARE_MULTICAST_DELEGATE(FOnInworldPlayerConversationChangedNative); + UCLASS(BlueprintType) class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject { @@ -37,16 +40,21 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject // ~UObject public: - UFUNCTION(BlueprintCallable, Server, Reliable, Category = "Message|Text") - void BroadcastTextMessage(const FString& Text); + UFUNCTION(BlueprintCallable, Category = "Session") + void SetSession(UInworldSession* InSession); + UFUNCTION(BlueprintPure, Category = "Session") + UInworldSession* GetSession() const { return Session; } + + UFUNCTION(BlueprintCallable, Category = "Message|Text") + void SendTextMessageToConversation(const FString& Text); UFUNCTION(BlueprintCallable, Category = "Message|Trigger") - void BroadcastTrigger(const FString& Name, const TMap& Params); + void SendTriggerToConversation(const FString& Name, const TMap& Params); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastAudioSessionStart(); + void SendAudioSessionStartToConversation(); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastAudioSessionStop(); + void SendAudioSessionStopToConversation(); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastSoundMessage(const TArray& Input, const TArray& Output); + void SendSoundMessageToConversation(const TArray& Input, const TArray& Output); public: UFUNCTION(BlueprintCallable, Category = "Player") @@ -76,13 +84,31 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject FOnInworldPlayerTargetCharactersChanged OnTargetCharactersChangedDelegate; FOnInworldPlayerTargetCharactersChangedNative& OnTargetCharactersChanged() { return OnTargetCharactersChangedDelegateNative; } + UFUNCTION(BlueprintPure, Category = "Conversation") + const FString& GetConversationId() const { return ConversationId; } + + UPROPERTY(BlueprintAssignable, Category = "Conversation") + FOnInworldPlayerConversationChanged OnConversationChangedDelegate; + FOnInworldPlayerConversationChangedNative& OnConversationChanged() { return OnConversationChangedDelegateNative; } + +private: + void UpdateConversation(); + private: + UPROPERTY(Replicated) + UInworldSession* Session; + UPROPERTY(Replicated) TArray TargetCharacters; FOnInworldPlayerTargetCharacterAddedNative OnTargetCharacterAddedDelegateNative; FOnInworldPlayerTargetCharacterRemovedNative OnTargetCharacterRemovedDelegateNative; FOnInworldPlayerTargetCharactersChangedNative OnTargetCharactersChangedDelegateNative; + + FString ConversationId; + FOnInworldPlayerConversationChangedNative OnConversationChangedDelegateNative; + + bool bHasAudioSession = false; }; UINTERFACE(MinimalAPI, BlueprintType) @@ -96,9 +122,6 @@ class INWORLDAIINTEGRATION_API IInworldPlayerOwnerInterface GENERATED_BODY() public: - UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") - UInworldSession* GetInworldSession() const; - UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Inworld") UInworldPlayer* GetInworldPlayer() const; }; \ No newline at end of file diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h index a76d5bba..ccb7df2e 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerAudioCaptureComponent.h @@ -110,9 +110,8 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct TAtomic bCapturingVoice = false; TWeakObjectPtr InworldPlayer; - FDelegateHandle OnPlayerTargetCharactersChanged; + FDelegateHandle OnPlayerConversationChanged; - TWeakObjectPtr InworldSession; FDelegateHandle OnSessionConnectionStateChanged; FDelegateHandle OnSessionLoaded; @@ -128,14 +127,6 @@ class INWORLDAIINTEGRATION_API UInworldPlayerAudioCaptureComponent : public UAct FAudioBuffer InputBuffer; FAudioBuffer OutputBuffer; - struct FPlayerAudioTargetState - { - TArray ActiveCharacters; - TArray DesiredCharacters; - bool bDirty = false; - - } PlayerAudioTargetState; - #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; #endif diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h index 4e5bf243..60d5528a 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerComponent.h @@ -37,15 +37,12 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, // IInworldPlayerInterface virtual UInworldPlayer* GetInworldPlayer_Implementation() const override { return InworldPlayer; } - virtual UInworldSession* GetInworldSession_Implementation() const override { return InworldSession.Get(); } // ~IInworldPlayerInterface virtual void OnRegister() override; virtual void OnUnregister() override; virtual void InitializeComponent() override; - - //virtual void BeginPlay() override; - virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void UninitializeComponent() override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual bool ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags) override; @@ -94,9 +91,6 @@ class INWORLDAIINTEGRATION_API UInworldPlayerComponent : public UActorComponent, UPROPERTY(Replicated) UInworldPlayer* InworldPlayer; - UPROPERTY(Replicated) - TWeakObjectPtr InworldSession; - #if defined(WITH_GAMEPLAY_DEBUGGER) && WITH_GAMEPLAY_DEBUGGER friend class FInworldGameplayDebuggerCategory; #endif diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index e4fe14cc..a4a9ee4a 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -28,6 +28,8 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldSilenceEvent, const FInwor DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldSilenceEventNative, const FInworldSilenceEvent& /*SilenceEvent*/); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldControlEvent, const FInworldControlEvent&, ControlEvent); DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldControlEventNative, const FInworldControlEvent& /*ControlEvent*/); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldConversationUpdateEvent, const FInworldConversationUpdateEvent&, ConversationUpdateEvent); +DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldConversationUpdateEventNative, const FInworldConversationUpdateEvent& /*ConversationUpdateEvent*/); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldEmotionEvent, const FInworldEmotionEvent&, EmotionEvent); DECLARE_MULTICAST_DELEGATE_OneParam(FOnInworldEmotionEventNative, const FInworldEmotionEvent& /*EmotionEvent*/); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInworldCustomEvent, const FInworldCustomEvent&, CustomEvent); @@ -41,6 +43,9 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject { GENERATED_BODY() public: + UInworldSession(); + virtual ~UInworldSession(); + // UObject virtual UWorld* GetWorld() const override { return GetTypedOuter()->GetWorld(); } virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; @@ -50,14 +55,17 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject // ~UObject public: - UInworldSession(); - virtual ~UInworldSession(); - UFUNCTION(BlueprintCallable, Category = "Client") void Init(); UFUNCTION(BlueprintCallable, Category = "Client") void Destroy(); + UFUNCTION(BlueprintPure, Category = "Client") + UInworldClient* GetClient() const { return InworldClient; } + + UFUNCTION() + void HandlePacket(const FInworldWrappedPacket& WrappedPacket); + UFUNCTION(BlueprintCallable, Category = "Register") void RegisterCharacter(UInworldCharacter* Character); UFUNCTION(BlueprintCallable, Category = "Register") @@ -66,6 +74,14 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject UFUNCTION(BlueprintPure, Category = "Register") const TArray& GetRegisteredCharacters() const { return RegisteredCharacters; } + UFUNCTION(BlueprintCallable, Category = "Register") + void RegisterPlayer(UInworldPlayer* Player); + UFUNCTION(BlueprintCallable, Category = "Register") + void UnregisterPlayer(UInworldPlayer* Player); + + UFUNCTION(BlueprintPure, Category = "Register") + const TArray& GetRegisteredPlayers() const { return RegisteredPlayers; } + UFUNCTION(BlueprintCallable, Category = "Session", meta = (AdvancedDisplay = "4", AutoCreateRefTerm = "PlayerProfile, Auth, Save, SessionToken, CapabilitySet")) void StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet); UFUNCTION(BlueprintCallable, Category = "Session") @@ -98,30 +114,32 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { InworldClient->LoadPlayerProfile(PlayerProfile); } UFUNCTION(BlueprintCallable, Category = "Message|Text") - void SendTextMessage(UInworldCharacter* Character, const FString& Message) { BroadcastTextMessage({Character}, Message); } + void SendTextMessage(UInworldCharacter* Character, const FString& Message); UFUNCTION(BlueprintCallable, Category = "Message|Text") - void BroadcastTextMessage(const TArray& Characters, const FString& Message); + void SendTextMessageToConversation(UInworldPlayer* Player, const FString& Message); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void SendSoundMessage(UInworldCharacter* Character, const TArray& InputData, const TArray& OutputData) { BroadcastSoundMessage({ Character }, InputData, OutputData); } + void SendSoundMessage(UInworldCharacter* Character, const TArray& InputData, const TArray& OutputData); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastSoundMessage(const TArray& Characters, const TArray& InputData, const TArray& OutputData); + void SendSoundMessageToConversation(UInworldPlayer* Player, const TArray& InputData, const TArray& OutputData); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void SendAudioSessionStart(UInworldCharacter* Character) { BroadcastAudioSessionStart({ Character }); } + void SendAudioSessionStart(UInworldCharacter* Character); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastAudioSessionStart(const TArray& Characters); + void SendAudioSessionStartToConversation(UInworldPlayer* Player); + UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void SendAudioSessionStop(UInworldCharacter* Character) { BroadcastAudioSessionStop({ Character }); } + void SendAudioSessionStop(UInworldCharacter* Character); UFUNCTION(BlueprintCallable, Category = "Message|Audio") - void BroadcastAudioSessionStop(const TArray& Characters); + void SendAudioSessionStopToConversation(UInworldPlayer* Player); UFUNCTION(BlueprintCallable, Category = "Message|Narration") void SendNarrationEvent(UInworldCharacter* Character, const FString& Content); UFUNCTION(BlueprintCallable, Category = "Message|Trigger") - void SendTrigger(UInworldCharacter* Character, const FString& Name, const TMap& Params) { BroadcastTrigger({ Character }, Name, Params); } + void SendTrigger(UInworldCharacter* Character, const FString& Name, const TMap& Params); UFUNCTION(BlueprintCallable, Category = "Message|Trigger") - void BroadcastTrigger(const TArray& Characters, const FString& Name, const TMap& Params); + void SendTriggerToConversation(UInworldPlayer* Player, const FString& Name, const TMap& Params); UFUNCTION(BlueprintCallable, Category = "Message|Mutation") void SendChangeSceneEvent(const FString& SceneName); @@ -129,25 +147,6 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject UFUNCTION(BlueprintCallable, Category = "Message|Mutation") void CancelResponse(UInworldCharacter* Character, const FString& InteractionId, const TArray& UtteranceIds); - UPROPERTY(BlueprintAssignable, Category = "Event") - FOnInworldTextEvent OnInworldTextEventDelegate; - FOnInworldTextEventNative& OnInworldTextEvent() { return OnInworldTextEventDelegateNative; } - UPROPERTY(BlueprintAssignable, Category = "Event") - FOnInworldAudioEvent OnInworldAudioEventDelegate; - FOnInworldAudioEventNative& OnInworldAudioEvent() { return OnInworldAudioEventDelegateNative; } - UPROPERTY(BlueprintAssignable, Category = "Event") - FOnInworldSilenceEvent OnInworldSilenceEventDelegate; - FOnInworldSilenceEventNative& OnInworldSilenceEvent() { return OnInworldSilenceEventDelegateNative; } - UPROPERTY(BlueprintAssignable, Category = "Event") - FOnInworldControlEvent OnInworldControlEventDelegate; - FOnInworldControlEventNative& OnInworldControlEvent() { return OnInworldControlEventDelegateNative; } - UPROPERTY(BlueprintAssignable, Category = "Event") - FOnInworldEmotionEvent OnInworldEmotionEventDelegate; - FOnInworldEmotionEventNative& OnInworldEmotionEvent() { return OnInworldEmotionEventDelegateNative; } - UPROPERTY(BlueprintAssignable, Category = "Event") - FOnInworldCustomEvent OnInworldCustomEventDelegate; - FOnInworldCustomEventNative& OnInworldCustomEvent() { return OnInworldCustomEventDelegateNative; } - UFUNCTION(BlueprintPure, Category = "Connection") EInworldConnectionState GetConnectionState() const { return InworldClient->GetConnectionState(); } UFUNCTION(BlueprintPure, Category = "Connection") @@ -186,11 +185,18 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject FDelegateHandle OnClientConnectionStateChangedHandle; FDelegateHandle OnClientPerceivedLatencyHandle; - UPROPERTY(Replicated) + UFUNCTION() + void OnRep_RegisteredCharacters(); + + UPROPERTY(ReplicatedUsing=OnRep_RegisteredCharacters) TArray RegisteredCharacters; + UPROPERTY(Replicated) + TArray RegisteredPlayers; + TMap BrainNameToCharacter; TMap AgentIdToCharacter; TMap BrainNameToAgentInfo; + TMap> ConversationIdToAgentIds; FOnInworldConnectionStateChangedNative OnConnectionStateChangedDelegateNative; FOnInworldSessionLoadedNative OnLoadedDelegateNative; @@ -207,12 +213,7 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject {} virtual ~FInworldSessionPacketVisitor() = default; - virtual void Visit(const FInworldTextEvent& Event) override; - virtual void Visit(const FInworldAudioDataEvent& Event) override; - virtual void Visit(const FInworldSilenceEvent& Event) override; - virtual void Visit(const FInworldControlEvent& Event) override; - virtual void Visit(const FInworldEmotionEvent& Event) override; - virtual void Visit(const FInworldCustomEvent& Event) override; + virtual void Visit(const FInworldConversationUpdateEvent& Event) override; virtual void Visit(const FInworldLoadCharactersEvent& Event) override; virtual void Visit(const FInworldChangeSceneEvent& Event) override; @@ -222,13 +223,6 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject TSharedRef PacketVisitor; - FOnInworldTextEventNative OnInworldTextEventDelegateNative; - FOnInworldAudioEventNative OnInworldAudioEventDelegateNative; - FOnInworldSilenceEventNative OnInworldSilenceEventDelegateNative; - FOnInworldControlEventNative OnInworldControlEventDelegateNative; - FOnInworldEmotionEventNative OnInworldEmotionEventDelegateNative; - FOnInworldCustomEventNative OnInworldCustomEventDelegateNative; - private: float RetryConnectionIntervalTime = 0.25f; float MaxRetryConnectionTime = 5.0f; diff --git a/InworldAI/inworld-ndk b/InworldAI/inworld-ndk index c57961c6..59785bbb 160000 --- a/InworldAI/inworld-ndk +++ b/InworldAI/inworld-ndk @@ -1 +1 @@ -Subproject commit c57961c6b435582cb3a4fb5e435f15137d34cdc9 +Subproject commit 59785bbbf6ebbafc4b99a631b23a7dbf0e7a8ec1 From 352776a17286d8e6bb990e0ac67c13034e9e4ac1 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 2 May 2024 14:57:20 -0400 Subject: [PATCH 29/45] add guard warnings to API --- .../InworldAIClient/Private/InworldClient.cpp | 90 +++++++- .../InworldAIClient/Public/InworldMacros.h | 25 ++ .../Private/InworldApi.cpp | 210 +++++++---------- .../Private/InworldCharacter.cpp | 38 +++- .../Private/InworldCharacterComponent.cpp | 50 ++++ .../Private/InworldPlayer.cpp | 31 ++- .../InworldPlayerAudioCaptureComponent.cpp | 10 +- .../Private/InworldPlayerComponent.cpp | 33 ++- .../Private/InworldSession.cpp | 215 ++++++++++++++---- .../Public/InworldCharacterComponent.h | 8 +- .../Public/InworldPlayer.h | 3 + .../Public/InworldSession.h | 25 +- 12 files changed, 534 insertions(+), 204 deletions(-) create mode 100644 InworldAI/Source/InworldAIClient/Public/InworldMacros.h diff --git a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp index b54ef82b..9ae31a2c 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp @@ -7,6 +7,7 @@ #include "InworldClient.h" #include "InworldAIClientModule.h" +#include "InworldMacros.h" #include "CoreMinimal.h" #include "GenericPlatform/GenericPlatformMisc.h" @@ -57,6 +58,9 @@ UInworldClient::FOnAudioDumperCVarChanged UInworldClient::OnAudioDumperCVarChang FAutoConsoleVariableSink UInworldClient::CVarSink(FConsoleCommandDelegate::CreateStatic(&UInworldClient::OnCVarsChanged)); #endif +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIClient, UInworldClient, Arg, Return) +#define NO_CLIENT_RETURN(Return) EMPTY_ARG_RETURN(Inworld::GetClient(), Return) + std::vector ToStd(const TArray& Array) { std::vector Vec; @@ -242,6 +246,8 @@ static void ConvertPlayerProfile(const FInworldPlayerProfile& PlayerProfile, Inw void UInworldClient::StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet) { + NO_CLIENT_RETURN(void()) + Inworld::ClientOptions Options; Options.ServerUrl = TCHAR_TO_UTF8(*(!Environment.TargetUrl.IsEmpty() ? Environment.TargetUrl : DefaultTargetUrl)); // Use first segment of scene for resource @@ -278,21 +284,29 @@ void UInworldClient::StartSession(const FString& SceneId, const FInworldPlayerPr void UInworldClient::StopSession() { + NO_CLIENT_RETURN(void()) + Inworld::GetClient()->StopClient(); } void UInworldClient::PauseSession() { + NO_CLIENT_RETURN(void()) + Inworld::GetClient()->PauseClient(); } void UInworldClient::ResumeSession() { + NO_CLIENT_RETURN(void()) + Inworld::GetClient()->ResumeClient(); } void UInworldClient::SaveSession(FOnInworldSessionSavedCallback Callback) { + NO_CLIENT_RETURN(void()) + Inworld::GetClient()->SaveSessionStateAsync([Callback](std::string Data, bool bSuccess) { FInworldSave Save; @@ -315,22 +329,32 @@ void UInworldClient::SaveSession(FOnInworldSessionSavedCallback Callback) void UInworldClient::LoadCharacters(const TArray& Ids) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(Ids, void()) + Inworld::GetClient()->LoadCharacters(ToStd(Ids)); } void UInworldClient::UnloadCharacters(const TArray& Ids) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(Ids, void()) + Inworld::GetClient()->UnloadCharacters(ToStd(Ids)); } void UInworldClient::LoadSavedState(const FInworldSave& Save) { + NO_CLIENT_RETURN(void()) + std::string Data((char*)Save.Data.GetData(), Save.Data.Num()); Inworld::GetClient()->LoadSavedState(Data); } void UInworldClient::LoadCapabilities(const FInworldCapabilitySet& CapabilitySet) { + NO_CLIENT_RETURN(void()) + Inworld::Capabilities Capabilities; ConvertCapabilities(CapabilitySet, Capabilities); Inworld::GetClient()->LoadCapabilities(Capabilities); @@ -338,6 +362,8 @@ void UInworldClient::LoadCapabilities(const FInworldCapabilitySet& CapabilitySet void UInworldClient::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { + NO_CLIENT_RETURN(void()) + Inworld::UserConfiguration UserConfig; ConvertPlayerProfile(PlayerProfile, UserConfig); Inworld::GetClient()->LoadUserConfiguration(UserConfig); @@ -345,21 +371,28 @@ void UInworldClient::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfil FString UInworldClient::UpdateConversation(const FString& ConversationId, const TArray& AgentIds, bool bIncludePlayer) { + NO_CLIENT_RETURN({}) + if (AgentIds.Num() == 0) { return {}; } + auto Packet = Inworld::GetClient()->UpdateConversation(ToStd(AgentIds), TCHAR_TO_UTF8(*ConversationId), bIncludePlayer); return UTF8_TO_TCHAR(Packet->_Routing._ConversationId.c_str()); } EInworldConnectionState UInworldClient::GetConnectionState() const { - return Inworld::GetClient() ? static_cast(Inworld::GetClient()->GetConnectionState()) : EInworldConnectionState::Disconnected; + NO_CLIENT_RETURN(EInworldConnectionState::Idle) + + return static_cast(Inworld::GetClient()->GetConnectionState()); } void UInworldClient::GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const { + NO_CLIENT_RETURN(void()) + std::string OutError; Inworld::GetClient()->GetConnectionError(OutError, OutErrorCode); OutErrorMessage = UTF8_TO_TCHAR(OutError.c_str()); @@ -367,11 +400,17 @@ void UInworldClient::GetConnectionError(FString& OutErrorMessage, int32& OutErro FString UInworldClient::GetSessionId() const { + NO_CLIENT_RETURN({}) + return UTF8_TO_TCHAR(Inworld::GetClient()->GetSessionInfo().SessionId.c_str()); } FInworldWrappedPacket UInworldClient::SendTextMessage(const FString& AgentId, const FString& Text) { + NO_CLIENT_RETURN({}) + EMPTY_ARG_RETURN(AgentId, {}) + EMPTY_ARG_RETURN(Text, {}) + auto Packet = Inworld::GetClient()->SendTextMessage(TCHAR_TO_UTF8(*AgentId), TCHAR_TO_UTF8(*Text)); InworldPacketTranslator PacketTranslator; Packet->Accept(PacketTranslator); @@ -380,6 +419,10 @@ FInworldWrappedPacket UInworldClient::SendTextMessage(const FString& AgentId, co FInworldWrappedPacket UInworldClient::SendTextMessageToConversation(const FString& ConversationId, const FString& Text) { + NO_CLIENT_RETURN({}) + EMPTY_ARG_RETURN(ConversationId, {}) + EMPTY_ARG_RETURN(Text, {}) + auto Packet = Inworld::GetClient()->SendTextMessageToConversation(TCHAR_TO_UTF8(*ConversationId), TCHAR_TO_UTF8(*Text)); InworldPacketTranslator PacketTranslator; Packet->Accept(PacketTranslator); @@ -388,6 +431,10 @@ FInworldWrappedPacket UInworldClient::SendTextMessageToConversation(const FStrin void UInworldClient::SendSoundMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(InputData, void()) + if (OutputData.Num() > 0) { std::string inputdata((char*)InputData.GetData(), InputData.Num()); @@ -403,6 +450,10 @@ void UInworldClient::SendSoundMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + EMPTY_ARG_RETURN(InputData, void()) + if (OutputData.Num() == 0) { std::string inputdata((char*)InputData.GetData(), InputData.Num()); @@ -418,46 +469,78 @@ void UInworldClient::SendSoundMessageToConversation(const FString& ConversationI void UInworldClient::SendAudioSessionStart(const FString& AgentId) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + Inworld::GetClient()->StartAudioSession(TCHAR_TO_UTF8(*AgentId)); } void UInworldClient::SendAudioSessionStartToConversation(const FString& ConversationId) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + Inworld::GetClient()->StartAudioSessionInConversation(TCHAR_TO_UTF8(*ConversationId)); } void UInworldClient::SendAudioSessionStop(const FString& AgentId) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + Inworld::GetClient()->StopAudioSession(TCHAR_TO_UTF8(*AgentId)); } void UInworldClient::SendAudioSessionStopToConversation(const FString& ConversationId) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + Inworld::GetClient()->StopAudioSessionInConversation(TCHAR_TO_UTF8(*ConversationId)); } void UInworldClient::SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(Name, void()) + Inworld::GetClient()->SendCustomEvent(TCHAR_TO_UTF8(*AgentId), TCHAR_TO_UTF8(*Name), ToStd(Params)); } void UInworldClient::SendTriggerToConversation(const FString& ConversationId, const FString& Name, const TMap& Params) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + EMPTY_ARG_RETURN(Name, void()) + Inworld::GetClient()->SendCustomEventToConversation(TCHAR_TO_UTF8(*ConversationId), TCHAR_TO_UTF8(*Name), ToStd(Params)); } void UInworldClient::SendChangeSceneEvent(const FString& SceneName) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(SceneName, void()) + Inworld::GetClient()->LoadScene(TCHAR_TO_UTF8(*SceneName)); } void UInworldClient::SendNarrationEvent(const FString& AgentId, const FString& Content) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(Content, void()) + Inworld::GetClient()->SendNarrationEvent(TCHAR_TO_UTF8(*AgentId), TCHAR_TO_UTF8(*Content)); } void UInworldClient::CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(InteractionId, void()) + EMPTY_ARG_RETURN(UtteranceIds, void()) + std::vector utteranceIds; utteranceIds.reserve(UtteranceIds.Num()); for (auto& Id : UtteranceIds) @@ -484,4 +567,7 @@ void UInworldClient::OnCVarsChanged() OnAudioDumperCVarChanged.Broadcast(GEnableSoundDump, GSoundDumpPath); } } -#endif \ No newline at end of file +#endif + +#undef EMPTY_ARG_RETURN +#undef NO_CLIENT_RETURN diff --git a/InworldAI/Source/InworldAIClient/Public/InworldMacros.h b/InworldAI/Source/InworldAIClient/Public/InworldMacros.h new file mode 100644 index 00000000..97e26303 --- /dev/null +++ b/InworldAI/Source/InworldAIClient/Public/InworldMacros.h @@ -0,0 +1,25 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + +#pragma once + + +#include "CoreMinimal.h" + +namespace Inworld +{ + template + bool CheckEmpty(const T& Value) { return !Value; } + template<> + bool CheckEmpty(const FString& Value) { return Value.IsEmpty(); } + template + bool CheckEmpty(const TArray& Value) { return Value.Num() == 0; } +} + +#ifndef INWORLD_WARN_AND_RETURN_EMPTY +#define INWORLD_WARN_AND_RETURN_EMPTY(LogCategory, Class, Argument, Return) if (Inworld::CheckEmpty(Argument)) { UE_LOG(LogCategory, Warning, TEXT("%s::%s skipped: %s is empty."), TEXT(#Class), *FString(__func__), TEXT(#Argument)); return Return; } +#endif diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index ba1600a5..0a676b90 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -10,6 +10,7 @@ #include "InworldPackets.h" #include "InworldCharacter.h" #include "InworldSessionComponent.h" +#include "InworldMacros.h" #include #include #include "TimerManager.h" @@ -22,8 +23,14 @@ TEXT("Inworld.Debug.LogAllPackets"), false, TEXT("Enable/Disable logging all packets going from server") ); +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldApiSubsystem, Arg, Return) +#define NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(InworldSession, Return) +#define NO_CLIENT_RETURN(Return) NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(InworldSession->GetClient(), Return) + UInworldApiSubsystem::UInworldApiSubsystem() : Super() + , AudioRepl(nullptr) + , InworldSession(nullptr) {} void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) @@ -49,27 +56,9 @@ void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } - - if (!ensure(GetWorld()->GetNetMode() < NM_Client)) - { - UE_LOG(LogInworldAIIntegration, Error, TEXT("UInworldApiSubsystem::StartSession shouldn't be called on client")); - return; - } - - if (ApiKey.IsEmpty()) - { - UE_LOG(LogInworldAIIntegration, Error, TEXT("Can't Start Session, ApiKey is empty")); - return; - } - if (ApiSecret.IsEmpty()) - { - UE_LOG(LogInworldAIIntegration, Error, TEXT("Can't Start Session, ApiSecret is empty")); - return; - } + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(ApiKey, void()) + EMPTY_ARG_RETURN(ApiSecret, void()) FInworldPlayerProfile PlayerProfile; PlayerProfile.Name = PlayerName; @@ -87,21 +76,12 @@ void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& Environment.AuthUrl = AuthUrlOverride; Environment.TargetUrl = TargetUrlOverride; - InworldSession->InworldClient->StartSession(SceneName, PlayerProfile, Auth, FInworldSave(), SessionToken, {}); + InworldSession->GetClient()->StartSession(SceneName, PlayerProfile, Auth, FInworldSave(), SessionToken, {}); } void UInworldApiSubsystem::StartSession_V2(const FString& SceneName, const FInworldPlayerProfile& PlayerProfile, const FInworldCapabilitySet& Capabilities, const FInworldAuth& Auth, const FInworldSessionToken& SessionToken, const FInworldEnvironment& Environment, FString UniqueUserIdOverride, FInworldSave SavedSessionState) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } - - if (!ensure(GetWorld()->GetNetMode() < NM_Client)) - { - UE_LOG(LogInworldAIIntegration, Error, TEXT("UInworldApiSubsystem::StartSession shouldn't be called on client")); - return; - } + NO_CLIENT_RETURN(void()) const bool bValidAuth = !Auth.Base64Signature.IsEmpty() || (!Auth.ApiKey.IsEmpty() && !Auth.ApiSecret.IsEmpty()); if (!bValidAuth) @@ -114,75 +94,55 @@ void UInworldApiSubsystem::StartSession_V2(const FString& SceneName, const FInwo UE_LOG(LogInworldAIIntegration, Warning, TEXT("Start Session, please provide unique PlayerProfile.ProjectName for possible troubleshooting")); } - InworldSession->InworldClient->StartSession(SceneName, PlayerProfile, Auth, SavedSessionState, SessionToken, Capabilities); + InworldSession->GetClient()->StartSession(SceneName, PlayerProfile, Auth, SavedSessionState, SessionToken, Capabilities); } void UInworldApiSubsystem::PauseSession() { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->PauseSession(); + InworldSession->GetClient()->PauseSession(); } void UInworldApiSubsystem::ResumeSession() { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->PauseSession(); + InworldSession->GetClient()->ResumeSession(); } void UInworldApiSubsystem::StopSession() { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->StopSession(); + InworldSession->GetClient()->StopSession(); } void UInworldApiSubsystem::SaveSession(FOnInworldSessionSavedCallback Callback) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->SaveSession(Callback); + InworldSession->GetClient()->SaveSession(Callback); } void UInworldApiSubsystem::SetResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->OnPerceivedLatencyDelegate.Add(Delegate); + InworldSession->GetClient()->OnPerceivedLatencyDelegate.Add(Delegate); } void UInworldApiSubsystem::ClearResponseLatencyTrackerDelegate(const FOnInworldPerceivedLatencyCallback& Delegate) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->OnPerceivedLatencyDelegate.Remove(Delegate); + InworldSession->GetClient()->OnPerceivedLatencyDelegate.Remove(Delegate); } void UInworldApiSubsystem::LoadCharacters(const TArray& Names) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(Names, void()) TArray Characters; for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) @@ -197,10 +157,8 @@ void UInworldApiSubsystem::LoadCharacters(const TArray& Names) void UInworldApiSubsystem::UnloadCharacters(const TArray& Names) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(Names, void()) TArray Characters; for (UInworldCharacter* Character : InworldSession->GetRegisteredCharacters()) @@ -215,122 +173,106 @@ void UInworldApiSubsystem::UnloadCharacters(const TArray& Names) void UInworldApiSubsystem::LoadSavedState(const FInworldSave& SavedState) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->LoadSavedState(SavedState); + InworldSession->GetClient()->LoadSavedState(SavedState); } void UInworldApiSubsystem::LoadCapabilities(const FInworldCapabilitySet& Capabilities) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->LoadCapabilities(Capabilities); + InworldSession->GetClient()->LoadCapabilities(Capabilities); } void UInworldApiSubsystem::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->LoadPlayerProfile(PlayerProfile); + InworldSession->GetClient()->LoadPlayerProfile(PlayerProfile); } void UInworldApiSubsystem::SendTextMessage(const FString& AgentId, const FString& Text) { - InworldSession->InworldClient->SendTextMessage(AgentId, Text); + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(Text, void()) + + InworldSession->GetClient()->SendTextMessage(AgentId, Text); } void UInworldApiSubsystem::SendTrigger(const FString& AgentId, const FString& Name, const TMap& Params) { - InworldSession->InworldClient->SendTrigger(AgentId, Name, Params); + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(Name, void()) + + InworldSession->GetClient()->SendTrigger(AgentId, Name, Params); } void UInworldApiSubsystem::SendNarrationEvent(const FString& AgentId, const FString& Content) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(Content, void()) - if (!ensureMsgf(!AgentId.IsEmpty(), TEXT("AgentId must be valid!"))) - { - return; - } - - InworldSession->InworldClient->SendNarrationEvent(AgentId, Content); + InworldSession->GetClient()->SendNarrationEvent(AgentId, Content); } void UInworldApiSubsystem::SendAudioMessage(const FString& AgentId, const TArray& InputData, const TArray& OutputData) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(InputData, void()) - InworldSession->InworldClient->SendSoundMessage(AgentId, InputData, OutputData); + InworldSession->GetClient()->SendSoundMessage(AgentId, InputData, OutputData); } void UInworldApiSubsystem::StartAudioSession(const FString& AgentId) { - InworldSession->InworldClient->SendAudioSessionStart(AgentId); + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + + InworldSession->GetClient()->SendAudioSessionStart(AgentId); } void UInworldApiSubsystem::StopAudioSession(const FString& AgentId) { - InworldSession->InworldClient->SendAudioSessionStop(AgentId); + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + + InworldSession->GetClient()->SendAudioSessionStop(AgentId); } void UInworldApiSubsystem::ChangeScene(const FString& SceneId) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(SceneId, void()) - InworldSession->InworldClient->SendChangeSceneEvent(SceneId); + InworldSession->GetClient()->SendChangeSceneEvent(SceneId); } EInworldConnectionState UInworldApiSubsystem::GetConnectionState() const { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return EInworldConnectionState::Idle; - } + NO_CLIENT_RETURN(EInworldConnectionState::Idle) return InworldSession->GetConnectionState(); } void UInworldApiSubsystem::GetConnectionError(FString& Message, int32& Code) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) - InworldSession->InworldClient->GetConnectionError(Message, Code); + InworldSession->GetConnectionError(Message, Code); } void UInworldApiSubsystem::CancelResponse(const FString& AgentId, const FString& InteractionId, const TArray& UtteranceIds) { - if (!ensureMsgf(InworldSession && InworldSession->InworldClient, TEXT("Inworld Session and Inworld Client must be valid!"))) - { - return; - } - - if (!ensureMsgf(!AgentId.IsEmpty(), TEXT("AgentId must be valid!"))) - { - return; - } + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(AgentId, void()) + EMPTY_ARG_RETURN(InteractionId, void()) + EMPTY_ARG_RETURN(UtteranceIds, void()) - InworldSession->InworldClient->CancelResponse(AgentId, InteractionId, UtteranceIds); + InworldSession->GetClient()->CancelResponse(AgentId, InteractionId, UtteranceIds); } void UInworldApiSubsystem::StartAudioReplication() @@ -387,9 +329,11 @@ void UInworldApiSubsystem::ReplicateAudioEventFromServer(FInworldAudioDataEvent& void UInworldApiSubsystem::HandleAudioEventOnClient(TSharedPtr Packet) { - if (!ensureMsgf(InworldSession, TEXT("Inworld Session must be valid!"))) - { - return; - } + NO_SESSION_RETURN(void()) + InworldSession->HandlePacket(FInworldWrappedPacket(Packet)); } + +#undef EMPTY_ARG_RETURN +#undef NO_SESSION_RETURN +#undef NO_CLIENT_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index d5f19756..3b4d0d81 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -9,6 +9,7 @@ #include "InworldCharacter.h" #include "InworldSession.h" #include "InworldPlayer.h" +#include "InworldMacros.h" #include "Engine/BlueprintGeneratedClass.h" #include "Engine/NetDriver.h" @@ -16,6 +17,9 @@ #include "Net/UnrealNetwork.h" +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldCharacter, Arg, Return) +#define NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(Session, Return) + UInworldCharacter::UInworldCharacter() : Super() , PacketVisitor(MakeShared(this)) @@ -75,14 +79,14 @@ void UInworldCharacter::SetSession(UInworldSession* InSession) return; } - if (Session) + if (Session && !AgentInfo.BrainName.IsEmpty()) { Session->UnregisterCharacter(this); } Session = InSession; - if (Session) + if (Session && !AgentInfo.BrainName.IsEmpty()) { Session->RegisterCharacter(this); } @@ -90,36 +94,63 @@ void UInworldCharacter::SetSession(UInworldSession* InSession) void UInworldCharacter::SendTextMessage(const FString& Text) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(AgentInfo.AgentId, void()) + EMPTY_ARG_RETURN(Text, void()) + Session->SendTextMessage(this, Text); } void UInworldCharacter::SendTrigger(const FString& Name, const TMap& Params) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(AgentInfo.AgentId, void()) + EMPTY_ARG_RETURN(Name, void()) + Session->SendTrigger(this, Name, Params); } void UInworldCharacter::SendNarrationEvent(const FString& Content) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(AgentInfo.AgentId, void()) + EMPTY_ARG_RETURN(Content, void()) + Session->SendNarrationEvent(this, Content); } void UInworldCharacter::SendAudioSessionStart() { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(AgentInfo.AgentId, void()) + Session->SendAudioSessionStart(this); } void UInworldCharacter::SendAudioSessionStop() { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(AgentInfo.AgentId, void()) + Session->SendAudioSessionStop(this); } void UInworldCharacter::SendSoundMessage(const TArray& InputData, const TArray& OutputData) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(AgentInfo.AgentId, void()) + EMPTY_ARG_RETURN(InputData, void()) + Session->SendSoundMessage(this, InputData, OutputData); } void UInworldCharacter::CancelResponse(const FString& InteractionId, const TArray& UtteranceIds) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(AgentInfo.AgentId, void()) + EMPTY_ARG_RETURN(InteractionId, void()) + EMPTY_ARG_RETURN(UtteranceIds, void()) + Session->CancelResponse(this, InteractionId, UtteranceIds); } @@ -262,3 +293,6 @@ TArray Inworld::CharactersToAgentIds(const TArray& } return AgentIds; } + +#undef EMPTY_ARG_RETURN +#undef NO_SESSION_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 2425429c..328ffd87 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -7,6 +7,7 @@ #include "InworldCharacterComponent.h" #include "InworldApi.h" +#include "InworldMacros.h" #include "InworldAIIntegrationModule.h" #include "Engine/EngineBaseTypes.h" #include "InworldPlayerComponent.h" @@ -17,6 +18,9 @@ #include #include +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldCharacterComponent, Arg, Return) +#define NO_CHARACTER_RETURN(Return) EMPTY_ARG_RETURN(InworldCharacter, Return) + UInworldCharacterComponent::UInworldCharacterComponent() : Super() , MessageQueue(MakeShared(this)) @@ -194,9 +198,32 @@ bool UInworldCharacterComponent::ReplicateSubobjects(UActorChannel* Channel, FOu void UInworldCharacterComponent::SetBrainName(const FString& Name) { + NO_CHARACTER_RETURN(void()) + InworldCharacter->SetBrainName(Name); } +FString UInworldCharacterComponent::GetBrainName() const +{ + NO_CHARACTER_RETURN({}) + + return InworldCharacter->GetAgentInfo().BrainName; +} + +FString UInworldCharacterComponent::GetAgentId() const +{ + NO_CHARACTER_RETURN({}) + + return InworldCharacter->GetAgentInfo().AgentId; +} + +FString UInworldCharacterComponent::GetGivenName() const +{ + NO_CHARACTER_RETURN({}) + + return InworldCharacter->GetAgentInfo().GivenName; +} + UInworldCharacterPlayback* UInworldCharacterComponent::GetPlayback(TSubclassOf Class) const { for (auto* Pb : Playbacks) @@ -209,8 +236,15 @@ UInworldCharacterPlayback* UInworldCharacterComponent::GetPlayback(TSubclassOfGetTargetPlayer() != nullptr; +} + void UInworldCharacterComponent::CancelCurrentInteraction() { + NO_CHARACTER_RETURN(void()) + TSharedPtr CurrentMessage = GetCurrentMessage(); if (!ensure(CurrentMessage.IsValid())) { @@ -227,26 +261,39 @@ void UInworldCharacterComponent::CancelCurrentInteraction() void UInworldCharacterComponent::SendTextMessage(const FString& Text) const { + NO_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(Text, void()) + InworldCharacter->SendTextMessage(Text); } void UInworldCharacterComponent::SendTrigger(const FString& Name, const TMap& Params) const { + NO_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(Name, void()) + InworldCharacter->SendTrigger(Name, Params); } void UInworldCharacterComponent::SendNarrationEvent(const FString& Content) { + NO_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(Content, void()) + InworldCharacter->SendNarrationEvent(Content); } void UInworldCharacterComponent::StartAudioSession() { + NO_CHARACTER_RETURN(void()) + InworldCharacter->SendAudioSessionStart(); } void UInworldCharacterComponent::StopAudioSession() { + NO_CHARACTER_RETURN(void()) + InworldCharacter->SendAudioSessionStop(); } @@ -529,3 +576,6 @@ void UInworldCharacterComponent::OnRep_InworldCharacter() InworldCharacter->OnInworldCustomEvent().AddUObject(this, &UInworldCharacterComponent::OnInworldCustomEvent); } } + +#undef EMPTY_ARG_RETURN +#undef NO_CHARACTER_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index e7c9e881..f7d1a66f 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -9,6 +9,7 @@ #include "InworldPlayer.h" #include "InworldCharacter.h" #include "InworldSession.h" +#include "InworldMacros.h" #include "Engine/BlueprintGeneratedClass.h" #include "Engine/NetDriver.h" @@ -16,6 +17,9 @@ #include "Net/UnrealNetwork.h" +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldPlayer, Arg, Return) +#define NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(Session, Return) + void UInworldPlayer::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); @@ -72,17 +76,28 @@ void UInworldPlayer::SetSession(UInworldSession* InSession) void UInworldPlayer::SendTextMessageToConversation(const FString& Text) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + EMPTY_ARG_RETURN(Text, void()) + Session->SendTextMessageToConversation(this, Text); } void UInworldPlayer::SendTriggerToConversation(const FString& Name, const TMap& Params) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + EMPTY_ARG_RETURN(Name, void()) + Session->SendTriggerToConversation(this, Name, Params); } void UInworldPlayer::SendAudioSessionStartToConversation() { - if (ConversationId.IsEmpty() || bHasAudioSession) + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + + if (bHasAudioSession) { return; } @@ -92,7 +107,10 @@ void UInworldPlayer::SendAudioSessionStartToConversation() void UInworldPlayer::SendAudioSessionStopToConversation() { - if (ConversationId.IsEmpty() || !bHasAudioSession) + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + + if (!bHasAudioSession) { return; } @@ -102,6 +120,10 @@ void UInworldPlayer::SendAudioSessionStopToConversation() void UInworldPlayer::SendSoundMessageToConversation(const TArray& Input, const TArray& Output) { + NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(ConversationId, void()) + EMPTY_ARG_RETURN(Input, void()) + if (!bHasAudioSession) { return; @@ -198,9 +220,12 @@ void UInworldPlayer::UpdateConversation() OnConversationChangedDelegateNative.Broadcast(); OnConversationChangedDelegate.Broadcast(); - if (bHadAudioSession) + if (bHadAudioSession && !ConversationId.IsEmpty()) { SendAudioSessionStartToConversation(); } } } + +#undef EMPTY_ARG_RETURN +#undef NO_SESSION_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp index 5ea186fb..1a5ec39b 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerAudioCaptureComponent.cpp @@ -308,11 +308,17 @@ void UInworldPlayerAudioCaptureComponent::EvaluateVoiceCapture() { if (bShouldCaptureVoice) { - InworldPlayer->SendAudioSessionStartToConversation(); + if (!InworldPlayer->HasAudioSession()) + { + InworldPlayer->SendAudioSessionStartToConversation(); + } } else { - InworldPlayer->SendAudioSessionStopToConversation(); + if (InworldPlayer->HasAudioSession()) + { + InworldPlayer->SendAudioSessionStopToConversation(); + } } bServerCapturingVoice = bShouldCaptureVoice; diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index f036aa25..f3af8a25 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -7,11 +7,15 @@ #include "InworldPlayerComponent.h" #include "InworldApi.h" +#include "InworldMacros.h" #include "InworldCharacterComponent.h" #include #include +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldPlayerComponent, Arg, Return) +#define NO_PLAYER_RETURN(Return) EMPTY_ARG_RETURN(InworldPlayer, Return) + UInworldPlayerComponent::UInworldPlayerComponent() : Super() { @@ -122,48 +126,69 @@ TArray UInworldPlayerComponent::GetTargetInworldCha void UInworldPlayerComponent::ContinueMultiAgentConversation() { + NO_PLAYER_RETURN(void()) + InworldPlayer->SendTriggerToConversation(TEXT("inworld.conversation.next_turn"), {}); } void UInworldPlayerComponent::SetTargetInworldCharacter(UInworldCharacterComponent* Character) { + NO_PLAYER_RETURN(void()) + InworldPlayer->AddTargetCharacter(IInworldCharacterOwnerInterface::Execute_GetInworldCharacter(Character)); } void UInworldPlayerComponent::ClearTargetInworldCharacter(UInworldCharacterComponent* Character) { + NO_PLAYER_RETURN(void()) + InworldPlayer->RemoveTargetCharacter(IInworldCharacterOwnerInterface::Execute_GetInworldCharacter(Character)); } void UInworldPlayerComponent::ClearAllTargetInworldCharacters() { + NO_PLAYER_RETURN(void()) + InworldPlayer->ClearAllTargetCharacters(); } void UInworldPlayerComponent::SendTextMessageToTarget(const FString& Message) { - if (!Message.IsEmpty()) - { - InworldPlayer->SendTextMessageToConversation(Message); - } + NO_PLAYER_RETURN(void()) + EMPTY_ARG_RETURN(Message, void()) + + InworldPlayer->SendTextMessageToConversation(Message); } void UInworldPlayerComponent::SendTriggerToTarget(const FString& Name, const TMap& Params) { + NO_PLAYER_RETURN(void()) + EMPTY_ARG_RETURN(Name, void()) + InworldPlayer->SendTriggerToConversation(Name, Params); } void UInworldPlayerComponent::StartAudioSessionWithTarget() { + NO_PLAYER_RETURN(void()) + InworldPlayer->SendAudioSessionStartToConversation(); } void UInworldPlayerComponent::StopAudioSessionWithTarget() { + NO_PLAYER_RETURN(void()) + InworldPlayer->SendAudioSessionStopToConversation(); } void UInworldPlayerComponent::SendAudioMessageToTarget(const TArray& InputData, const TArray& OutputData) { + NO_PLAYER_RETURN(void()) + EMPTY_ARG_RETURN(InputData, void()) + InworldPlayer->SendSoundMessageToConversation(InputData, OutputData); } + +#undef EMPTY_ARG_RETURN +#undef NO_PLAYER_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index ab925da8..287f3fe4 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -10,6 +10,7 @@ #include "InworldCharacter.h" #include "InworldPlayer.h" #include "InworldClient.h" +#include "InworldMacros.h" #include "InworldAIIntegrationModule.h" @@ -19,8 +20,13 @@ #include "Net/UnrealNetwork.h" +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldSession, Arg, Return) +#define NO_CLIENT_RETURN(Return) EMPTY_ARG_RETURN(Client, Return) +#define INVALID_CHARACTER_RETURN(Return) EMPTY_ARG_RETURN(Character, Return) EMPTY_ARG_RETURN(Character->GetAgentInfo().AgentId, Return) +#define INVALID_PLAYER_RETURN(Return) EMPTY_ARG_RETURN(Player, Return) EMPTY_ARG_RETURN(Player->GetConversationId(), Return) + UInworldSession::UInworldSession() - : InworldClient(nullptr) + : Client(nullptr) , bIsLoaded(false) , PacketVisitor(MakeShared(this)) {} @@ -39,6 +45,7 @@ void UInworldSession::GetLifetimeReplicatedProps(TArray& OutL DOREPLIFETIME(UInworldSession, bIsLoaded); DOREPLIFETIME(UInworldSession, RegisteredCharacters); + DOREPLIFETIME(UInworldSession, RegisteredPlayers); } int32 UInworldSession::GetFunctionCallspace(UFunction* Function, FFrame* Stack) @@ -64,9 +71,9 @@ bool UInworldSession::CallRemoteFunction(UFunction* Function, void* Parms, FOutP void UInworldSession::Init() { - InworldClient = NewObject(this); - OnClientPacketReceivedHandle = InworldClient->OnPacketReceived().AddUObject(this, &UInworldSession::HandlePacket); - OnClientConnectionStateChangedHandle = InworldClient->OnConnectionStateChanged().AddLambda( + Client = NewObject(this); + OnClientPacketReceivedHandle = Client->OnPacketReceived().AddUObject(this, &UInworldSession::HandlePacket); + OnClientConnectionStateChangedHandle = Client->OnConnectionStateChanged().AddLambda( [this](EInworldConnectionState ConnectionState) -> void { OnConnectionStateChangedDelegateNative.Broadcast(ConnectionState); @@ -96,7 +103,7 @@ void UInworldSession::Init() } } ); - OnClientPerceivedLatencyHandle = InworldClient->OnPerceivedLatency().AddLambda( + OnClientPerceivedLatencyHandle = Client->OnPerceivedLatency().AddLambda( [this](const FString& InteractionId, int32 LatencyMs) -> void { OnPerceivedLatencyDelegateNative.Broadcast(InteractionId, LatencyMs); @@ -112,20 +119,20 @@ void UInworldSession::Destroy() { UnregisterCharacter(RegisteredCharacter); } - if (IsValid(InworldClient)) + if (IsValid(Client)) { #if ENGINE_MAJOR_VERSION == 5 - InworldClient->MarkAsGarbage(); + Client->MarkAsGarbage(); #endif #if ENGINE_MAJOR_VERSION == 4 - InworldClient->MarkPendingKill(); + Client->MarkPendingKill(); #endif - InworldClient->OnPacketReceived().Remove(OnClientPacketReceivedHandle); - InworldClient->OnConnectionStateChanged().Remove(OnClientConnectionStateChangedHandle); - InworldClient->OnPerceivedLatency().Remove(OnClientPerceivedLatencyHandle); + Client->OnPacketReceived().Remove(OnClientPacketReceivedHandle); + Client->OnConnectionStateChanged().Remove(OnClientConnectionStateChangedHandle); + Client->OnPerceivedLatency().Remove(OnClientPerceivedLatencyHandle); } - InworldClient = nullptr; + Client = nullptr; } void UInworldSession::HandlePacket(const FInworldWrappedPacket& WrappedPacket) @@ -173,12 +180,11 @@ void UInworldSession::HandlePacket(const FInworldWrappedPacket& WrappedPacket) void UInworldSession::RegisterCharacter(UInworldCharacter* Character) { + EMPTY_ARG_RETURN(Character, void()) + const FString& BrainName = Character->GetAgentInfo().BrainName; - if (BrainName.IsEmpty()) - { - return; - } + EMPTY_ARG_RETURN(BrainName, void()) if (!ensureMsgf(!BrainNameToCharacter.Contains(BrainName), TEXT("UInworldSession::RegisterInworldCharacter: Character already registered for Brain: %s!"), *BrainName)) { @@ -198,19 +204,18 @@ void UInworldSession::RegisterCharacter(UInworldCharacter* Character) } else { - InworldClient->LoadCharacter(BrainName); + Client->LoadCharacter(BrainName); } } } void UInworldSession::UnregisterCharacter(UInworldCharacter* Character) { + EMPTY_ARG_RETURN(Character, void()) + const FString& BrainName = Character->GetAgentInfo().BrainName; - if (BrainName.IsEmpty()) - { - return; - } + EMPTY_ARG_RETURN(BrainName, void()) if (!ensureMsgf(BrainNameToCharacter.Contains(BrainName) && BrainNameToCharacter[BrainName] == Character, TEXT("UInworldSession::UnregisterInworldCharacter: Component mismatch for Brain: %s!"), *BrainName)) { @@ -220,44 +225,111 @@ void UInworldSession::UnregisterCharacter(UInworldCharacter* Character) AgentIdToCharacter.Remove(Character->GetAgentInfo().AgentId); BrainNameToCharacter.Remove(BrainName); RegisteredCharacters.Remove(Character); - InworldClient->UnloadCharacter(BrainName); + Client->UnloadCharacter(BrainName); Character->Unpossess(); } void UInworldSession::RegisterPlayer(UInworldPlayer* Player) { + EMPTY_ARG_RETURN(Player, void()) + RegisteredPlayers.Add(Player); } void UInworldSession::UnregisterPlayer(UInworldPlayer* Player) { + EMPTY_ARG_RETURN(Player, void()) + RegisteredPlayers.Remove(Player); } void UInworldSession::StartSession(const FString& SceneId, const FInworldPlayerProfile& PlayerProfile, const FInworldAuth& Auth, const FInworldSave& Save, const FInworldSessionToken& SessionToken, const FInworldCapabilitySet& CapabilitySet) { - InworldClient->StartSession(SceneId, PlayerProfile, Auth, Save, SessionToken, CapabilitySet); + NO_CLIENT_RETURN(void()) + + Client->StartSession(SceneId, PlayerProfile, Auth, Save, SessionToken, CapabilitySet); } void UInworldSession::StopSession() { UnpossessAgents(); - InworldClient->StopSession(); + NO_CLIENT_RETURN(void()) + + Client->StopSession(); +} + +void UInworldSession::PauseSession() +{ + NO_CLIENT_RETURN(void()) + + Client->PauseSession(); +} + +void UInworldSession::ResumeSession() +{ + NO_CLIENT_RETURN(void()) + + Client->ResumeSession(); +} + +FString UInworldSession::GetSessionId() const +{ + NO_CLIENT_RETURN({}) + + return Client->GetSessionId(); +} + +void UInworldSession::SaveSession(FOnInworldSessionSavedCallback Callback) +{ + NO_CLIENT_RETURN(void()) + + Client->SaveSession(Callback); } void UInworldSession::LoadCharacters(const TArray& Characters) { - InworldClient->LoadCharacters(Inworld::CharactersToAgentIds(Characters)); + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(Characters, void()) + + Client->LoadCharacters(Inworld::CharactersToAgentIds(Characters)); } void UInworldSession::UnloadCharacters(const TArray& Characters) { - InworldClient->UnloadCharacters(Inworld::CharactersToAgentIds(Characters)); + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(Characters, void()) + + Client->UnloadCharacters(Inworld::CharactersToAgentIds(Characters)); +} + +void UInworldSession::LoadSavedState(const FInworldSave& Save) +{ + NO_CLIENT_RETURN(void()) + + Client->LoadSavedState(Save); +} + +void UInworldSession::LoadCapabilities(const FInworldCapabilitySet& CapabilitySet) +{ + NO_CLIENT_RETURN(void()) + + Client->LoadCapabilities(CapabilitySet); +} + +void UInworldSession::LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) +{ + NO_CLIENT_RETURN(void()) + + Client->LoadPlayerProfile(PlayerProfile); } void UInworldSession::SendTextMessage(UInworldCharacter* Character, const FString& Message) { - auto Packet = InworldClient->SendTextMessage(Character->GetAgentInfo().AgentId, Message).Packet; + NO_CLIENT_RETURN(void()) + INVALID_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(Message, void()) + + auto Packet = Client->SendTextMessage(Character->GetAgentInfo().AgentId, Message).Packet; if (Packet.IsValid()) { Packet->Accept(*PacketVisitor); @@ -266,7 +338,11 @@ void UInworldSession::SendTextMessage(UInworldCharacter* Character, const FStrin void UInworldSession::SendTextMessageToConversation(UInworldPlayer* Player, const FString& Message) { - auto Packet = InworldClient->SendTextMessageToConversation(Player->GetConversationId(), Message).Packet; + NO_CLIENT_RETURN(void()) + INVALID_PLAYER_RETURN(void()) + EMPTY_ARG_RETURN(Message, void()) + + auto Packet = Client->SendTextMessageToConversation(Player->GetConversationId(), Message).Packet; if (Packet.IsValid()) { Packet->Accept(*PacketVisitor); @@ -275,58 +351,112 @@ void UInworldSession::SendTextMessageToConversation(UInworldPlayer* Player, cons void UInworldSession::SendSoundMessage(UInworldCharacter* Character, const TArray& InputData, const TArray& OutputData) { - InworldClient->SendSoundMessage(Character->GetAgentInfo().AgentId, InputData, OutputData); + NO_CLIENT_RETURN(void()) + INVALID_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(InputData, void()) + + Client->SendSoundMessage(Character->GetAgentInfo().AgentId, InputData, OutputData); } void UInworldSession::SendSoundMessageToConversation(UInworldPlayer* Player, const TArray& InputData, const TArray& OutputData) { - InworldClient->SendSoundMessageToConversation(Player->GetConversationId(), InputData, OutputData); + NO_CLIENT_RETURN(void()) + INVALID_PLAYER_RETURN(void()) + EMPTY_ARG_RETURN(InputData, void()) + + Client->SendSoundMessageToConversation(Player->GetConversationId(), InputData, OutputData); } void UInworldSession::SendAudioSessionStart(UInworldCharacter* Character) { - InworldClient->SendAudioSessionStart(Character->GetAgentInfo().AgentId); + NO_CLIENT_RETURN(void()) + INVALID_CHARACTER_RETURN(void()) + + Client->SendAudioSessionStart(Character->GetAgentInfo().AgentId); } void UInworldSession::SendAudioSessionStartToConversation(UInworldPlayer* Player) { - InworldClient->SendAudioSessionStartToConversation(Player->GetConversationId()); + NO_CLIENT_RETURN(void()) + INVALID_PLAYER_RETURN(void()) + + Client->SendAudioSessionStartToConversation(Player->GetConversationId()); } void UInworldSession::SendAudioSessionStop(UInworldCharacter* Character) { - InworldClient->SendAudioSessionStop(Character->GetAgentInfo().AgentId); + NO_CLIENT_RETURN(void()) + INVALID_CHARACTER_RETURN(void()) + + Client->SendAudioSessionStop(Character->GetAgentInfo().AgentId); } void UInworldSession::SendAudioSessionStopToConversation(UInworldPlayer* Player) { - InworldClient->SendAudioSessionStopToConversation(Player->GetConversationId()); + NO_CLIENT_RETURN(void()) + INVALID_PLAYER_RETURN(void()) + + Client->SendAudioSessionStopToConversation(Player->GetConversationId()); } void UInworldSession::SendNarrationEvent(UInworldCharacter* Character, const FString& Content) { - InworldClient->SendNarrationEvent(Character->GetAgentInfo().AgentId, Content); + NO_CLIENT_RETURN(void()) + INVALID_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(Content, void()) + + Client->SendNarrationEvent(Character->GetAgentInfo().AgentId, Content); } void UInworldSession::SendTrigger(UInworldCharacter* Character, const FString& Name, const TMap& Params) { - InworldClient->SendTrigger(Character->GetAgentInfo().AgentId, Name, Params); + NO_CLIENT_RETURN(void()) + INVALID_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(Name, void()) + + Client->SendTrigger(Character->GetAgentInfo().AgentId, Name, Params); } void UInworldSession::SendTriggerToConversation(UInworldPlayer* Player, const FString& Name, const TMap& Params) { - InworldClient->SendTrigger(Player->GetConversationId(), Name, Params); + NO_CLIENT_RETURN(void()) + INVALID_PLAYER_RETURN(void()) + EMPTY_ARG_RETURN(Name, void()) + + Client->SendTriggerToConversation(Player->GetConversationId(), Name, Params); } void UInworldSession::SendChangeSceneEvent(const FString& SceneName) { + NO_CLIENT_RETURN(void()) + EMPTY_ARG_RETURN(SceneName, void()) + UnpossessAgents(); - InworldClient->SendChangeSceneEvent(SceneName); + Client->SendChangeSceneEvent(SceneName); } void UInworldSession::CancelResponse(UInworldCharacter* Character, const FString& InteractionId, const TArray& UtteranceIds) { - InworldClient->CancelResponse(Character->GetAgentInfo().AgentId, InteractionId, UtteranceIds); + NO_CLIENT_RETURN(void()) + INVALID_CHARACTER_RETURN(void()) + EMPTY_ARG_RETURN(InteractionId, void()) + EMPTY_ARG_RETURN(UtteranceIds, void()) + + Client->CancelResponse(Character->GetAgentInfo().AgentId, InteractionId, UtteranceIds); +} + +EInworldConnectionState UInworldSession::GetConnectionState() const +{ + NO_CLIENT_RETURN(EInworldConnectionState::Idle) + + return Client->GetConnectionState(); +} + +void UInworldSession::GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const +{ + NO_CLIENT_RETURN(void()) + + Client->GetConnectionError(OutErrorMessage, OutErrorCode); } void UInworldSession::PossessAgents(const TArray& AgentInfos) @@ -362,7 +492,7 @@ void UInworldSession::PossessAgents(const TArray& AgentInfos) if (BrainNames.Num() > 0) { - InworldClient->LoadCharacters(BrainNames); + Client->LoadCharacters(BrainNames); } bIsLoaded = true; @@ -437,3 +567,8 @@ void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldChangeSc { Session->PossessAgents(Event.AgentInfos); } + +#undef EMPTY_ARG_RETURN +#undef NO_CLIENT_RETURN +#undef INVALID_CHARACTER_RETURN +#undef INVALID_PLAYER_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h index 7851f936..9d56d261 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldCharacterComponent.h @@ -87,13 +87,13 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone void SetBrainName(const FString& Name); UFUNCTION(BlueprintCallable, Category = "Inworld") - const FString& GetBrainName() const { return InworldCharacter->GetAgentInfo().BrainName; } + FString GetBrainName() const; UFUNCTION(BlueprintCallable, Category = "Inworld") - const FString& GetAgentId() const { return InworldCharacter->GetAgentInfo().AgentId; } + FString GetAgentId() const; UFUNCTION(BlueprintCallable, Category = "Inworld") - const FString& GetGivenName() const { return InworldCharacter->GetAgentInfo().GivenName; } + FString GetGivenName() const; UFUNCTION(BlueprintCallable, Category = "Inworld") const FString& GetUiName() const { return UiName; } @@ -104,7 +104,7 @@ class INWORLDAIINTEGRATION_API UInworldCharacterComponent : public UActorCompone UInworldCharacterPlayback* GetPlayback(TSubclassOf Class) const; UFUNCTION(BlueprintCallable, Category = "Interactions") - bool IsInteractingWithPlayer() const { return InworldCharacter != nullptr && InworldCharacter->GetTargetPlayer() != nullptr; } + bool IsInteractingWithPlayer() const; UFUNCTION(BlueprintCallable, Category = "Emotions") EInworldCharacterEmotionalBehavior GetEmotionalBehavior() const { return EmotionalBehavior; } diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h index 744e62c6..aa9f13ee 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayer.h @@ -91,6 +91,9 @@ class INWORLDAIINTEGRATION_API UInworldPlayer : public UObject FOnInworldPlayerConversationChanged OnConversationChangedDelegate; FOnInworldPlayerConversationChangedNative& OnConversationChanged() { return OnConversationChangedDelegateNative; } + UFUNCTION() + bool HasAudioSession() const { return bHasAudioSession; } + private: void UpdateConversation(); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index a4a9ee4a..a596a744 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -61,7 +61,7 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject void Destroy(); UFUNCTION(BlueprintPure, Category = "Client") - UInworldClient* GetClient() const { return InworldClient; } + UInworldClient* GetClient() const { return Client; } UFUNCTION() void HandlePacket(const FInworldWrappedPacket& WrappedPacket); @@ -87,15 +87,15 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject UFUNCTION(BlueprintCallable, Category = "Session") void StopSession(); UFUNCTION(BlueprintCallable, Category = "Session") - void PauseSession() { InworldClient->PauseSession(); } + void PauseSession(); UFUNCTION(BlueprintCallable, Category = "Session") - void ResumeSession() { InworldClient->ResumeSession(); } + void ResumeSession(); UFUNCTION(BlueprintPure, Category = "Session") - FString GetSessionId() const { return InworldClient->GetSessionId(); } + FString GetSessionId() const; UFUNCTION(BlueprintCallable, Category = "Session") - void SaveSession(FOnInworldSessionSavedCallback Callback) { InworldClient->SaveSession(Callback); } + void SaveSession(FOnInworldSessionSavedCallback Callback); UFUNCTION(BlueprintCallable, Category = "Load|Character") void LoadCharacter(UInworldCharacter* Character) { LoadCharacters({ Character }); } @@ -107,11 +107,11 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject void UnloadCharacters(const TArray& Characters); UFUNCTION(BlueprintCallable, Category = "Load") - void LoadSavedState(const FInworldSave& Save) { InworldClient->LoadSavedState(Save); } + void LoadSavedState(const FInworldSave& Save); UFUNCTION(BlueprintCallable, Category = "Load") - void LoadCapabilities(const FInworldCapabilitySet& CapabilitySet) { InworldClient->LoadCapabilities(CapabilitySet); } + void LoadCapabilities(const FInworldCapabilitySet& CapabilitySet); UFUNCTION(BlueprintCallable, Category = "Load") - void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile) { InworldClient->LoadPlayerProfile(PlayerProfile); } + void LoadPlayerProfile(const FInworldPlayerProfile& PlayerProfile); UFUNCTION(BlueprintCallable, Category = "Message|Text") void SendTextMessage(UInworldCharacter* Character, const FString& Message); @@ -148,9 +148,9 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject void CancelResponse(UInworldCharacter* Character, const FString& InteractionId, const TArray& UtteranceIds); UFUNCTION(BlueprintPure, Category = "Connection") - EInworldConnectionState GetConnectionState() const { return InworldClient->GetConnectionState(); } + EInworldConnectionState GetConnectionState() const; UFUNCTION(BlueprintPure, Category = "Connection") - void GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const { InworldClient->GetConnectionError(OutErrorMessage, OutErrorCode); } + void GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const; UPROPERTY(BlueprintAssignable, Category = "Connection") FOnInworldConnectionStateChanged OnConnectionStateChangedDelegate; @@ -173,7 +173,7 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject private: UPROPERTY() - UInworldClient* InworldClient; + UInworldClient* Client; UFUNCTION() void OnRep_IsLoaded(); @@ -229,9 +229,6 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject float CurrentRetryConnectionTime = 1.0f; FTimerHandle RetryConnectionTimerHandle; - - // Temp: Hack until deprecated functions are removed - friend class UInworldApiSubsystem; }; UINTERFACE(MinimalAPI, BlueprintType) From 4b81c6986f2d88149a14ff9233380c1095fd2bc7 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Thu, 2 May 2024 16:56:05 -0400 Subject: [PATCH 30/45] inline checkempty macro helper --- InworldAI/Source/InworldAIClient/Public/InworldMacros.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InworldAI/Source/InworldAIClient/Public/InworldMacros.h b/InworldAI/Source/InworldAIClient/Public/InworldMacros.h index 97e26303..70515119 100644 --- a/InworldAI/Source/InworldAIClient/Public/InworldMacros.h +++ b/InworldAI/Source/InworldAIClient/Public/InworldMacros.h @@ -13,11 +13,11 @@ namespace Inworld { template - bool CheckEmpty(const T& Value) { return !Value; } + inline bool CheckEmpty(const T& Value) { return !Value; } template<> - bool CheckEmpty(const FString& Value) { return Value.IsEmpty(); } + inline bool CheckEmpty(const FString& Value) { return Value.IsEmpty(); } template - bool CheckEmpty(const TArray& Value) { return Value.Num() == 0; } + inline bool CheckEmpty(const TArray& Value) { return Value.Num() == 0; } } #ifndef INWORLD_WARN_AND_RETURN_EMPTY From e70d731736a57843a3d1f1ae806de91aaf8a1a64 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 10:17:08 -0400 Subject: [PATCH 31/45] remove logically duplicate code --- .../Source/InworldAIIntegration/Private/InworldCharacter.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index 3b4d0d81..2ec40266 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -219,11 +219,6 @@ void UInworldCharacter::Unpossess() void UInworldCharacter::SetTargetPlayer(UInworldPlayer* Player) { - if (Player == nullptr) - { - ClearTargetPlayer(); - return; - } if (Player != TargetPlayer) { ClearTargetPlayer(); From e15874fc0a849d85a5ddecb1cbbd6c75d28da65d Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 10:40:42 -0400 Subject: [PATCH 32/45] fixup audio repl in session --- .../InworldAIIntegration/Private/InworldApi.cpp | 12 +++++++++++- .../Private/InworldSession.cpp | 14 -------------- .../InworldAIIntegration/Public/InworldSession.h | 5 +---- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index 0a676b90..b8e5def4 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -330,8 +330,18 @@ void UInworldApiSubsystem::ReplicateAudioEventFromServer(FInworldAudioDataEvent& void UInworldApiSubsystem::HandleAudioEventOnClient(TSharedPtr Packet) { NO_SESSION_RETURN(void()) + EMPTY_ARG_RETURN(Packet, void()) - InworldSession->HandlePacket(FInworldWrappedPacket(Packet)); + UInworldCharacter* const* InworldCharacter = InworldSession->GetRegisteredCharacters().FindByPredicate( + [Packet](UInworldCharacter* InworldCharacter) -> bool + { + return InworldCharacter && InworldCharacter->GetAgentInfo().AgentId == Packet->Routing.Source.Name; + } + ); + if (InworldCharacter != nullptr) + { + (*InworldCharacter)->HandlePacket(FInworldWrappedPacket(Packet)); + } } #undef EMPTY_ARG_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 287f3fe4..6970ae74 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -523,20 +523,6 @@ void UInworldSession::OnRep_IsLoaded() OnLoadedDelegate.Broadcast(bIsLoaded); } -void UInworldSession::OnRep_RegisteredCharacters() -{ - BrainNameToCharacter = {}; - AgentIdToCharacter = {}; - BrainNameToAgentInfo = {}; - for (UInworldCharacter* Character : RegisteredCharacters) - { - const FInworldAgentInfo& AgentInfo = Character->GetAgentInfo(); - BrainNameToCharacter.Add(AgentInfo.BrainName, Character); - AgentIdToCharacter.Add(AgentInfo.AgentId, Character); - BrainNameToAgentInfo.Add(AgentInfo.BrainName, AgentInfo); - } -} - void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldConversationUpdateEvent& Event) { if (Event.EventType == EInworldConversationUpdateType::EVICTED) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index a596a744..93e94524 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -185,10 +185,7 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject FDelegateHandle OnClientConnectionStateChangedHandle; FDelegateHandle OnClientPerceivedLatencyHandle; - UFUNCTION() - void OnRep_RegisteredCharacters(); - - UPROPERTY(ReplicatedUsing=OnRep_RegisteredCharacters) + UPROPERTY(Replicated) TArray RegisteredCharacters; UPROPERTY(Replicated) TArray RegisteredPlayers; From d2d655ea64ae717f5ef49e9f9651bed5e2a227d7 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 13:43:35 -0400 Subject: [PATCH 33/45] refresh audio session when conversation id updates --- .../Private/InworldPlayer.cpp | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index f7d1a66f..b1f33778 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -207,23 +207,22 @@ void UInworldPlayer::ClearAllTargetCharacters() void UInworldPlayer::UpdateConversation() { - FString NextConversationId = Session->GetClient()->UpdateConversation(ConversationId, Inworld::CharactersToAgentIds(TargetCharacters), false); - if (ConversationId != NextConversationId) + NO_SESSION_RETURN(void()) + + FString NextConversationId = Session->GetClient()->UpdateConversation(ConversationId, Inworld::CharactersToAgentIds(TargetCharacters), true); + const bool bHadAudioSession = bHasAudioSession; + if (bHasAudioSession) { - const bool bHadAudioSession = bHasAudioSession; - if (bHasAudioSession) - { - SendAudioSessionStopToConversation(); - } + SendAudioSessionStopToConversation(); + } - ConversationId = NextConversationId; - OnConversationChangedDelegateNative.Broadcast(); - OnConversationChangedDelegate.Broadcast(); + ConversationId = NextConversationId; + OnConversationChangedDelegateNative.Broadcast(); + OnConversationChangedDelegate.Broadcast(); - if (bHadAudioSession && !ConversationId.IsEmpty()) - { - SendAudioSessionStartToConversation(); - } + if (bHadAudioSession && !ConversationId.IsEmpty()) + { + SendAudioSessionStartToConversation(); } } From 3bba94be0f100701770e0da262c9449d6a583e9a Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 13:58:53 -0400 Subject: [PATCH 34/45] Add BP function library conversions --- InworldAI/Config/BaseInworldAI.ini | 1 + InworldAI/Config/DefaultInworldAI.ini | 1 + .../Public/InworldBlueprintFunctionLibrary.h | 31 --------------- .../InworldBlueprintFunctionLibrary.cpp | 22 +++++++++++ .../Public/InworldBlueprintFunctionLibrary.h | 39 +++++++++++++++++++ 5 files changed, 63 insertions(+), 31 deletions(-) delete mode 100644 InworldAI/Source/InworldAIClient/Public/InworldBlueprintFunctionLibrary.h rename InworldAI/Source/{InworldAIClient => InworldAIIntegration}/Private/InworldBlueprintFunctionLibrary.cpp (75%) create mode 100644 InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h diff --git a/InworldAI/Config/BaseInworldAI.ini b/InworldAI/Config/BaseInworldAI.ini index 87e7ebf0..f3ec57b3 100644 --- a/InworldAI/Config/BaseInworldAI.ini +++ b/InworldAI/Config/BaseInworldAI.ini @@ -9,3 +9,4 @@ +StructRedirects=(OldName="/Script/InworldAIIntegration.FInworldAuth",NewName="/Script/InworldAIClient.FInworldAuth") +StructRedirects=(OldName="/Script/InworldAIIntegration.FInworldSessionToken",NewName="/Script/InworldAIClient.FInworldSessionToken") +StructRedirects=(OldName="/Script/InworldAIIntegration.FInworldEnvironment",NewName="/Script/InworldAIClient.FInworldEnvironment") ++ClassRedirects=(OldName="/Script/InworldAIClient.UInworldBlueprintFunctionLibrary",NewName="/Script/InworldAIIntegration.UInworldBlueprintFunctionLibrary") diff --git a/InworldAI/Config/DefaultInworldAI.ini b/InworldAI/Config/DefaultInworldAI.ini index 87e7ebf0..f3ec57b3 100644 --- a/InworldAI/Config/DefaultInworldAI.ini +++ b/InworldAI/Config/DefaultInworldAI.ini @@ -9,3 +9,4 @@ +StructRedirects=(OldName="/Script/InworldAIIntegration.FInworldAuth",NewName="/Script/InworldAIClient.FInworldAuth") +StructRedirects=(OldName="/Script/InworldAIIntegration.FInworldSessionToken",NewName="/Script/InworldAIClient.FInworldSessionToken") +StructRedirects=(OldName="/Script/InworldAIIntegration.FInworldEnvironment",NewName="/Script/InworldAIClient.FInworldEnvironment") ++ClassRedirects=(OldName="/Script/InworldAIClient.UInworldBlueprintFunctionLibrary",NewName="/Script/InworldAIIntegration.UInworldBlueprintFunctionLibrary") diff --git a/InworldAI/Source/InworldAIClient/Public/InworldBlueprintFunctionLibrary.h b/InworldAI/Source/InworldAIClient/Public/InworldBlueprintFunctionLibrary.h deleted file mode 100644 index d0d1b135..00000000 --- a/InworldAI/Source/InworldAIClient/Public/InworldBlueprintFunctionLibrary.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2022-2024 Theai, Inc. dba Inworld AI - * - * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement - * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license - */ - -#pragma once - -#include "CoreMinimal.h" -#include "Kismet/BlueprintFunctionLibrary.h" -#include "InworldBlueprintFunctionLibrary.generated.h" - -class USoundWave; - -/** - * Blueprint Function Library for Inworld. - */ -UCLASS() -class INWORLDAICLIENT_API UInworldBlueprintFunctionLibrary : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -public: - - UFUNCTION(BlueprintCallable, Category = "Inworld|Audio") - static bool SoundWaveToDataArray(USoundWave* SoundWave, TArray& OutDataArray); - - UFUNCTION(BlueprintCallable, Category = "Inworld|Audio") - static USoundWave* DataArrayToSoundWave(const TArray& DataArray); -}; diff --git a/InworldAI/Source/InworldAIClient/Private/InworldBlueprintFunctionLibrary.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldBlueprintFunctionLibrary.cpp similarity index 75% rename from InworldAI/Source/InworldAIClient/Private/InworldBlueprintFunctionLibrary.cpp rename to InworldAI/Source/InworldAIIntegration/Private/InworldBlueprintFunctionLibrary.cpp index bee0e5a7..761b2f9a 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldBlueprintFunctionLibrary.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldBlueprintFunctionLibrary.cpp @@ -8,9 +8,31 @@ #include "InworldBlueprintFunctionLibrary.h" +#include "InworldSession.h" +#include "InworldSessionComponent.h" +#include "InworldCharacter.h" +#include "InworldCharacterComponent.h" +#include "InworldPlayer.h" +#include "InworldPlayerComponent.h" + #include "Audio.h" #include "Sound/SoundWave.h" +UInworldSession* UInworldBlueprintFunctionLibrary::Conv_InworldSessionComponentToSession(UInworldSessionComponent* SessionComponent) +{ + return IInworldSessionOwnerInterface::Execute_GetInworldSession(SessionComponent); +} + +UInworldCharacter* UInworldBlueprintFunctionLibrary::Conv_InworldCharacterComponentToCharacter(UInworldCharacterComponent* CharacterComponent) +{ + return IInworldCharacterOwnerInterface::Execute_GetInworldCharacter(CharacterComponent); +} + +UInworldPlayer* UInworldBlueprintFunctionLibrary::Conv_InworldPlayerComponentToPlayer(UInworldPlayerComponent* PlayerComponent) +{ + return IInworldPlayerOwnerInterface::Execute_GetInworldPlayer(PlayerComponent); +} + bool UInworldBlueprintFunctionLibrary::SoundWaveToDataArray(USoundWave* SoundWave, TArray& OutDataArray) { //TODO: support other formats diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h b/InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h new file mode 100644 index 00000000..8f47040e --- /dev/null +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h @@ -0,0 +1,39 @@ +/** + * Copyright 2022-2024 Theai, Inc. dba Inworld AI + * + * Use of this source code is governed by the Inworld.ai Software Development Kit License Agreement + * that can be found in the LICENSE.md file or at https://www.inworld.ai/sdk-license + */ + +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "InworldBlueprintFunctionLibrary.generated.h" + +class USoundWave; + +/** + * Blueprint Function Library for Inworld. + */ +UCLASS() +class INWORLDAIINTEGRATION_API UInworldBlueprintFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintPure, meta = (BlueprintAutocast, DisplayName = "To Inworld Session (Inworld Session Component)", CompactNodeTitle = "->")) + static UInworldSession* Conv_InworldSessionComponentToSession(UInworldSessionComponent* SessionComponent); + + UFUNCTION(BlueprintPure, meta = (BlueprintAutocast, DisplayName = "To Inworld Character (Inworld Character Component)", CompactNodeTitle = "->")) + static UInworldCharacter* Conv_InworldCharacterComponentToCharacter(UInworldCharacterComponent* CharacterComponent); + + UFUNCTION(BlueprintPure, meta = (BlueprintAutocast, DisplayName = "To Inworld Player (Inworld Player Component)", CompactNodeTitle = "->")) + static UInworldPlayer* Conv_InworldPlayerComponentToPlayer(UInworldPlayerComponent* PlayerComponent); + + UFUNCTION(BlueprintCallable, Category = "Inworld|Audio") + static bool SoundWaveToDataArray(USoundWave* SoundWave, TArray& OutDataArray); + + UFUNCTION(BlueprintCallable, Category = "Inworld|Audio") + static USoundWave* DataArrayToSoundWave(const TArray& DataArray); +}; From 02dcd9cf6367d70a712099849f784dddaaae7467 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 14:16:11 -0400 Subject: [PATCH 35/45] add categories --- .../Public/InworldBlueprintFunctionLibrary.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h b/InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h index 8f47040e..a8e1e202 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldBlueprintFunctionLibrary.h @@ -22,13 +22,13 @@ class INWORLDAIINTEGRATION_API UInworldBlueprintFunctionLibrary : public UBluepr GENERATED_BODY() public: - UFUNCTION(BlueprintPure, meta = (BlueprintAutocast, DisplayName = "To Inworld Session (Inworld Session Component)", CompactNodeTitle = "->")) + UFUNCTION(BlueprintPure, Category = "Inworld|Component", meta = (BlueprintAutocast, DisplayName = "To Inworld Session (Inworld Session Component)", CompactNodeTitle = "->")) static UInworldSession* Conv_InworldSessionComponentToSession(UInworldSessionComponent* SessionComponent); - UFUNCTION(BlueprintPure, meta = (BlueprintAutocast, DisplayName = "To Inworld Character (Inworld Character Component)", CompactNodeTitle = "->")) + UFUNCTION(BlueprintPure, Category = "Inworld|Component", meta = (BlueprintAutocast, DisplayName = "To Inworld Character (Inworld Character Component)", CompactNodeTitle = "->")) static UInworldCharacter* Conv_InworldCharacterComponentToCharacter(UInworldCharacterComponent* CharacterComponent); - UFUNCTION(BlueprintPure, meta = (BlueprintAutocast, DisplayName = "To Inworld Player (Inworld Player Component)", CompactNodeTitle = "->")) + UFUNCTION(BlueprintPure, Category = "Inworld|Component", meta = (BlueprintAutocast, DisplayName = "To Inworld Player (Inworld Player Component)", CompactNodeTitle = "->")) static UInworldPlayer* Conv_InworldPlayerComponentToPlayer(UInworldPlayerComponent* PlayerComponent); UFUNCTION(BlueprintCallable, Category = "Inworld|Audio") From 2702459b5fbf09feca9849ccd6aa436970f129f4 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 16:28:53 -0400 Subject: [PATCH 36/45] Update Inworld Session Component Add configuration to Inworld Session Component --- .../BP_InworldSessionController.uasset | Bin 82347 -> 77015 bytes InworldAI/Content/Dialog/DialogMap.umap | Bin 17845 -> 18093 bytes .../Content/Dialog/WBP_DialogWidget.uasset | Bin 273086 -> 272005 bytes .../StudioWidget/EUW_InworldStudio.uasset | Bin 902850 -> 906645 bytes .../InworldAIClient/Public/InworldTypes.h | 56 +++--- .../Private/InworldSession.cpp | 23 --- .../Private/InworldSessionComponent.cpp | 185 ++++++++++++++++++ .../Public/InworldSession.h | 7 - .../Public/InworldSessionComponent.h | 73 +++++++ 9 files changed, 286 insertions(+), 58 deletions(-) diff --git a/InworldAI/Content/BP_InworldSessionController.uasset b/InworldAI/Content/BP_InworldSessionController.uasset index f820e35668fb3b22eac55e6d2072782fe9ee6bac..17febc1b18677f14a433349d6bce3bb2aa1a1187 100644 GIT binary patch literal 77015 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 W@6hGHEKW|3I78W;^922eE&l+SS}}D1 diff --git a/InworldAI/Content/Dialog/WBP_DialogWidget.uasset b/InworldAI/Content/Dialog/WBP_DialogWidget.uasset index 72912cdd85fb67836d97583d3cdc1f09698f018f..5f9a576b96e8ed2234460de79710fc8ae2ed98fa 100644 GIT binary patch literal 272005 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 IeYgJnzZM)ZPyhe` diff --git a/InworldAI/Content/StudioWidget/EUW_InworldStudio.uasset b/InworldAI/Content/StudioWidget/EUW_InworldStudio.uasset index 2ed403692d2d07043a2e196b3cf9a51ff7ecf40b..14025601a2073ade59df4857fd979df0b31c4e01 100644 GIT binary patch literal 906645 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

NxhnZ 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 C#=m+1 literal 902850 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
ImhA+2uSu`uLqgTbtr(e-n? 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 Fields = {}; }; @@ -35,40 +35,40 @@ struct FInworldCapabilitySet { GENERATED_BODY() - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool Animations = false; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool Audio = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool Emotions = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool Interruptions = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool EmotionStreaming = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool SilenceEvents = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool PhonemeInfo = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool Continuation = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool TurnBasedSTT = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool NarratedActions = false; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool Relations = true; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") bool MultiAgent = true; }; @@ -77,13 +77,13 @@ struct FInworldAuth { GENERATED_BODY() - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") FString Base64Signature = ""; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") FString ApiKey = ""; - UPROPERTY(BlueprintReadWrite, Category = "Capability") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Capability") FString ApiSecret = ""; }; @@ -92,13 +92,13 @@ struct FInworldSessionToken { GENERATED_BODY() - UPROPERTY(BlueprintReadWrite, Category = "Token") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Token") FString Token = ""; - UPROPERTY(BlueprintReadWrite, Category = "Token") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Token") int64 ExpirationTime = 0; - UPROPERTY(BlueprintReadWrite, Category = "Token") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Token") FString SessionId = ""; }; @@ -107,7 +107,7 @@ struct FInworldSave { GENERATED_BODY() - UPROPERTY(BlueprintReadWrite, Category = "Data") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Data") TArray Data; }; @@ -116,10 +116,10 @@ struct FInworldEnvironment { GENERATED_BODY() - UPROPERTY(BlueprintReadWrite, Category = "Environment") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Environment") FString AuthUrl = ""; - UPROPERTY(BlueprintReadWrite, Category = "Environment") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Environment") FString TargetUrl = ""; }; @@ -128,12 +128,12 @@ struct FInworldAgentInfo { GENERATED_BODY() - UPROPERTY(BlueprintReadWrite, Category = "Agent") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Agent") FString BrainName = ""; - UPROPERTY(BlueprintReadWrite, Category = "Agent") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Agent") FString AgentId = ""; - UPROPERTY(BlueprintReadWrite, Category = "Agent") + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Agent") FString GivenName = ""; }; diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 6970ae74..5297269a 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -78,29 +78,6 @@ void UInworldSession::Init() { OnConnectionStateChangedDelegateNative.Broadcast(ConnectionState); OnConnectionStateChangedDelegate.Broadcast(ConnectionState); - - if (ConnectionState == EInworldConnectionState::Connected) - { - CurrentRetryConnectionTime = 1.f; - } - - if (ConnectionState == EInworldConnectionState::Disconnected) - { - UWorld* World = GetWorld(); - if (!World || World->bIsTearingDown) - { - return; - } - if (CurrentRetryConnectionTime == 0.f) - { - ResumeSession(); - } - else - { - World->GetTimerManager().SetTimer(RetryConnectionTimerHandle, this, &UInworldSession::ResumeSession, CurrentRetryConnectionTime); - } - CurrentRetryConnectionTime += FMath::Min(CurrentRetryConnectionTime + RetryConnectionIntervalTime, MaxRetryConnectionTime); - } } ); OnClientPerceivedLatencyHandle = Client->OnPerceivedLatency().AddLambda( diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp index b9696903..f29cfbe4 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp @@ -8,10 +8,14 @@ #include "InworldSessionComponent.h" #include "InworldApi.h" +#include "InworldMacros.h" #include #include +#define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldSessionComponent, Arg, Return) +#define NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(InworldSession, Return) EMPTY_ARG_RETURN(InworldSession->GetClient(), Return) + UInworldSessionComponent::UInworldSessionComponent() : Super() { @@ -78,9 +82,190 @@ bool UInworldSessionComponent::ReplicateSubobjects(UActorChannel* Channel, FOutB #endif } +bool UInworldSessionComponent::GetIsLoaded() const +{ + NO_SESSION_RETURN(false) + + return InworldSession->IsLoaded(); +} + +void UInworldSessionComponent::StartSession() +{ + NO_SESSION_RETURN(void()) + + InworldSession->GetClient()->SetEnvironment(Environment); + InworldSession->StartSession(SceneId, PlayerProfile, Auth, {}, {}, CapabilitySet); +} + +void UInworldSessionComponent::StartSessionFromSave(const FInworldSave& Save) +{ + NO_SESSION_RETURN(void()) + + InworldSession->GetClient()->SetEnvironment(Environment); + InworldSession->StartSession(SceneId, PlayerProfile, Auth, Save, {}, CapabilitySet); +} + +void UInworldSessionComponent::StartSessionFromToken(const FInworldSessionToken& Token) +{ + NO_SESSION_RETURN(void()) + + InworldSession->GetClient()->SetEnvironment(Environment); + InworldSession->StartSession(SceneId, PlayerProfile, Auth, {}, Token, CapabilitySet); +} + +void UInworldSessionComponent::StopSession() +{ + NO_SESSION_RETURN(void()) + + InworldSession->StopSession(); +} + +void UInworldSessionComponent::PauseSession() +{ + NO_SESSION_RETURN(void()) + + InworldSession->PauseSession(); +} + +void UInworldSessionComponent::ResumeSession() +{ + NO_SESSION_RETURN(void()) + + InworldSession->ResumeSession(); +} + +FString UInworldSessionComponent::GetSessionId() const +{ + NO_SESSION_RETURN({}) + + return InworldSession->GetSessionId(); +} + +void UInworldSessionComponent::SaveSession(FOnInworldSessionSavedCallback Callback) +{ + NO_SESSION_RETURN(void()) + + InworldSession->SaveSession(Callback); +} + +EInworldConnectionState UInworldSessionComponent::GetConnectionState() const +{ + NO_SESSION_RETURN(EInworldConnectionState::Idle) + + return InworldSession->GetConnectionState(); +} + +void UInworldSessionComponent::GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const +{ + NO_SESSION_RETURN(void()) + + return InworldSession->GetConnectionError(OutErrorMessage, OutErrorCode); +} + +void UInworldSessionComponent::SetSceneId(const FString& InSceneId) +{ + SceneId = InSceneId; + + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) + { + NO_SESSION_RETURN(void()) + + if (GetConnectionState() == EInworldConnectionState::Connected) + { + InworldSession->SendChangeSceneEvent(InSceneId); + } + } +} + +void UInworldSessionComponent::SetPlayerProfile(const FInworldPlayerProfile& InPlayerProfile) +{ + PlayerProfile = InPlayerProfile; + + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) + { + NO_SESSION_RETURN(void()) + + if (GetConnectionState() == EInworldConnectionState::Connected) + { + InworldSession->LoadPlayerProfile(InPlayerProfile); + } + } +} + +void UInworldSessionComponent::SetCapabilities(const FInworldCapabilitySet& InCapabilitySet) +{ + CapabilitySet = InCapabilitySet; + + UWorld* World = GetWorld(); + if (World && (World->WorldType == EWorldType::Game || World->WorldType == EWorldType::PIE) && World->GetNetMode() != NM_Client) + { + NO_SESSION_RETURN(void()) + + if (GetConnectionState() == EInworldConnectionState::Connected) + { + InworldSession->LoadCapabilities(InCapabilitySet); + } + } +} + void UInworldSessionComponent::OnRep_InworldSession() { GetWorld()->GetSubsystem()->SetInworldSession(InworldSession); OnSessionCreatedDelegateNative.Broadcast(); OnSessionCreatedDelegate.Broadcast(); + + const bool bIsLoaded = GetIsLoaded(); + OnSessionLoadedDelegateNative.Broadcast(bIsLoaded); + OnSessionLoadedDelegate.Broadcast(bIsLoaded); + + InworldSession->OnLoaded().AddLambda( + [this](bool bIsLoaded) -> void + { + OnSessionLoadedDelegateNative.Broadcast(bIsLoaded); + OnSessionLoadedDelegate.Broadcast(bIsLoaded); + } + ); + + const EInworldConnectionState ConnectionState = GetConnectionState(); + OnSessionConnectionStateChangedDelegateNative.Broadcast(ConnectionState); + OnSessionConnectionStateChangedDelegate.Broadcast(ConnectionState); + + InworldSession->OnConnectionStateChanged().AddLambda( + [this](EInworldConnectionState ConnectionState) -> void + { + OnSessionConnectionStateChangedDelegateNative.Broadcast(ConnectionState); + OnSessionConnectionStateChangedDelegate.Broadcast(ConnectionState); + + UWorld* World = GetWorld(); + if (!World || World->bIsTearingDown) + { + return; + } + if (World->GetNetMode() != NM_Client) + { + if (ConnectionState == EInworldConnectionState::Connected) + { + CurrentRetryConnectionTime = 1.f; + } + + if (ConnectionState == EInworldConnectionState::Disconnected) + { + if (CurrentRetryConnectionTime == 0.f) + { + ResumeSession(); + } + else + { + World->GetTimerManager().SetTimer(RetryConnectionTimerHandle, this, &UInworldSessionComponent::ResumeSession, CurrentRetryConnectionTime); + } + CurrentRetryConnectionTime += FMath::Min(CurrentRetryConnectionTime + RetryConnectionIntervalTime, MaxRetryConnectionTime); + } + } + } + ); } + +#undef EMPTY_ARG_RETURN +#undef NO_SESSION_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index 93e94524..126288ec 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -219,13 +219,6 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject }; TSharedRef PacketVisitor; - -private: - float RetryConnectionIntervalTime = 0.25f; - float MaxRetryConnectionTime = 5.0f; - float CurrentRetryConnectionTime = 1.0f; - - FTimerHandle RetryConnectionTimerHandle; }; UINTERFACE(MinimalAPI, BlueprintType) diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h index a19f2407..23dea9b5 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSessionComponent.h @@ -37,8 +37,81 @@ class INWORLDAIINTEGRATION_API UInworldSessionComponent : public UActorComponent FOnInworldSessionCreated OnSessionCreatedDelegate; FOnInworldSessionCreatedNative& OnSessionCreated() { return OnSessionCreatedDelegateNative; } + UFUNCTION(BlueprintPure, Category = "Load") + bool GetIsLoaded() const; + + UPROPERTY(BlueprintAssignable, Category = "Connection") + FOnInworldSessionLoaded OnSessionLoadedDelegate; + FOnInworldSessionLoadedNative& OnLoaded() { return OnSessionLoadedDelegateNative; } + + UFUNCTION(BlueprintCallable, Category = "Session") + void StartSession(); + UFUNCTION(BlueprintCallable, Category = "Session") + void StartSessionFromSave(const FInworldSave& Save); + UFUNCTION(BlueprintCallable, Category = "Session") + void StartSessionFromToken(const FInworldSessionToken& Token); + UFUNCTION(BlueprintCallable, Category = "Session") + void StopSession(); + UFUNCTION(BlueprintCallable, Category = "Session") + void PauseSession(); + UFUNCTION(BlueprintCallable, Category = "Session") + void ResumeSession(); + + UFUNCTION(BlueprintPure, Category = "Session") + FString GetSessionId() const; + + UFUNCTION(BlueprintCallable, Category = "Session") + void SaveSession(FOnInworldSessionSavedCallback Callback); + + UPROPERTY(BlueprintAssignable, Category = "Connection") + FOnInworldConnectionStateChanged OnSessionConnectionStateChangedDelegate; + FOnInworldConnectionStateChangedNative& OnSessionConnectionStateChanged() { return OnSessionConnectionStateChangedDelegateNative; } + + UFUNCTION(BlueprintPure, Category = "Connection") + EInworldConnectionState GetConnectionState() const; + UFUNCTION(BlueprintPure, Category = "Connection") + void GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const; + + UFUNCTION(BlueprintCallable, Category = "Scene") + void SetSceneId(const FString& InSceneId); + + UFUNCTION(BlueprintCallable, Category = "Player Profile") + void SetPlayerProfile(const FInworldPlayerProfile& InPlayerProfile); + + UFUNCTION(BlueprintCallable, Category = "Capabilities") + void SetCapabilities(const FInworldCapabilitySet& InCapabilitySet); + +protected: + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Config") + FString SceneId; + + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Config") + FInworldPlayerProfile PlayerProfile; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Config") + FInworldAuth Auth; + + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Config") + FInworldCapabilitySet CapabilitySet; + + UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Config|Internal") + FInworldEnvironment Environment; + + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Config|Connection") + float RetryConnectionIntervalTime = 0.25f; + + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Config|Connection") + float MaxRetryConnectionTime = 5.0f; + + UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Config|Connection") + float CurrentRetryConnectionTime = 1.0f; + + FTimerHandle RetryConnectionTimerHandle; + private: FOnInworldSessionCreatedNative OnSessionCreatedDelegateNative; + FOnInworldSessionLoadedNative OnSessionLoadedDelegateNative; + FOnInworldConnectionStateChangedNative OnSessionConnectionStateChangedDelegateNative; UFUNCTION() void OnRep_InworldSession(); From 45c9cfd45c333f576d454d34e18ef05fcb7a8111 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 17:36:03 -0400 Subject: [PATCH 37/45] missing headers --- .../Source/InworldAIIntegration/Private/InworldCharacter.cpp | 2 ++ InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp | 2 ++ .../InworldAIIntegration/Private/InworldPlayerComponent.cpp | 2 ++ .../InworldAIIntegration/Private/InworldSessionComponent.cpp | 2 ++ 4 files changed, 8 insertions(+) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index 2ec40266..88eacf26 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -11,6 +11,8 @@ #include "InworldPlayer.h" #include "InworldMacros.h" +#include "InworldAIIntegrationModule.h" + #include "Engine/BlueprintGeneratedClass.h" #include "Engine/NetDriver.h" #include "Engine/Engine.h" diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp index b1f33778..62e56cd7 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayer.cpp @@ -11,6 +11,8 @@ #include "InworldSession.h" #include "InworldMacros.h" +#include "InworldAIIntegrationModule.h" + #include "Engine/BlueprintGeneratedClass.h" #include "Engine/NetDriver.h" #include "Engine/Engine.h" diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp index f3af8a25..6dc577ac 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerComponent.cpp @@ -10,6 +10,8 @@ #include "InworldMacros.h" #include "InworldCharacterComponent.h" +#include "InworldAIIntegrationModule.h" + #include #include diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp index f29cfbe4..92efc34b 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp @@ -10,6 +10,8 @@ #include "InworldApi.h" #include "InworldMacros.h" +#include "InworldAIIntegrationModule.h" + #include #include From f74f71998b5567d362e31cae6b52695d4b2837c4 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 18:04:45 -0400 Subject: [PATCH 38/45] missing header --- .../InworldAIIntegration/Private/InworldSessionComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp index 92efc34b..888d5e16 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp @@ -12,6 +12,7 @@ #include "InworldAIIntegrationModule.h" +#include "TimerManager.h" #include #include From 0cd03429bd7bf8c479ebe6f650c0fab1d4cde2de Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Mon, 6 May 2024 21:36:07 -0400 Subject: [PATCH 39/45] allow override of project name --- InworldAI/Source/InworldAIClient/Private/InworldClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp index 9ae31a2c..40ae099b 100644 --- a/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp +++ b/InworldAI/Source/InworldAIClient/Private/InworldClient.cpp @@ -263,7 +263,7 @@ void UInworldClient::StartSession(const FString& SceneId, const FInworldPlayerPr Options.Base64 = TCHAR_TO_UTF8(*Auth.Base64Signature); Options.ApiKey = TCHAR_TO_UTF8(*Auth.ApiKey); Options.ApiSecret = TCHAR_TO_UTF8(*Auth.ApiSecret); - Options.ProjectName = TCHAR_TO_UTF8(FApp::GetProjectName()); + Options.ProjectName = TCHAR_TO_UTF8(!PlayerProfile.ProjectName.IsEmpty() ? *PlayerProfile.ProjectName : FApp::GetProjectName()); ConvertPlayerProfile(PlayerProfile, Options.UserConfig); ConvertCapabilities(CapabilitySet, Options.Capabilities); From b8455ef1f810ddf1e57a800caf886527332bac14 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Tue, 7 May 2024 10:39:48 -0400 Subject: [PATCH 40/45] Fix SetName in editor --- .../Private/InworldCharacterComponent.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp index 328ffd87..d5c73231 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacterComponent.cpp @@ -198,9 +198,19 @@ bool UInworldCharacterComponent::ReplicateSubobjects(UActorChannel* Channel, FOu void UInworldCharacterComponent::SetBrainName(const FString& Name) { +#if WITH_EDITOR + UWorld* World = GetWorld(); + if (World == nullptr || !World->IsPlayInEditor()) + { + BrainName = Name; + return; + } +#endif NO_CHARACTER_RETURN(void()) + + BrainName = Name; - InworldCharacter->SetBrainName(Name); + InworldCharacter->SetBrainName(BrainName); } FString UInworldCharacterComponent::GetBrainName() const From 9c8e528a1eb4fe65780b55de5df6c08378bb333a Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Tue, 7 May 2024 11:04:03 -0400 Subject: [PATCH 41/45] Fixup Dialogue map example Forward connection state over rep fixup nodes to use SessionComponent for ease of use --- .../BP_InworldSessionController.uasset | Bin 77015 -> 83366 bytes .../Content/Dialog/BP_DialogMapPawn.uasset | Bin 136429 -> 121472 bytes .../Private/InworldSession.cpp | 17 +++++++++++------ .../Private/InworldSessionComponent.cpp | 16 +++++++++------- .../Public/InworldSession.h | 6 ++++++ 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/InworldAI/Content/BP_InworldSessionController.uasset b/InworldAI/Content/BP_InworldSessionController.uasset index 17febc1b18677f14a433349d6bce3bb2aa1a1187..57a134217d71a33c4dd734ff5f70a14851ca98c3 100644 GIT binary patch literal 83366 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 literal 77015 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

CWFf)L2@1w`JSqnMq4dGA9eu># z;lRQO3ZM}jnF8FPupAe3pg`BU0hcgBiR z;)lkD2&m-%tuqNet^`1J5A(0 z>EyFTO^GDwK9(wq3c1WW!q5=_7G8YRI2C1kk&i$&@e zYc@N&b|w~WPZ~!o${8X6ynsG9is?g1AEkXBdhNEt9S&6Z%jxB(P`S_JFQa#GOUf#= z!2-3=ehMI%2endFW3f7CR;=*LdY*iR2=BvH;aYXxU!CQ05a`qe>8Cj8%s&fgzFw!W z*QhhrWpLEXQ||ZYI~=*=?2`J?i=Y4Kx)m>c`}-LRWxhItxHt||XGc;Z%g8Gw0{D+C z<+qF8dSmC~M~ALnH|EUs-#>PFUMcy(ido7PN^;l}4$PNuaNmkNq=*2pCGKcP$oyBa SnG#plK+W8QN6t9-s{aSP&C}2T diff --git a/InworldAI/Content/Dialog/BP_DialogMapPawn.uasset b/InworldAI/Content/Dialog/BP_DialogMapPawn.uasset index 99f4e59e3e04c663439fc489b0a3c61a1d84128e..3cba466af1980c3a5aa9673eb9aa9babc3a85310 100644 GIT binary patch literal 121472 zcmeHw2YeL8`}ZCoB3KXvEC?460hQjdKzc$+0--1h;YcnJOzy(ng{DF%iUkz`MNvd4 z7C=E!ilCx@8zPFmpn`}fid}yy7T)JOGtceb-ri*|TtI!@eD-$tnexo@%+sdq=9wAi z-2LmJLx)CI*Rsqq5Ihw@h2Qd;A-97k&BRdCgBI*agpw==OWY-kRUd z)E=KQ?wqr05NzP^4=%~b>{xH&B@;K?uzy2oErMNh>X{>FW*4mb_|1kZ-g)uM6V4~t zw70J+TA7%=@4$dQD_X5v{}f=&-X3(pMG z?p;&6bm`G0v3-Xw-P2OLckj}vLrO==B9C5l$v<1u`qFjf>6-RSZ%v~*v`wj+_J4Hl zqI3Ok@8;e*vrFQQNn;8#m%aS_jz{lz4C!}$#@yX^j4z)&t_1l}4;pX`oz=C4XZCi~ zqq}p@9h}>*J9 zIDv4Fqch#N%k)g}`ict@Gux#Uxr)7`+a=}X$-Dlp(j3UF4WVt&Bu zOD=Z#{o3FTi?^HzP(i^U?~o$*gi^0Bply9|YWMmAI^N~UcNgRoc~Xk}rNypE+LT7$ z9(x>;ii@+n1#Z7~sKMt+q6VMOH7UpEEp__>leEk=pB5dDY!h5Xfqq_BfxAHa?ZB(s zP9oSSD(jt)LW~L&c|F>p?@#=y0l>-Lk`lKkkW@BmRI!^-dZ^5}wk`UdfW%CHve)Ae zq?LK{wH`k|_B<*lU{0COEnx3Gmwojafc0~acI8jXa=VEjN*(Raz1&?q&|T=)Zhq*p z^C8%yRC|7U=aJ56c~WtiyVO_Y38a@56=<&=d-~whjL=L^!0q$6iU<4M*`DG_+BLiH z8PLd>A$O8L;4T^B_W421w7_xahSWM}QmI=z{^Ys4ATFc4-eRq7oq{hxR1!S|IaasE zn(HA(qq4`leZHasL6%@p-T%$Gv>~$R3~~92T*RCdw?E%kR4P)ZHaPqEQ$tewy92Hi zSHP9(3HT;yZ`@W|E;yL$E-oY<2HX<^+Ne*ieB=}$8&c#ia}^g&b`$eUNx3`$ZRM=4 zABd(-3b?f|_uRZiG?gBLP2HE(W=mr#o$M+u2J`cheQsC4oj1@ODD!!SxQL(H^XrS7 zwJ_#McL#*rWfuy`3&}jM=6Cy{$-xRKbEaQ*Q%J^TqukwEn=Bxl2f`siWUo z(d=1)E;}nFPng-qe(Bg+K)jxUA|Yz$tr}MkW+A!EAMlo-=K&T}xK_>n9{3@5ech9^ z6P_-+6ov6D1tRr}D;J9#?m|~taX_1P$a@joQHp#{_qj^Pz@li6?b$cpkdT}2_P7Un zy#a0W?7NSFp-?4)38GZboF_j6Z&jkiS@(sXI-v((Yes|0Uw+RR2ta`jSa`EUCUXR3 zJYm$%p5PQ0B@5#Axycx6txwEoEt(lepX3u~JOZPo45{GS zq1gt6E)VNNReoJxFm7o>Re%U~BXJ%wIvQ(oQQ(O#L9J!-5wKak@J zjL}|ATwE^7^eZYPyIMjD&E2-SM!`!^Xm_#St$o$1x3!!1S)Tf5|5+1!WW6`P!9V{&6}4 z%uNqv)YnA|_O57#dgSxqQEuO82w7g3UtG0l{{finv|_I-5R`!5@BjEuNK~4y$n7a8 zo+Ns#`tvW>K|@&hMf3bxO6yh^f~ySHo49<~9}UpNbm)5D7W>{s>2wllAIW2Z)XHmW zT|5XTz+@t|>Z>{q04EIAP+QokcoQr)!OVtF8$0*mw?*|JGw9W{zxMng6j`)Y__!t0 zw~Y^G)Z4nYcoP%SKCxcv(GFV0A?i=>~Vhh@u>FMt+^SjBIUfv&C`_zNt)8~H@h^#n z9FmiXWd%jvWLGIUF}JqkV7Hs#bZ(j&D+J2TVeLSH90HRrSlP`VS$y4$=i|&G6^T(TRvqIa2I0f7&!rg}a0_REX#Q z297&c2Z`>V-E{3bFs{GImE$5)9MGohzv=??zXa-NrmWl83;N7~P$EK8ZD3)&cVQt( zT+52x6sNlaMdRJVc$PN1!3DYOPmZamUlENl9vIzgC-4Dzu&L93sMSXR-4j?g{o1no zzF!M|f%~HMudk}Hk^wnh|Haz#mtI@V0Juc+rG4#&>qZg3w(+k!i=lPG>Hbvx`4f(% z2d}W~n!E3ULl84%=$U7UJJ)`BF2Ej>pouuFATN(QJhy1H$0g-?c-fwFEQ+Wg%c8_L z8?v&{>}-#Umq%WF`~sNvY>yIm8TJ)udw#yL4LpZAfm@+D_s+230;5elL4Yfnr#<|QB= z=+1YOSSGng7kSVKZQ50%UWQd1=q@cT$`>T)uHF0etl6lG63Lzv6;6T!(vH3Jt+{Bc zF&IcLBRTp#zCGEZb+5D0KP!7Yc_$;Qcfp(ejquC~UYP z0ubTClilZDg+Wg)jRfFQ;AHX!XJQ1FI#E0Sg3jAuzbSQ)i^h1AC)CtyBYNFB6*8Gy zL;)^>A%DPECgRmxF?7;SId`BF0+#D7RQ^hsf~oiJycfL74fwd*wDX_woh7o0DuUql z+FgG@^5DpVz~_1f)`Pgf7&natA9w`k4(<7j3yg-Z&mkH2Yo|9~(n)~Hfp+a2Y|)6)%ZlO2 zX#9#%l9>t=R%PK+1X!U^EY+opVgwlGk)wLjjFa)K%@I`^+DYj#l2 zA|6a{*{?RN$Pf||udic@Hn@H9aWKO}F?&Jn!FW`~3y%$4>wts}%k~w}cxO=kug0{e z$9Ab6QU-TBI3KSs7}pGR`@Lnpe7C<{ZouU!aQO;^%kgV>Z0f(ZCCVwGpeYgx`An8F zI9$|j&-itHtI+HgGb+I#LVM-imDQV9m>)ARTK}fCzp>6bG#G@+&_&z6;rKt$OYNk1 zwhNLez3Tp*SEj(La&ofQ=N_!s_G@OFi_q_!CfTK3)BEa7*gyscxqsO9@_$!*;k`v1DaCd8a>sCJeGsAVhmF_4 zshC-H&-O8+psPwarQ0=1% zS0<)09$LPx16;Jqz)ci`d+p9Qk2wb>KqY1t4kCA!iur@O>5dm*FjPuk4^7PMxH_qZ zp(eGa0+uD-eR zEs`h<(0s3+oFtfMp=;|4GUr1ac|f4;Eq`nt8WjxqVc;;cDh8#Q&%87jHbL1}ci*oa zkPa10YX0jpt!0iR92hL6V%HSTyOpMFMZAPkidB24_M? z5d_oc@T1OrsggK5h*z}T2o)W4w3+Wi zoB2MnneStp`F7jP_leDXdu-k;Z>9jz$e4x4!2v6=5HoB6)CneRrM`F^mO?`NC& z?y-??Gx6DFGv9kQ^X1#j=eCh=6SePaoB4jVneU*@e1F);_XM?XmyLWIDc_G#^1Y_g z&>z!m=9_MjkNq3#1XXwF1B-mDZ*QtJ=-V4n^07_XPxUb30*Zi{>@2W<1uzb{A0$2Jf7 zwprw3dHGhQ;qti6eCurHTW>SpMw|Jbu$hl(v+^@WdYPvc<$Ka5-luHld)j8cEf)E> z&Frhtzpq&2V;=mZ(va_Fi+tSX-&NWc%J*B8e1E7k*zxTa`Mw~y0*lM@>H#B)W|;S( z1Dlliz@7fYQ2okjRBcGT$niPBJ~hB!P{l9`+OCu`tpV4d5~Ex=rxh;NaW1}9-E^R9 zs=BX#D%ZfdD!y9b+Gn5%HNK^)!N_v3LUC~w;aX+D^^m%M=(PCIb-+Lu_^HG}^#4T) z*Ra#823H?dKWgs)0iomeD#A5GRxjwfQ{8WEUNv;hG~i+$7MvA7Tsu^sp}#mzK<$ic zNt|$fWRi_{6cNQXK%8*>ZopN8@a&`$IHAjH0ifg8 zD#Qg8z_ml+TG={2vT@Kv*N21yH3QeFO0lnKTXndYhszXQ^Ey`@F8D6c<*iOXbad-c zb+{nw!1av6b>9V5hYM>8!1blVHM)1z;i{)_oq@?hItHXv9WG2&g02P%S8?B}!-aWd zBd%!!s}5HKh3hLN^S516b-37WlqlJlHlpfq9i!-SE4sdMRUIyf1p4a}g)6tP>Tm%M zPNu8#H}<&3RRa3*7|SU|c^fs5)FMhm5PiUGc&7gNcWq5j~76 zS;=A7d#Vl>!g%nIaZOrMb-36sGp^0c;)CmZ6A$+hJuDk{DmgrKUwm+VXTtS4;X=*e zA&Tq$4eI}67aof{Xhl}mTW<}T9XR8hu+YOct@AFlM3mX-o%MBC{ zy)VTF*ViVQ$G!m63|t?fVEk3xuGT=hJ-{FT2bk!<_%k{dB3wQbxa#|l$Z7_D{ z9G@6qsQ*=!fO)pF)%^+Y+NoV-Ru?N=ZyRu-My$=^3Lf(OVW&9Z+HJtqi|YT`fD8Tw zN3SZx1zv(K#?|7z`0&t*F1AsOtIqrJ!L`f4L(p>%o!nnH&^?at1P6u1z66l0pG^4W#ou|`zGM&xo#N1g^I@{2Rxh0az=>!b4Jx=$y;u&&Gm)AHWaP4}O3T;3;5EI*|^%pcDMVJ?aGx+=EuohIWHr z;5%r3p6UY)-~-aY!56B_!*leE_TU+9hRmS-pb5M|dEBENhjJ0-k^^lH>ex5Kz5KH za)Wj!sAu#sWCnPeDH!TTp62Qq{A;7`(GIi+>5xN|M?1kE^!3?vA`LL4gBI`yFysLY zeT8-cCvc-Js0YvJU$h&%LK(Ch?FYY|bOMHZz)%O$(MR-n=nXp2PPCh48ZyK*0ypFu z_yA|RAS1}n^nyoDI)RI21Tq8u1BSf7gYw`h+RgfcXXIi2gB~ZH$O9RHyl@_tF_s~e zgWQ1skRjwlI~h0n8S)Ca@o>;XPdag}qpru(6*w=T^Flf=qH_bC6&vJ`v;K=hXR zeFyEuRN2H}Hq-80u+&_LcKW_a#g11i_rL^6FlVzs4~7IWiT8X2BxleiIjOWy*;nE! z7K$FsgLi}ETX$4aBxTa8v_5)oESTaK>}l0nNFt>cyYbe$yFk1STu3kM`B7B#MX*}& z%9drDA+9DCWD_V@GBmBF;awq%mwzljr;?Z4QUoE!*9W28;zh!i{ECcx8K*63XesPq z7QG{a*G};Ut9<9Mfg@)l}=3RA18vWMG-nyQ{`YL|yFJIMM;3Uvtc;bfKKppIiM z=yzu*7-*kJ^!SN>H`&HPf}Q};RZ1xdS_)k~L@k~Q=`5piHB{NdrH0E7rrJvhKe#!L z>W&0IM&V`3GzZhgT;P%pvY;|8wmv>Vl^P&qAceSGMpTcX*7>!`lvYvtv8EPU^S+kK zRjTD{ms9-(f~yRT7Y#Xv+Ea+TqexC6sZ2wpbjHtIwx;1UMMJ3kgi4Q*@{Hx?un|ksRF|&vP{s9 zp+uv!QaYaK^{`%KEB$qlN0WNNe5x$}x#l4xWzs%|Lrx0A#n}6ieg%XDDJ+E%1tyAlUwdnBd1o|gH?T618 zM=g<7Q}3Nf>D+62FR*-u`ymHK^pYp&MV(f&)nxn8ns_9w^*L0oUYsaq%Z9q$f@%ki z@bq>utiFQD6xa@(Ms8t0ikG<_s~#H}>}3bVXR;=}KNGYowRF-5XdH8#rD6)@W*^70 z7AY@2^2e=oP<$fqhiFE-Xf1oNqAWK_q80ED=L>rPD==0_W-{H4p?j}3K*_Fyf*Fa$ zD(w`Nrt^z&#OA{ohi>zkJ34-=H0A)yrp`&@9dp&#helo0d+c!OU{Ar4l0khwmSoRC zLj=ji@RUX>B{~hwRIVO0ChI_RFliM1btEs+h2%1YWUD7VrBF(DO6f^w3fZ7!I@9S7 z*Pb*+MNVA`4wqK;3PxL~_geH+_QcU?W;>8Z9Mo-y5#LA+ed?h33CZ2VrHQRW21);9 zvW`VmuN90V(dg~xp4Hn9O2(1}fbO+3c!QDDd)>52gspL$C}BUQQ!1v*&QfjRwi`VS`*GdgBgTNv>9n-4 zRh~IoNLB%(EeFk0N*?fU#Zd~!H5e0?(BB}USIz;L;|tv@44}MnY*0qg!M`|m?@%1K&BTXnPVFw2(J{1GB>{ISO9-XykBAkP_~ zR5HzFLq|uEe8Ccp(gxEx#(F8B>X5%6)!JB{1r}Af^(KrweVB;NHy_qpA{$Dq*=0 zha+->lw4%19+v%l?P8L?07<=E*MWzWQ7~o^da1f3hY@+|Iv0JW>gf4Hj-o=XV2aQ( z%z(q7MNW~afVqjVQWLsfx9YlqlvOI&6Ox|oH zNh_icjKjx>HOO%mycj8JhGtdVvSBJ$xRr(+V^t4ahTOQRR$eD+MN7S*eUe1a?L%7E zo;-`)7PpHbFQ`MzpQc(asl;ys1+hCz%X1~6>kX61CV*c0W+w4EU(k>Bz4M8}fUrG& z5v%(N8_%X9MXrwOY3Zsp(XBJLIW*4Xkx%$&C&N~)tfwiYn;6+hT}>rD?L=os;x@)W zors5WCKGv*>AtJbkxw=RGkOjhwMo8L?m5?1-E3WCoFnJ6c@1%psv%r5xPQy2m#}BWLAM;6%g}<2WyIXnVkyI0+!9wB|#vB;k>+|-;QVAjD9NHxc zQ|0Wub!!|N`{n4hG6%a6Uoc+)-bq>SM%;u&PbUac5SMi$NV4K)cS?tqPoex6i(G1p z3XVl0NqgvQuP*PGsoJF+hDOuoo?@$L_p87AG+@HlG<+0)RnY(I6~ z;+TfZR6Os*R_kKo<^aNAjLFRShTGyR>yS=?LmQz=hHE&FKkdX|vW=l}qmd)+h(FcNC4ZRgy=`Lxc|cO}*x_RR_=6*`sKbtvXLqxpHV9oR=(vm+VF8 zypn@rL_7AC=VHzClNiBb&mdwYMB5JXt9I(+y$_+%hkc3TsDR1bNg!A$@iIK$7}dt;bhCBtPL>z5xSh!2VwSfHX`CDtW5kTe1S4a)4gs%* zdyK17C^w>XhlsN(=5u&t41CzbfG9|=s3I~(M1(N`+9Ky;!&hG;MaE-oQO;Tujn|jk zs)?h^OKIl~{bMktA;qd}xNT%e2g-riwqmZa|AB5p20W^iEQ{Y*<*%)(!DvOp$Jgf3 zC1yp-#Hd=X&SsJ9f!>kY5Q64V>#$P-bEA4RBg-ThN+nRdBg-X-atXnb4ywTpKUiuZ zf0(^VA?ZP++(kqXkkuYSIw89lHDV>B2jxOK*3OdY4so@E+F=J@Bb6%_`p4O-nJt;o zX32S?aGUG1RU=z6%zcD75=0a*) zf6i8ZIv^wK9Kb zL=Z{Fpt<;qE)T4K@EECLgoAmTZgh60Kl-02q<6627|miH7P{F(=xM6R1)c3qsScvf z4nF3jUCOVpRVzpFp}GgXflUJ^uC!GTa|3n=BSg&V;40TlF}u}?c!BW^xB_l~Gw^I! zHSIum9Vjon!Bq;MOQ@+^m=2oAe5U1^3{mu!3%1 zny|+~&TU|28S{KSh;!gfC%S`G2VcQOj1d9F=n(M(xSLFvrrN@npmOOW8J^#3M;b17 z0gV+itC(BnU2MDxs8d&N3mebC$x*&>AKWxs<$2Vh^EZJaLtamsZmSNq1hG&z!&c2a z|6=qE;c*1y@9^g7D;h7^8zZ(Nnr7OfE1Fbat!mI`a(Fe?sGHc0>J@%UpMz(JasGy_ z5N230#=@>Qct_qF?9i^U)#8fUFw0ggY|CKFv0oT-GT227EtI2z9;9iQr9r%oQG?V* zL|E91)R}A`w9=tn8xuZw3XCY=K@gdBp}G;V!Jhz%bc{$~H?h|lV-gwLb)fXlgzLJP z@S**34>W8F;=vU9LmOb5fe*8Jc*ZIOyc;YI>@;R&F`sw6!lz4twS{K=N9^dM-i0Q} zH*F%P++d3q9z%vo9infn6GM*VOl&yj*|zFuS-@^&@SvyY7uaP;1m^RS=oh_^PMpCE z9^?i79&@0u;aI(aUB1y4KBgzq%$=DIeeUiiTlI7Q@VtEjwbY^AT*-z%@JQYsRtoXUxY+s{ozEXe*ieK8<=B z5g%e1ylv2po>ED7p+TLA!-#l#5G;vs&9jA%<8-~9^Hn*W&pcNi+nyrk2ll?^lfKJ2 z_VBkOBcIs^8FIna>T?~$wCw?EqE6dvmqy>2eF-ugB{xKw(#-TMAD#B zV5apBTeY!F==Fs1V4b8N zowg|EnS7mMhjy2(lKj?0gJMvtB87duk1?$&{94Aw*u6LcaQgt!4w zhmyF>yrhV!|92>@DWBzzf7i@U=32 zl536_S;8kn`!N3n9Ykbyk1c#`DIl|DG~&>A1zFA8-)pN*?p2I{<$51{XHTrWkW09+dN|-6#*{ zF|daL^Z0nf5E6%o*`eKU3m@;Iixm4=Q=>He789op)L zRV{if$h~5efBl_v;|e_1{zKotVlEkTC4}h9YFn-585Uz3;P3Rk6XCem*s7WN4;{lg z2lfHsT?~wWF&2gWOrvME`7#Q}SRA7^ND}s_bR%4k*uux$G`>ad&>po_mLm(Jy;*Ck zWJ8q;mKr@I_W`>}wnBH}>EoowY}L!$gI|$j7R+bBj(zZ*9kn?-+UWf=}bOx!w zJdj-3z^abi&xOeQ$(ZoLlF2=f*bM-@@HBGu7Lo{vlsSw9z(eG~OeEwpiEuq-3m?Y- zQkUcxY2;TKp0-t7uZg)7%yq(2$*2lz z9iSUt7h@vqk-!Wo#!&89H(bwKxv##h5rL<6XIyho~1LJZLw@5}5gy z9vU$WVr0DE3_Am#jJO##<|SMB*awET-TbXMhql#LZFwqJeAc-tHd3u|9;Ru*GaM1+X#URC()_b{(o!#+gbmmpKC=FR)lRGUL}KGa?z<}`mB@-<4egvy)n0>)oEP4&L5&er8-J!j% z@WtL=a!&nd>?5gcf4vbCZxJ&gs>Emy{6iEAoxt3NeCrJHEh2WzP|ELVAsT~s!U~2% zdoyO=~zZ`=WVwMe~BrZ*?2L3F)B!*dXOdpXb2JZXme3nrDqCE9&F#<2vZSD9HNk z<^DwFj&3`6Ry0zb7^xcDu*X)d)-zRRo~IGbpm;LX`KhgXS<~h2ICxErC*Z&2{%7p| zzz7{OgEb1wVac~SDtvZ5gyM&qN1mM7N<6_4TAj~M4Z4GKDw}% zYoBUUbgALh?a&d9aW{Js$+27PHo;yeeBT*w@E20;pWDK4mdX`71}oaXu!WQ7vk@Wd zUuA^+%RR)o#8tfg;n4Qms*gFY*I?DQE9m=C?dj}EZyDphgSc--lG=>^UrRHRR-`o} ziI&e@)N@z$+)X`qSI<4fbD`$aiizWHQAY=bp}l%y9EeAn(cb^z3NCSlwgZ+}V#dsu zYzyYe87A?Y%W!KjpC-$66m0-Sh#nZmRCWx~iSduD8)GES$M_IGF^q9wW=_I71#w{J zQ^L45*a|>GTMFMJu_3w%Ey37fUu2%>yuFIJXzW29bL5(tu8L|NPQ4UbJI3AI2Ri*a zPndp0WXw;NrK;j_XC-HlR^XTNYsL3?@+Ooo@vJ$V>+maPt|L-m4l~y=hs>~OT*ug- z^F@)%WsV@*zO`&dbOKL3WWt zNXm7FUMp^L8)O>tN=VlbeoGH>g()qR|5&Mu)D}+D{RZ#=6R2dV#yX&s58bX?Nk3vT znJ>CsuR7_+Tt=+YkJ%Y}(r@Mp>rrGM!Z}#eFb1`UYq-#z_-L9@3!9NeG3rKDXrJUL zOYr}1+Go@yaGrI{%5HF)v5b}e!3v-*UH`fTV;()O!n%vh7hV4__rdvCGBIvqn6x>~ zNLE>&!@ZC0^D*j@C9PvE%*Ajz+h^>wkT5A7z-3=E%=QWMX|gsWf0$=Ff4UoZ#-7D0 zCc+y%d$)L%8nBw;VNqI=$tUuX}iy_p&b?%=zfr^PhB>_3xi79he=K(x=-Ftj9>0(RS$e zB%1B$VX!gLY-_YJt8QB{tHrt@qv+6aEbB=;G$&N!tFC6OgfUIPf>{o%9!MBl6RclJ z2y+p;KqVwL%V_0)xNgSAny=$xNNl*U-e#t)Vq7e3vEpKhjNJQ71=D3e{tT4{%p}3{ zM7PprY$(O@TM=#Hb{nNxQgq$4ihGcgkZtv0@!-UsqN;!NG8BfU+jBjsj*^Q>>+l^`#9mq*DajR& z4ABGem1%opL*R`r(Z~@l9fzy`p)ygq2;fNd3rlN!Y|VfD0xyg4v6a5)qkY{6Sj}WY zDp{+e_X~2ert7l>fU>UZ>r}DN=A#~#L;JQ9rP$ZSW<4wC`I-KTa8=!$CTu?J8_zjH zry|Y1%QU&N%K4?;wwj^Cek~cd0S9aumyveex(qlH3BOF!XaA)yu&zg@>3Jawk?NIc zdS2NZ*7eFXW z?7>5A6Z>O*ZVudiOyOXNUwt?TQ*O58GIgpzr3HL0Y6-Q(6 zQ;~<1W9p;fA?4^>jvoIl9nCc=U~re zEEQ|ir(4Cy`0QK!;bIOA?SVbEUR%&pF>@h3(p6#|BXlmq%A@L97TTNkY_8QxUsZZj z_WjW~%Y7MJzg1n$dc+aA)!gRF&Rp5?-nt&}$VQjcig;yZ9rV59x^=LYCZlJLHh-ww z(&(|7ZkM9(L^JLHw~G2>=^5QJ=zGX3;#z30=oV6!gZTFe%dy@kum}t_>Nvh&VQ+?B z=Tr24i8e!TwAuJ}WwiOqe@e`3trg5`y$2#`1&)%Na{k!b`r{jTcD!%At-l^)SxXdKu6S@L zH2$f&nva(C*WYc?ds|;u549EcY`<}(o%P9TJY`%B=e25`zgDp>TFAC7a^JE{GHz~l zY<44-{$Nb8t)gNkzbf7Y$DVL#FlN%Q0whN();k7yBm=&4e%xD+(e+)Ez=1yFGBT>N z#)1BbRG&=KcQ;B-TGu1f^t_Sh67ZEc;MDWVzPGMdrXB5Fli($8+v>0-1|&;Oq`mbq0q>k-fRumfpXxSxg$a3l~aFKqupwwvWO zvfZw1OjLC>vpz;{GxPfJq@`jCDvL+XyvE1Nu&u8Oe*!Jz`VY^Sv?0GF|Ca?uNLVw+ zx3#!#*-zGfK&Bx-PFP8lgiq(v6?+`)7)1$`!>&&*S+V~?9EP_e@s1hvxjU7WrS0tE zkN3BMU|rbq>DI+6E<{dHcQkEF)#>SQLDzr!!*cwe{@8m52EI3Z6b&fvay5Eq*a|xu z^j|aw%gtlO%8bz1rb&COzxxF1C3}oV4Mt2yCYs~6Rb+4Bo$N?U)x~lwt?`eG{k8WqwUw zFo&)N?FBW#_z7^ahP#kSk5Zq zD-c}%NW7EFxFU~a?9WPLjy@Wft@x$C%L2~9s`jM+`ys!xF0D5punIMQaDOsSo;`bf>mODS>{dq?+omFBo6c=D39Q;mhv-5$5k6>t|M7rXp^ z?N~}fdRAGMnNa4E4P#Wg@QaDQdh3Au6iD-u3?w^Q|hgp(Ih?V zx~m3PyLwRNLA10hm}--sp>jKU3XGPgyiLf5TNOypL$-Ru1z@obh^p(Oz`@O z3!J%bzrV=qaRwEQ{@tWJmZ@u7b=3r4PN1j0Mg9_ZAUA)EyTm1+Degj7S#cobevT@( zQeA^wJx0mhe3cN!cBXBf%5a*ghKtm*c8X6g+7V{?FjhF+!|BTNhNU3pqc>AnVPFiOhse$%=oqH1Zby#TqsRFm#8Zj zUZixJsTH=BGcj8wfl9V5CGi-dj{+sk%DVm8F`SC%}+Lx5{9) zp~mLGFG134(+Rs$lTK(K5CYDXK0x<49GX*IHBHEyQ$Fj;r>&OL}5*WvK1`@~Qk^P5{&ovQDtP}p-6MwU!a zCD9AQ1Tv3~5gmloAdier4f*>Zl@9dcOmQcB6}^iC*BRnYvVE?)hZNMPHBgg3-=&!sDUrd33g*vpt=NYZ}rCM+P&OKxb<@ zo6*^XPIMx|?dEjCOf;nvz73HyWC@0%JDnZrgnQ{mC!)zy>4f8gn?sl22sbl>WkOKp zgnAJyqM3RB#Gx0r@V%08XXlf;UNHH@{gq}acU!q?fl$-4=^>7d{oliN1}r_WD`~^D z@^?C}`~5~^V~zLR1YFS<;M0g=s=5-Nljx11SQ z?i86NSa6TQ;6Uc#x?(H_F~$*IjBy6Bts`tkrkJrsV9J|@Mnd6mgkzI%1N;9n6*FVw z=E;J=M*e9k2Fqjv8;WtyU9Q?q^$1Q3q^cC~`R+lfp@Kv-47a#GpdH3ZTT!|?xyHO;AN0lG1-a8*Wp4Mz++7VaV} z`>>i|3#`!&D%Wt>h&+*nC0x|_8l^OHLXwdlM$2hoC78MbV59>@MKL45f@Q>BVV@g~ zxa@FQ##Ir^W{Nhz%J!G+Vw)z2+YaK0J=uZ^W0H{<&<6uApl8Gj*~olVKl&A}m5;_R zQ!br3Tm>`7rShRJ!5kxi+A2GO?V&*aD%uK&)=>2m+dU+o=6syekqntIrZj#L1)Z>b zBF$JSkuhc)Cm0JQ!0n3z)j=RYAP_|^(t}cQGy-$Nnjr*GX3!eHq}ocg>69Wdj8aKg zXH^iF#xHP#1v6BkaD>e2%T!q~K(N{fI17T|nxV3YMnip>*r@7zjVcvXUn3x_s$nDg z4In8PR(O$x%*M zbp$Oo1L%s{+2(U(1sD!oan8qsID$1un|}@g;Sk9(79gXMnW7}u2nWuw+#=$DtyqrA zghzrs$Yw2?*)E-37&WurCp)%&FYp@pQF&h2Ld3kV~DjX|(+^XZq;vT~i=btp? z`b*n3yNI!%8m<|`m!T6J9jww?S5CUu5r~1&RIfZ?C|2m(mSU8 za8HfYMSs4&;G)YXe-2)lVeBEzyucIzQJ&^2a(fDjCow|;f)zC>QOs!SoWPU=ju3)b zST~biOq1zhznmv5fdC<#Xi9)fuGl)LR^okWx8(-<{ycQY0u+kIi6dmP*s(G35lz+( zYVVb3G#z>J60|y6UGmQ{+p~rr-nn6Ki-x^7ZXeh6yK7I%<0hbTwr7}nDXQE5!ao*1 z(R;&FC$_%nrcNhV!H%XqYesGCdmuM=$7?;(uUYx=uTRx^p%-X~*1Jdt9h*-1y=C?d zIjOfS&tAFnsc-sN!H%XqLx9|Tb-hp0p6QWz&HQ#ZCEU`iBie3?pbY@7X!~;{lm}e9!YsPch;mE zzUr3?SGH8$>JuUMQ}SfFeJQp zo9FpQT5apQy4o=f>I^(~vlZ-U+A{>AAMTqmxcSd>Q)h3uEcuL8w~6_kXuZp{{r+S3 zk}oE#Pc0A3`QyS3KkWl;X4uiNXJ{V|J2Wh*b??@X-+DfI)5|T_@B87BFF}JD7RhcI zA}zyhFu0y78li_85M>3D7o*ICBv?FP_5AE??RAhS`I^UcRbreJj{VEIWzj~iAf^xkG1%Vs z@%3BhZho-$@?m#1yld;6Uy#!df#W>uZr{47&uCsUwuYQx%ju z@Ab+Mh^dSeZQw9GhhoE7Y7IuIwd@$pv9!4G~>k~RPLK8FrnI|^}Rh2m}Hc&uPY!+}7A zaX{V74jk}kB93&>5%~Doy?4w?>~qb;omUnfZ1#;6EKZIEx&XAn!zfEZUgn#mMe&JJl3KQ2%zWBQ>Uyfe@!p*S9P?Ih?wOM@v(5G`+irjG25tfx$hH>yEMCm0y?tlz z&WZEAAFZ1<>#hM-u-IiD%OG+>t2Q|111Kovg+OwQbZg(mgLI<}Co1`Q} z{c=JGu!4t>8X^e{*8xiFW;FhNQSGnN?tL_4#^&jtG`E7?$_3~u5Kv1G4WWmD?m(H( z;~e6m?ccSNyxwBB%Tv3yg!-M>Pvk5rbmn_K0iUF+VmOFV1~tR8wL8Q;#bqSxO&ttMw!u}(eG@VzxXLI&zr=ozpBUrySQ zoVAA?AtYDmLx_oQM`@q@wQBj!PQL!r zpYD16Q~_UA13jC|6e=*J_^;wLS$5TUZ~U5}1~Vfo?f9Hd$rPGot_@G3#o_)6N-r z)i0}(=MGr5vhIvMOSuWCoUPL-bU)>%w3*FsZIH44#nl^%+}Ad;f*pNbg*=^@eds&a zcN;QqN*&ec`}Ma}7>-33>>zFg6_ z@sG(@@9ETNz-2Ek06dx$BOTP7`{kZj6LuE$d*b948Gp50(b)>ddS+jTTT{(yu#!%1 zN0t`5COLBh^af+x_c@LDDVMc^ON((7tVt&BubBec6Ya8zMfoSd8BGKtBbjtLA z*I8KPDQN5LU*-=uN4cH;Qg?n)VG#}As3xD=Pj3!7ClnPIBh6h>8kp2p)4)_5-1YnI zateivjmI-Kr{ZdhQ^<$|Tp2a&{XO?TdP~+5|5y0qxMuf$Vg<7t%w9@`LkF`t&hR%b zd59XO6SWmPD5^6{Y0&Ls}_Au`{P=N&tM&EW>>G(eL z7xnaf+x1>(byTDBcXN$+|0ZG>+n&PCm|f$6M{fN7v4<~BTlig_UT@Eu{0s9RoMG44 zfbIu3zv1=f#kG=VZr=CS#&0`qwt^jf*VvL;TI-SzPEDwLMeohKcFtN|@1{PWB$5$9 z8V*q7>N%s%N9jYeHm6rF$Xb>CrxonzyT(S;(&<0E(BscW+p|_Y-KhV(&*qH<1$HQ$ zT<+Pnpy&N5i}${9`P6EC`h!9+`0MR?W$GnQ7af*NXU_NE974Osjd;*%7cX928SK(_$YfqLej>@88h!0 zT>rp%-wN$8!)}$;iQgcn2GgV2HOjAfIO%g9&g3yJpDRD$_8q=cWZHtQFk0&%u!5Tq zr`VM;4=zbd{P65e{WiYz({D@GogsW)G=}}%oZ?6te@1kQmD&ZgxZBj57rJXEt$gOM zbN6n2ewC5U>=ZE>Wp;{Iu%qu3F@3*x)`VI$hdrLX_=(}|ZtLG-J7gqUA0r*qn4O{( z?C3j1C$;q5GkT5x-LtgM+^b99>h#9PB?PiXq1gd~LNn~&?-W6`*(qAV{`pQ(NU+H% zTEYHvir|Xb0b0TSbxslAB6#@Iw*Gy;p5OQOx;qwncfGNPKvB&}{G1{_v=MOcl=&a00vFjHP`rrHLj(#`zmz{i^HfR|)0nOnVV5`xI73}CcMG*&^ zMtq>8BBuyydN)08ao%-rq&zzB(BS7v_P=fgJ99$F-(0uv{XJ7p>vaA1i@_-~>?}iL1Y)A#P&Wbw zhXA#iA3;b=EcrO@Ea^(EOIy2O{&NGela{VN_4{fM54{0YL}N)jc2cDQ2^|4>3IC0_ z#uWAC&4H>S7L|zR@jJ>G(LBzf%}+5;r1g0*tw;ZEkM@0_z*BenlGY&`KY241cJ3Z} zX6B%#?=DJuaNp=LfBwGeH!E1|D%X)}HmO|LckpcJT>M`kg!otHg&VNt&(m*7NxyM* z%44U0{q3~toOP^Vmca)UF?2-EJFn8+0cWP)+0W}La2FiueN?AYvwq!G`{}Kp`}=J8 z%`vxGN8Mbp+S6)UWR;=_A!e0IdvZth83TGHUq7{U;iO>& z+qns74o4i=!QJ!qZIAT7qFeg(gwgdHPu#i93KqLc0ZZ5x#3R3w2V!Ral=0i!%YRI} z?$2khskY{mZdNeMk(nh8M}CbC?H#iBmE#_*)2ZLAUs4|JJoCIYRU$Nv%dXk^63eww|=^4 z@U;{D?^qck7YICyLr~Ocdi)TA3(n z{nhJN^?YMi+8zG#TYAr_JHyx+97UZ${M&WS$|nbXTRrjN$Fk3xesSYoRY9dBVW*)r+rsHhspl>(2f9taGbd!H#AW<)k*Q{B6cL-u9_|X7$=OFfWi@ zhd@W&$n2#Vpoqa&5n4zGYxouNG5k|6YiRyAVuUoZGLyp}UHj&Xb01Ai+Wh9R2j(|8 zIEb5o7EpcSXiUF@Z*KVBibji)Z*E^YeEJQKpK1k*laT?d6lQrbwkagR;^8?}IHZP1 z9)`ne5VP{dCfgdGI5Ktl%0oTZEqVEAE7;%J$e_JXt)I7e!uL&*R=s!Z?50DSwz7gn zR?d?ZJ0r3?VuGO`u*z;L8o-XPHcw4>;L!bbGiFR&>ss8V1R+XPMU9`&$0p8*>Npqe zpo8g+sE%7G(`4kNW2wBzkGj+SQ1u*knYg?4M~QDZ=?`bF zO6Z>uv?ROBJML-K4Hps@n6^l|x{yyfQNbV;+C@nJ>Ef5*If4uFk#@chxki1JC+5Axwv! zd8qnNB|l_7Uc>$L{<7pZtzeOQvniEN_PObMfczP}Jh>4+(^Fa|zlcYRy_$sSpTslw zvh8U<#Td(rtzPDmAkzGaDJ$5us(@LHEeK~0WGlkqCqh33=;)$qo1(5^mxu{rIdy=b zn^hJQDCQ4;A!{^~6;bMEDkL#Wz4`U#h*F#`aoO7K&Wx@MdHvgEnuk5&XQ|crAhE2F? z*UOiJHZ!aRDpSWHTqzh3*RWT!4(r1^;)C_5U7-?}Xr2KXoOGH$%wq+MJnEWCHQ->$ z=4ME!At4B`aU*D8n~nZ4fBgt`bf$A-(S#n`KR%FH-toP(_Z_ETcZIEfGf%NNshk;h zJt|X&Xb}2s5CMXFiXy&s=FFbpDe{bV%AB`^R~!+CWD&h_rFN2<$7^h} z&;*{kNTBALraR8Xl<4tpOP&(2fP=J*< z$XsYw>`NJW`EO4qE}YZ#!CUT|DhzZqR-+u~c>js>x_w=Lb<%Cxb01dQ@L8S}>}Y!9 z*3`y>clx*g+Tr-V4?KB$%X!b;H5hHTL)(4r`YqX7;TooR7}w&6 zsCd}N5Z`f|`D;5ytz=u(jGFZ6@R9|?(mq)7m=)|Ww2~<|H%G7|!jI@( zPK(xy$bu83yww^U?N-Xp3mbd6prvJW|W|GOxd z`f2*T^AFUXFyir(tYC*BPfWSFIbdg`Bg9(Z(@5u)jmbFB=eg9)KaO2g(rQ>P3Rct? zpySjBnx36;>C;*3v?XshIOE~!Rly(!4zISQiR#M#AFB2Uh~3>73^rrCl)=-3s~SpMYgtjXD_8a5FBJuFV-dCLY$>)g= zUp;eD^0*spxxUuS&jy2uTB%`nhLf+db4OYvrN`K6bg zoVdyLTh73=uVfu)Uo7E@m_A(3 zrgLm+`stp(eoJ1{+rOp8MQN**wHjsP(!ncLE|f8HRv$!7qNn2!ikR%aS{J{94SW5aZYiK zm|)0t4Bd zkq$b{A3L{#{XGl>rlQOrs0S5xs5E~Q22`41e@g>_RnW>92oU(u1%G`~`^;~$7n~Eg zd0R%G3#?%OCIhjCXpU$gI*|2<*+4jNYu0MxD{E69zvX%VuKbs`S{aDegw;HIYy~@- z1|oslXr6^9P=%@kI?S`jRzLG_&#W)H?dg2es1B0tI|04s2`)TzJ-?i%-5W^hNK{)EsL_Lgw`X~Q0Q^S{|cOCr&Rw8%jyMa~g@%$mxG(EpPE zTDZ5`N9Q*w+iDT%6hEqN`J;{d(7C$APwktYG#i*IkjKD2G92aNSO2Vt*c>P}JWv9o z!VWkb5#Pz#er{61q3XvbuYcg-%iJqEE@YXDDE2$3wuoY1m%2FS=={$8n(ySt2d2*c z`SV|1J)uhnZUWlPlv}O(S-~<;NF5;#>InQpn&yPpyn2eJL=t<|Obv82d1>}VBX?bq z_UMM$$NyZtRc$NSFfKsXP}-)d6y{v~-kU(%abWGCGT%f39S=62bMV$}gR)ocTln<$ zv9G>v1se?{>Ik9j2u$8#wfuqK7hblh>4>D+i}o~{KJ&5_Xo{VF+dpH~N!z>bOMSfS zI}JxBwHEzmh7~Hha5+-6G0KW)z_+e&u)Ro=kMaJ<*)^(K7SM>+rIZ>R(YjP>v2*LY z=Pg}Qva#Cjg4wj<$e|@eK)n2~r>m}1J zEz8)r_0q39U3JMLz-WgT=AE73g&Bq+A`UYz@KGqDJk3|+_7oIPVur|<^=PzYdS^}R zf=cLMPKXCI631qWQ>M$?uwTv-mOua@c$^`D0OtL)D1>y*gJP6YZMQ?)kj-5;j@;cZ?XDM(EquS`{p&!R8TL=IXO)c{LAQAiqZRCk z*|TZrL5l;O8tDkJXBZ!tcaEZ9G^vPaSbCF5j%Zl6kRgb9820Ut{U_u$y{PYXf8N&Q zV69rsjfRD3w0cv+3dRBo@P>rZO`nHu{Bimnc}4G9!I)l@wH5=eJ^pbN-YLu7 z`pU8yk3O1l#{;XUH{0^0kiBSPfOdio^Z#74g0TRb<0wPaXt*V*5DW-g1Bm}WjXQ-1 zF#pdy5EhMav;5CQ0XhQm68;-e#N8_IICW)>s&FFe{*-zvXEaIAy6&pM)$ZQCvj-*- zanzHS;IIBQ&4_YePNc>x_tP%Py*P30$LY)Jx7qN)1=@KmnLx~PZ{^FZV9W%RJyLSd zZM2#>LOb9)&2a?a(ZmAjpzp1^>%Lm_!RW;DGp@g2e#(ajtYC4{2POlk#bN9RhE;Tx zs-|*9A`tL@q})ez2IWLiM5VyCtC*GI!AE{;+<$UG+TtNkkKf+(g^+)s!98U)V6}oB z4W&RI_kDt47ViaK zrV?0@4?pOM`q}o~HRAnN*xQc57tO48R>qn$HZET|Z$JVQ0=ifUFbXj*yj#JT87Ldw zGsJ%Z-D27G78WUkeBe^i1MGW z@>U$sL^SMcq7C*&RmQMich14gaW`I6NX|ir`Jbg)!Qv$6@!zu3fCz|XFA11pw%z}T z(QHKHzk_t}N{~fIp1cGn`o+gbVpfXrs|!}NyQWvh-COQon|tF~Ypj$43n}IWe=FG0 zi0WB!Poy?3*gJ81n+7kZ-&^OGj}||1lGqw_D#6YFvkHu>NLfIid8lgzi<7c28EBd~ zjQzl{imsJ*3jc7WAZHL!DKOU*vr?osyX}V^Z$6l{ZrYiPx3@a`H)CfUqj~{zidVb7 zT+z4jkI7f>>C|YzWiKwUf*s9uwNt2#U-zv)v*&@YGUv?t(Ld(kh^AwWFPcUQJa+IyQ7Y&j}ZN2nLfP*5Z1IH$NqObE#p`XErC?Kn=Lb7}n{@1Hwu zTfdvmf8f?dTYuaDxEm055k9YgUSLMdLip$(iZ=rhd6}d(gyU%mxyFAV^zuQ^l z@dwk)6HLy54Kha;GuA5baZi;7w*0NhBsbIz%Kobw#|zn~-?zOsB&>GbFOib@0L z2|1!K80Nd30k6|v>YCtj=6g#@y&ktG;CH$_1<(GY7fj`NIP;xJGAjCy$RBbU4FmY-!7f1 zPxH~w1h4P%c8U1`udnSG?S7ThZ?38G6vaS|Kpsoip#ZwBSd`R%tYE13cs)x<8LVTW zj4{17J=1iW#+{96RO)P}_cW z-MglC>C&T1V*3tVx~HXf@7|?Thm?+5Bat=Q!X`2pEqW_eqFi0UBXN8}LqqHf#ZfMP z^*vz1A~sXNW$M~OUFA*#)RUW>D;`qZg|4#VK*;^WD)&-#Wp6T+YcXF}%zG;Fv`al% z_fKf~%Y@%+6^>9DCaSAgE5|*89UQi({3sfgaAZfA%IaOFpVxlCjakbU_MWovq2Crp zq;iy?(I%Cc8;#hPFv>@m${y>ojvv3aPTJb?20c%IY0sR9ROVYyd7FYEj=;f^Q!bw9 mhlX$31$16W=S6g~NZT%eC1@Pw;#aRg)M^x~XJ(vp_x}SHX0(X_ literal 136429 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 diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 5297269a..6ed8e37c 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -44,6 +44,7 @@ void UInworldSession::GetLifetimeReplicatedProps(TArray& OutL } DOREPLIFETIME(UInworldSession, bIsLoaded); + DOREPLIFETIME(UInworldSession, ConnectionState); DOREPLIFETIME(UInworldSession, RegisteredCharacters); DOREPLIFETIME(UInworldSession, RegisteredPlayers); } @@ -74,10 +75,10 @@ void UInworldSession::Init() Client = NewObject(this); OnClientPacketReceivedHandle = Client->OnPacketReceived().AddUObject(this, &UInworldSession::HandlePacket); OnClientConnectionStateChangedHandle = Client->OnConnectionStateChanged().AddLambda( - [this](EInworldConnectionState ConnectionState) -> void + [this](EInworldConnectionState InworldConnectionState) -> void { - OnConnectionStateChangedDelegateNative.Broadcast(ConnectionState); - OnConnectionStateChangedDelegate.Broadcast(ConnectionState); + ConnectionState = InworldConnectionState; + OnRep_ConnectionState(); } ); OnClientPerceivedLatencyHandle = Client->OnPerceivedLatency().AddLambda( @@ -424,9 +425,7 @@ void UInworldSession::CancelResponse(UInworldCharacter* Character, const FString EInworldConnectionState UInworldSession::GetConnectionState() const { - NO_CLIENT_RETURN(EInworldConnectionState::Idle) - - return Client->GetConnectionState(); + return ConnectionState; } void UInworldSession::GetConnectionError(FString& OutErrorMessage, int32& OutErrorCode) const @@ -500,6 +499,12 @@ void UInworldSession::OnRep_IsLoaded() OnLoadedDelegate.Broadcast(bIsLoaded); } +void UInworldSession::OnRep_ConnectionState() +{ + OnConnectionStateChangedDelegateNative.Broadcast(ConnectionState); + OnConnectionStateChangedDelegate.Broadcast(ConnectionState); +} + void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldConversationUpdateEvent& Event) { if (Event.EventType == EInworldConversationUpdateType::EVICTED) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp index 888d5e16..af013d98 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSessionComponent.cpp @@ -17,7 +17,8 @@ #include #define EMPTY_ARG_RETURN(Arg, Return) INWORLD_WARN_AND_RETURN_EMPTY(LogInworldAIIntegration, UInworldSessionComponent, Arg, Return) -#define NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(InworldSession, Return) EMPTY_ARG_RETURN(InworldSession->GetClient(), Return) +#define NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(InworldSession, Return) +#define NO_CLIENT_RETURN(Return) NO_SESSION_RETURN(Return) EMPTY_ARG_RETURN(InworldSession->GetClient(), Return) UInworldSessionComponent::UInworldSessionComponent() : Super() @@ -94,7 +95,7 @@ bool UInworldSessionComponent::GetIsLoaded() const void UInworldSessionComponent::StartSession() { - NO_SESSION_RETURN(void()) + NO_CLIENT_RETURN(void()) InworldSession->GetClient()->SetEnvironment(Environment); InworldSession->StartSession(SceneId, PlayerProfile, Auth, {}, {}, CapabilitySet); @@ -102,7 +103,7 @@ void UInworldSessionComponent::StartSession() void UInworldSessionComponent::StartSessionFromSave(const FInworldSave& Save) { - NO_SESSION_RETURN(void()) + NO_CLIENT_RETURN(void()) InworldSession->GetClient()->SetEnvironment(Environment); InworldSession->StartSession(SceneId, PlayerProfile, Auth, Save, {}, CapabilitySet); @@ -110,7 +111,7 @@ void UInworldSessionComponent::StartSessionFromSave(const FInworldSave& Save) void UInworldSessionComponent::StartSessionFromToken(const FInworldSessionToken& Token) { - NO_SESSION_RETURN(void()) + NO_CLIENT_RETURN(void()) InworldSession->GetClient()->SetEnvironment(Environment); InworldSession->StartSession(SceneId, PlayerProfile, Auth, {}, Token, CapabilitySet); @@ -118,21 +119,21 @@ void UInworldSessionComponent::StartSessionFromToken(const FInworldSessionToken& void UInworldSessionComponent::StopSession() { - NO_SESSION_RETURN(void()) + NO_CLIENT_RETURN(void()) InworldSession->StopSession(); } void UInworldSessionComponent::PauseSession() { - NO_SESSION_RETURN(void()) + NO_CLIENT_RETURN(void()) InworldSession->PauseSession(); } void UInworldSessionComponent::ResumeSession() { - NO_SESSION_RETURN(void()) + NO_CLIENT_RETURN(void()) InworldSession->ResumeSession(); } @@ -272,3 +273,4 @@ void UInworldSessionComponent::OnRep_InworldSession() #undef EMPTY_ARG_RETURN #undef NO_SESSION_RETURN +#undef NO_CLIENT_RETURN diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h index 126288ec..66a678ec 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldSession.h @@ -181,6 +181,12 @@ class INWORLDAIINTEGRATION_API UInworldSession : public UObject UPROPERTY(ReplicatedUsing = OnRep_IsLoaded) bool bIsLoaded; + UFUNCTION() + void OnRep_ConnectionState(); + + UPROPERTY(ReplicatedUsing = OnRep_ConnectionState) + EInworldConnectionState ConnectionState; + FDelegateHandle OnClientPacketReceivedHandle; FDelegateHandle OnClientConnectionStateChangedHandle; FDelegateHandle OnClientPerceivedLatencyHandle; From a8b97958a5c60ef7124b6185e9542a767bc2a326 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Tue, 7 May 2024 13:15:26 -0400 Subject: [PATCH 42/45] lazy init session on api subsystem --- .../Private/InworldApi.cpp | 23 +++++++++++++------ .../InworldAIIntegration/Public/InworldApi.h | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp index b8e5def4..80973459 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldApi.cpp @@ -54,6 +54,22 @@ void UInworldApiSubsystem::SetInworldSession(UInworldSession* Session) } } +UInworldSession* UInworldApiSubsystem::GetInworldSession() +{ + if (InworldSession == nullptr) + { + // Lazily instantiate the InworldSession if needed for backwards compatability + UWorld* World = GetWorld(); + if (World && World->GetNetMode() != NM_Client) + { + // Backward compatibility for calls directly to InworldApi without some sort of session actor + UInworldSessionComponent* SessionComponent = Cast(World->GetGameState()->AddComponentByClass(UInworldSessionComponent::StaticClass(), false, FTransform::Identity, false)); + SetInworldSession(IInworldSessionOwnerInterface::Execute_GetInworldSession(SessionComponent)); + } + } + return InworldSession; +} + void UInworldApiSubsystem::StartSession(const FString& SceneName, const FString& PlayerName, const FString& ApiKey, const FString& ApiSecret, const FString& AuthUrlOverride, const FString& TargetUrlOverride, const FString& Token, int64 TokenExpirationTime, const FString& SessionId) { NO_CLIENT_RETURN(void()) @@ -305,13 +321,6 @@ void UInworldApiSubsystem::OnWorldBeginPlay(UWorld& InWorld) Super::OnWorldBeginPlay(InWorld); UWorld* World = GetWorld(); - if (InworldSession == nullptr && World && World->GetNetMode() != NM_Client) - { - // Backward compatibility for calls directly to InworldApi without some sort of session actor - UInworldSessionComponent* SessionComponent = Cast(World->GetGameState()->AddComponentByClass(UInworldSessionComponent::StaticClass(), false, FTransform::Identity, false)); - SetInworldSession(IInworldSessionOwnerInterface::Execute_GetInworldSession(SessionComponent)); - } - if (World && World->GetNetMode() != NM_Standalone) { StartAudioReplication(); diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h index f7bd9075..bd4141e1 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldApi.h @@ -36,7 +36,7 @@ class INWORLDAIINTEGRATION_API UInworldApiSubsystem : public UWorldSubsystem void SetInworldSession(UInworldSession* Session); UFUNCTION(BlueprintPure, Category = "Session") - UInworldSession* GetInworldSession() const { return InworldSession; } + UInworldSession* GetInworldSession(); /** * Start InworldAI session From 7acf6c6047e99c93e9708d031744fd90c7ad211b Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 8 May 2024 11:30:26 -0400 Subject: [PATCH 43/45] fix player talk events --- .../Source/InworldAIIntegration/Private/InworldSession.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 6ed8e37c..187b7359 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -137,7 +137,9 @@ void UInworldSession::HandlePacket(const FInworldWrappedPacket& WrappedPacket) { (*TargetCharacter)->HandlePacket(WrappedPacket); } - + } + if (Source.Type == EInworldActorType::PLAYER) + { if (TArray* AgentIds = ConversationIdToAgentIds.Find(ConversationId)) { for (const FString& AgentId : *AgentIds) From e6fee409df5738c325e6391c9e7dd60fad70c811 Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 8 May 2024 12:35:41 -0400 Subject: [PATCH 44/45] don't clear brain on unpossess --- .../Source/InworldAIIntegration/Private/InworldCharacter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp index 88eacf26..0c4edca2 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldCharacter.cpp @@ -215,7 +215,8 @@ void UInworldCharacter::Unpossess() } OnPossessedDelegateNative.Broadcast(false); OnPossessedDelegate.Broadcast(false); - AgentInfo = {}; + AgentInfo.AgentId = {}; + AgentInfo.GivenName = {}; } } From f0e6f3110365c330d725610c58d17071eea99d5d Mon Sep 17 00:00:00 2001 From: Matt Carey Date: Wed, 8 May 2024 12:51:56 -0400 Subject: [PATCH 45/45] Unitary sessions fix --- .../Private/InworldPlayerTargetingComponent.cpp | 15 +++++++++------ .../Private/InworldSession.cpp | 2 +- .../Public/InworldPlayerTargetingComponent.h | 1 - 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp index 9c2261d5..6f341c3d 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldPlayerTargetingComponent.cpp @@ -40,15 +40,18 @@ void UInworldPlayerTargetingComponent::TickComponent(float DeltaTime, enum ELeve { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - if (InworldPlayer.IsValid()) - { - UpdateTargetCharacters(); - } + UpdateTargetCharacters(); } void UInworldPlayerTargetingComponent::UpdateTargetCharacters() { + if (!InworldPlayer.IsValid()) + { + return; + } + // clear all targets if just switched from multiple targeting + TArray TargetCharacters = InworldPlayer->GetTargetCharacters(); if (!bMultipleTargets && TargetCharacters.Num() > 1) { InworldPlayer->ClearAllTargetCharacters(); @@ -60,7 +63,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() const FVector Location = GetOwner()->GetActorLocation(); for (int32 i = 0; i < TargetCharacters.Num(); i++) { - UInworldCharacter* Character = TargetCharacters[i].Get(); + UInworldCharacter* Character = TargetCharacters[i]; AActor* OuterActor = Character->GetTypedOuter(); const FVector CharacterLocation = OuterActor != nullptr ? OuterActor->GetActorLocation() : FVector::ZeroVector; const float DistSq = FVector::DistSquared(Location, CharacterLocation); @@ -147,7 +150,7 @@ void UInworldPlayerTargetingComponent::UpdateTargetCharacters() return; } - UInworldCharacter* CurrentTarget = TargetCharacters.Num() != 0 ? TargetCharacters[0].Get() : nullptr; + UInworldCharacter* CurrentTarget = TargetCharacters.Num() != 0 ? TargetCharacters[0] : nullptr; if (CurrentTarget != BestTarget) { if (CurrentTarget) diff --git a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp index 187b7359..e3a670db 100644 --- a/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp +++ b/InworldAI/Source/InworldAIIntegration/Private/InworldSession.cpp @@ -529,12 +529,12 @@ void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldConversa void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldLoadCharactersEvent& Event) { - Session->UnpossessAgents(); Session->PossessAgents(Event.AgentInfos); } void UInworldSession::FInworldSessionPacketVisitor::Visit(const FInworldChangeSceneEvent& Event) { + Session->UnpossessAgents(); Session->PossessAgents(Event.AgentInfos); } diff --git a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h index cd0037ed..d0725c96 100644 --- a/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h +++ b/InworldAI/Source/InworldAIIntegration/Public/InworldPlayerTargetingComponent.h @@ -42,5 +42,4 @@ class INWORLDAIINTEGRATION_API UInworldPlayerTargetingComponent : public UActorC private: TWeakObjectPtr InworldPlayer; - TArray> TargetCharacters; };

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�S5?NpnW16H$TqrI+CTh{Zn_L%zC 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

CWFf)L2@1w`JSqnMq4dGA9eu># z;lRQO3ZM}jnF8FPupAe3pg`BU0hcgBiR z;)lkD2&m-%tuqNet^`1J5A(0 z>EyFTO^GDwK9(wq3c1WW!q5=_7G8YRI2C1kk&i$&@e zYc@N&b|w~WPZ~!o${8X6ynsG9is?g1AEkXBdhNEt9S&6Z%jxB(P`S_JFQa#GOUf#= z!2-3=ehMI%2endFW3f7CR;=*LdY*iR2=BvH;aYXxU!CQ05a`qe>8Cj8%s&fgzFw!W z*QhhrWpLEXQ||ZYI~=*=?2`J?i=Y4Kx)m>c`}-LRWxhItxHt||XGc;Z%g8Gw0{D+C z<+qF8dSmC~M~ALnH|EUs-#>PFUMcy(ido7PN^;l}4$PNuaNmkNq=*2pCGKcP$oyBa SnG#plK+W8QN6t9-s{aSP&C}2T literal 82347 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 diff --git a/InworldAI/Content/Dialog/DialogMap.umap b/InworldAI/Content/Dialog/DialogMap.umap index 4eb7a008de5010667c54b9767b302bc2c6f8d365..15fe4da8b68a0c19f1b5ba3e8c345ac90de9a5cb 100644 GIT binary patch literal 18093 zcmeHP33yaRwk`w(R9qsP3KEb(knDs=z(6ORg&-j@3xYljH|d+CrPDXuz9Gb6$x{>@ z=Z)hsq98h>4zATGpR)wxUZ#HDB6yzk(_gL8W_cJvX9eMl|JF;s84a$m~+Y3(bHeQnX&F`Fh% zNGI5*Q=dPrWqL;D?KRI|k$%EepY$Nuo9*w7IivKp9SdGKVa@J0(oR2-VAXS8pFOoa zCuQO6g&VHiwV|yK!7d*>bndcB-@R|WIPmV5pWfYX62bm`+hYGcg_VE)@Z4#4kA8Ul zV}Om=R(sQ9m80$~?LGXu=P!9sOC#9J8xO9T)uXcfl9b`^thn=?ceJ4+q`clR-mxaGR(4ezmJvuW<&*ihC`-n4SImxG03dvNT#lN16nA=%v0~3dmNBV zQ|qiUjW*r1I$8O;cl~5bK#dNs(b`5!60}%dZPVm_09%&U*ixmL0A?J#lQS;Td^K&R z-_qH`eMdfdGNCmTwp&I`o7NGm@P|VFU^9tbtXUdM*_S>A-q$eI@AK(Fwq$Gh(WlaN zQJ`HX5<$yL@>#mi;T&Qa#f$sUYO;nIx>e}&nR+OsH3W1v{`Uo)13BEVN)6K+@RLlH zW{qwx&`maA___z7U6EnTYt_toTuatmd&-qigP;LN-Svz z*P}S3J=DT7J{#zRNs3Imas*==W;fS?mRD=7G_4lne8XsE3(SHI$J)RuBjm@zvGv}8 zmkC(4Ve!ReBX&IH#|qKpx;7s)X1>3TdK$s%)!IVs0X@uUU{~dQ$QOpJzIy#2NW_gr zEGl&3?_La}?GNl8O5iH3ah}$!Pd6I1fd671Sr8=DrZws;#p+yvMUOOSd(G|}`H`px2!8>e z%cFEf)qpg0zzNkyH@-OrbPzG&RqMZATZN5`qZuaqiT{yT;RSX)*ygL&n{?VJNtUa= z*#0qS)EG?`w?dU>wXoH{@gIO1+)2Ch`9FNwo`RsZci6B19|n&)09UNB;4Jp$J?RN^ zB+NxHibV&U#ctY<6|2=3TI`8@j~^?B3kT!LiPm~}0)W+e&_^3+AJ4^GAaZR>duu~b z^9Q&W{dW4e2cTx1w}!mI-{jYQf{0%av3VVfa>XcZ!+vK`%8BAaHg@L)xAewbKX;w0 z7S~R~@w5u zlOQ(q580>CLCZ2l$P|`m7FE?p#t*rgWzrr)YTht)-+H7a3VJb7HkvWZ?m7FY{?O