// Fill out your copyright notice in the Description page of Project Settings. #include "LuckyDataTransferSubsystem.h" #include "JsonUtilities.h" #include "JsonObjectConverter.h" #include "WebSocketsModule.h" #include "Slate/SceneViewport.h" ULuckyDataTransferSubsystem::ULuckyDataTransferSubsystem() { } void ULuckyDataTransferSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); } void ULuckyDataTransferSubsystem::Deinitialize() { Super::Deinitialize(); if (Socket.IsValid() && Socket->IsConnected()) { Socket->Close(); } } void ULuckyDataTransferSubsystem::Internal_OpenWebsocket(const FString& URL, const FString& Protocol) { const FString NewUrl = URL.IsEmpty() ? TEXT("ws://127.0.0.1:3000/ws") : URL; const FString NewProtocol = Protocol.IsEmpty() ? TEXT("ws") : Protocol; UE_LOG(LogTemp, Warning, TEXT("Opening WebSocket URL: %s"), *NewUrl); if (!FModuleManager::Get().IsModuleLoaded("WebSockets")) { FModuleManager::Get().LoadModule("WebSockets"); } Socket = FWebSocketsModule::Get().CreateWebSocket(NewUrl); Socket->Connect(); Socket->OnConnected().AddLambda([]() { UE_LOG(LogTemp, Warning, TEXT("WebSocket connected")); }); Socket->OnConnectionError().AddLambda([](const FString& Message) { UE_LOG(LogTemp, Warning, TEXT("WebSocket connection error")); }); Socket->OnMessage().AddUObject(this, &ULuckyDataTransferSubsystem::Callback_OnMessage); } //Callbacks / Lambas void ULuckyDataTransferSubsystem::Callback_OnConnected() { } void ULuckyDataTransferSubsystem::Callback_OnConnectionError(const FString& Error) { } void ULuckyDataTransferSubsystem::Callback_OnMessage(const FString& Message) { if (!Message.IsEmpty()) { CommandReady(InterpretData(Message)); return; } UE_LOG(LogTemp, Warning, TEXT("The message received from the websocket is invalid")); } void ULuckyDataTransferSubsystem::Internal_OnMessageSent(const FString& Message) { } void ULuckyDataTransferSubsystem::Callback_OnConnectionClosed() { } //Blueprint Exposed Implementation void ULuckyDataTransferSubsystem::ConnectToWebsocket(const FString& URL, const FString& Protocol) { Internal_OpenWebsocket(URL, Protocol); } void ULuckyDataTransferSubsystem::SendMessage(const FString& Message) { if (Socket.IsValid() && Socket->IsConnected()) { Socket->Send(Message); return; } UE_LOG(LogTemp, Warning, TEXT("WebSocket message failed")); } FPayload ULuckyDataTransferSubsystem::InterpretData(const FString& Message) { FPayload Payload = FPayload(); if (!Message.IsEmpty()) { TSharedPtr JsonObj; TSharedRef> Reader = TJsonReaderFactory<>::Create(Message); if (FJsonSerializer::Deserialize(Reader, JsonObj) && JsonObj.IsValid()) { for (auto& Elem : JsonObj->Values) { FCommand Command = FCommand(); Command.Key = FString(Elem.Key); Command.Value = Elem.Value->AsNumber(); Payload.Commands.Add(Command); } } } return Payload; } void ULuckyDataTransferSubsystem::CommandReady(const FPayload& Payload) { if (OnCommandReady.IsBound()) { OnCommandReady.Broadcast(Payload); } } //Blueprint Callable function - Use CreateJsonPayload_Observation in C++ bool ULuckyDataTransferSubsystem::MakeObservationPayload(const FObservationPayload& Data) { return CreateJsonPayload_Observation(Data); } bool ULuckyDataTransferSubsystem::CreateJsonPayload_Observation(const FObservationPayload& Data) { bool bSuccess = false; ObservationPayloadString = FString(); if (!Data.ObservationState.IsEmpty()) { FJsonObjectConverter::UStructToJsonObjectString(Data, ObservationPayloadString); UE_LOG(LogTemp, Warning, TEXT("Payload observation: %s"), *ObservationPayloadString); bSuccess = true; } return bSuccess; }