Files
TerracottaWarriors/Source/TerracottaWarriors/Private/UDPInstanceSubsystem.cpp
2025-07-14 22:24:27 +08:00

270 lines
8.1 KiB
C++

#include "UDPInstanceSubsystem.h"
#include "Serialization/JsonReader.h"
#include "Serialization/JsonWriter.h"
#include "Sockets.h"
#include "Camera/CameraComponent.h"
#include "Common/UdpSocketBuilder.h"
#include "Common/UdpSocketReceiver.h"
#include "GameFramework/Pawn.h"
#include "Kismet/KismetMathLibrary.h"
TSharedPtr<FJsonObject> FDeviceData::ToJsonObject() const
{
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
JsonObject->SetStringField("id", ID);
JsonObject->SetNumberField("x", X);
JsonObject->SetNumberField("y", Y);
JsonObject->SetNumberField("z", Z);
JsonObject->SetNumberField("yaw", Yaw);
JsonObject->SetNumberField("roll", Roll);
JsonObject->SetNumberField("pitch", Pitch);
return JsonObject;
}
bool FDeviceData::FromJsonObject(const TSharedPtr<FJsonObject>& JsonObject, FDeviceData& OutDeviceData)
{
if (!JsonObject.IsValid())
return false;
if (!JsonObject->TryGetStringField("id", OutDeviceData.ID))
return false;
if (!JsonObject->TryGetNumberField("x", OutDeviceData.X))
return false;
if (!JsonObject->TryGetNumberField("y", OutDeviceData.Y))
return false;
if (!JsonObject->TryGetNumberField("z", OutDeviceData.Z))
return false;
if (!JsonObject->TryGetNumberField("yaw", OutDeviceData.Yaw))
return false;
if (!JsonObject->TryGetNumberField("roll", OutDeviceData.Roll))
return false;
if (!JsonObject->TryGetNumberField("pitch", OutDeviceData.Pitch))
return false;
return true;
}
void UUDPInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
InitNetwork();
UUID = FGuid::NewGuid().ToString();
}
void UUDPInstanceSubsystem::Deinitialize()
{
CleanupNetwork();
Super::Deinitialize();
}
void UUDPInstanceSubsystem::InitNetwork()
{
// 初始化发送socket
SenderSocket = FUdpSocketBuilder(TEXT("UDPSenderSocket"))
.AsReusable()
.WithBroadcast();
// 设置远程端点 (192.168.1.28:1234)
FIPv4Address::Parse(TEXT("192.168.30.254"), RemoteEndpoint.Address);
RemoteEndpoint.Port = 1234;
// 初始化接收socket
ReceiverSocket = FUdpSocketBuilder(TEXT("UDPReceiverSocket"))
.AsReusable()
.WithBroadcast()
.BoundToEndpoint(FIPv4Endpoint(FIPv4Address::Any, 9999)) // 监听相同端口
.WithReceiveBufferSize(65535);
// 启动接收线程
SocketReceiver = new FUdpSocketReceiver(ReceiverSocket, FTimespan::FromMilliseconds(100), TEXT("UDPReceiver"));
SocketReceiver->OnDataReceived().BindUObject(this, &UUDPInstanceSubsystem::OnDataReceived);
SocketReceiver->Start();
}
void UUDPInstanceSubsystem::CleanupNetwork()
{
// 停止接收线程
if (SocketReceiver)
{
SocketReceiver->Stop();
delete SocketReceiver;
SocketReceiver = nullptr;
}
// 关闭接收socket
if (ReceiverSocket)
{
ReceiverSocket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ReceiverSocket);
ReceiverSocket = nullptr;
}
// 关闭发送socket
if (SenderSocket)
{
SenderSocket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SenderSocket);
SenderSocket = nullptr;
}
}
void UUDPInstanceSubsystem::SetTrackedPawn(APawn* NewPawn)
{
TrackedPawn = NewPawn;
}
void UUDPInstanceSubsystem::SendDeviceData(const FDeviceData& DeviceData)
{
if (!SenderSocket)
return;
// 将结构体转换为JSON
TSharedPtr<FJsonObject> JsonObject = DeviceData.ToJsonObject();
FString JsonString;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&JsonString);
FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);
// 发送数据
TArray<uint8> Data;
FTCHARToUTF8 Converter(*JsonString);
Data.Append((uint8*)Converter.Get(), Converter.Length());
int32 BytesSent = 0;
SenderSocket->SendTo(Data.GetData(), Data.Num(), BytesSent, RemoteEndpoint.ToInternetAddr().Get());
}
void UUDPInstanceSubsystem::SendCurrentPawnData()
{
if (!TrackedPawn)
return;
FDeviceData DeviceData;
/*DeviceData.ID = "PlayerPawn";*/
DeviceData.ID = UUID;
UCameraComponent* TargetCamera = TrackedPawn->FindComponentByClass<UCameraComponent>();
FVector Location = TargetCamera->GetComponentLocation();
DeviceData.X = Location.X;
DeviceData.Y = Location.Y;
DeviceData.Z = 0;
FRotator Rotation = TargetCamera->GetComponentRotation();
DeviceData.Yaw = Rotation.Yaw;
DeviceData.Roll = Rotation.Roll;
DeviceData.Pitch = Rotation.Pitch;
/*FVector Location = TrackedPawn->GetActorLocation();
DeviceData.X = Location.X;
DeviceData.Y = Location.Y;
DeviceData.Z = Location.Z;
FRotator Rotation = TrackedPawn->GetActorRotation();
DeviceData.Yaw = Rotation.Yaw;
DeviceData.Roll = Rotation.Roll;
DeviceData.Pitch = Rotation.Pitch;*/
SendDeviceData(DeviceData);
}
void UUDPInstanceSubsystem::SpawnActorInGameThread(TSubclassOf<AActor> Actor, const FVector& Location, const FRotator& Rotation, const FString& ID, FOnActorSpawned OnActorSpawned)
{
// 强制要求在 GameThread 调用
if (IsInGameThread())
{
UE_LOG(LogTemp, Error, TEXT("In main thread"));
return;
}
// 记录开始创建
UE_LOG(LogTemp, Log, TEXT("Actor1111 "));
// 使用智能指针或委托机制才能安全地处理异步结果
AsyncTask(ENamedThreads::GameThread, [this, Location, Rotation, ID, Actor, OnActorSpawned]()
{
if (!GetWorld())
{
UE_LOG(LogTemp, Error, TEXT("Cannot spawn actor: invalid world"));
OnActorSpawned.ExecuteIfBound(nullptr, ID);
return;
}
if (!Actor)
{
UE_LOG(LogTemp, Error, TEXT("Cannot spawn actor: invalid actor class"));
OnActorSpawned.ExecuteIfBound(nullptr, ID);
return;
}
AActor* NewActor = GetWorld()->SpawnActor<AActor>(Actor, Location, Rotation);
if (NewActor)
{
UE_LOG(LogTemp, Log, TEXT("Actor %s spawned at %s"), ID.Len() ? *ID : TEXT("Unknown"), *Location.ToString());
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Failed to spawn actor %s"), *ID);
}
OnActorSpawned.ExecuteIfBound(NewActor, ID);
});
}
void UUDPInstanceSubsystem::OnDataReceived(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt)
{
// 将接收到的二进制数据转换为字符串
uint8* Data = (uint8*)ArrayReaderPtr->GetData();
int32 DataSize = ArrayReaderPtr->Num();
// 添加字符串结束符
TArray<uint8> DataWithNull;
DataWithNull.Append(Data, DataSize);
DataWithNull.Add(0); // 添加null终止符
// 转换为FString
FString DataString = UTF8_TO_TCHAR(DataWithNull.GetData());
ParseReceivedData(DataString);
// 在游戏线程中处理数据
// AsyncTask(ENamedThreads::GameThread, [this, DataString]() {
//
// });
}
void UUDPInstanceSubsystem::ParseReceivedData(const FString& DataString)
{
//UE_LOG(LogTemp, Warning, TEXT("Received Data: %s"), *DataString);
TMap<FString, FDeviceData> DeviceDataMap;
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(DataString);
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
{
for (const auto& Pair : JsonObject->Values)
{
if (Pair.Value.IsValid() && Pair.Value->Type == EJson::Object)
{
FDeviceData DeviceData;
if (FDeviceData::FromJsonObject(Pair.Value->AsObject(), DeviceData))
{
DeviceData.ID = Pair.Key; // Set ID from map key
DeviceDataMap.Add(Pair.Key, DeviceData);
}
}
}
}
FDeviceDataMap DeviceDataMapStruct;
DeviceDataMapStruct.ReceivedDataMap = DeviceDataMap;
AsyncTask(ENamedThreads::GameThread, [&,this, DeviceDataMapStruct]()
{
OnDeviceDataReceived.Broadcast(DeviceDataMapStruct);
});
}