Files
planet/unreal/Source/Planet/Public/UeSceneWebSocketClient.h
2026-05-09 15:51:46 +08:00

160 lines
4.9 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "IWebSocket.h"
#include "UeSceneWebSocketClient.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUeSceneRawMessageEvent, const FString&, Message);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUeSceneConnectedEvent, bool, bConnected);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUeSceneErrorEvent, const FString&, ErrorMessage);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(
FUeSceneFrameEvent,
const FString&,
UpdateType,
int32,
Sequence,
int32,
TotalRecords
);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(
FUeScenePayloadEvent,
const FString&,
UpdateType,
int32,
Sequence,
const FString&,
PayloadJson
);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(
FUeSceneSubmarineCableEvent,
const FString&,
CableName,
const TArray<FVector>&,
GeoPoints
);
UCLASS(ClassGroup=(Planet), meta=(BlueprintSpawnableComponent))
class PLANET_API UUeSceneWebSocketClient : public UActorComponent
{
GENERATED_BODY()
public:
UUeSceneWebSocketClient();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Planet|Backend")
FString BackendBaseUrl = TEXT("http://127.0.0.1:8000");
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Planet|Backend")
FString Username;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Planet|Backend")
FString Password;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Planet|Backend")
TArray<FString> DefaultChannels = {TEXT("ue_scene")};
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Planet|Backend")
int32 LastSequence = INDEX_NONE;
UPROPERTY(BlueprintAssignable, Category="Planet|Backend")
FUeSceneConnectedEvent OnConnectedChanged;
UPROPERTY(BlueprintAssignable, Category="Planet|Backend")
FUeSceneRawMessageEvent OnRawMessage;
UPROPERTY(BlueprintAssignable, Category="Planet|Backend")
FUeSceneErrorEvent OnError;
UPROPERTY(BlueprintAssignable, Category="Planet|Backend")
FUeSceneFrameEvent OnSceneFrame;
UPROPERTY(BlueprintAssignable, Category="Planet|Backend")
FUeScenePayloadEvent OnScenePayload;
UPROPERTY(BlueprintAssignable, Category="Planet|Backend|Legacy")
FUeSceneSubmarineCableEvent OnSubmarineCableReceived;
UFUNCTION(BlueprintCallable, Category="Planet|Backend")
void ConnectToBackend();
UFUNCTION(BlueprintCallable, Category="Planet|Backend")
void DisconnectFromBackend();
UFUNCTION(BlueprintCallable, Category="Planet|Backend")
void SendSubscribe();
UFUNCTION(BlueprintCallable, Category="Planet|Backend")
void SendInitialSyncRequest();
UFUNCTION(BlueprintCallable, Category="Planet|Backend")
void SendSyncRequest(const FString& Reason, int32 InLastSequence);
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private:
struct FLayerChunkAccumulator
{
int32 Revision = 0;
int32 ExpectedChunkCount = 0;
TSet<int32> ReceivedChunkIndices;
TArray<TSharedPtr<FJsonValue>> Items;
};
struct FFullSceneAssemblyState
{
int32 Sequence = INDEX_NONE;
int32 ExpectedTransportChunkCount = 0;
int32 TotalRecords = 0;
FString ClusterTime;
TSharedPtr<FJsonObject> DisplayProfile;
TSharedPtr<FJsonObject> CameraState;
TSharedPtr<FJsonObject> Meta;
TMap<FString, FLayerChunkAccumulator> Layers;
TSet<int32> ReceivedTransportChunkIndices;
void Reset()
{
Sequence = INDEX_NONE;
ExpectedTransportChunkCount = 0;
TotalRecords = 0;
ClusterTime.Reset();
DisplayProfile.Reset();
CameraState.Reset();
Meta.Reset();
Layers.Reset();
ReceivedTransportChunkIndices.Reset();
}
};
FString AccessToken;
TSharedPtr<IWebSocket> Socket;
FFullSceneAssemblyState PendingFullScene;
void RequestAccessToken();
void HandleLoginResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bSucceeded);
void OpenWebSocket();
void BindSocketEvents();
void EmitError(const FString& ErrorMessage);
void TryBroadcastSceneFrame(const FString& Message);
bool TryAssembleFullScene(
const TSharedPtr<FJsonObject>& DataObject,
int32 Sequence,
int32 TotalRecords,
TSharedPtr<FJsonObject>& OutAssembledDataObject
);
void BroadcastScenePayload(
const FString& UpdateType,
int32 Sequence,
const TSharedPtr<FJsonObject>& DataObject
);
void BroadcastLegacySubmarineCableEvents(const TSharedPtr<FJsonObject>& DataObject);
FString BuildWsUrl() const;
FString BuildHttpUrl(const FString& Path) const;
void SendJsonString(const FString& JsonPayload);
};