Skip to content

Commit

Permalink
Merge pull request #77 from metaworking/40-multi-actor-components
Browse files Browse the repository at this point in the history
Support multiple replicated ActorComponents in one Actor#40
  • Loading branch information
indiest authored Sep 5, 2023
2 parents c34af74 + 0c45efc commit 0d2a724
Show file tree
Hide file tree
Showing 20 changed files with 1,337 additions and 424 deletions.
5 changes: 3 additions & 2 deletions Source/ChanneldUE/ChannelDataInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,16 @@ class CHANNELDUE_API IChannelDataProcessor
virtual bool UpdateChannelData(UObject* TargetObj, google::protobuf::Message* ChannelData) {return true;}
virtual bool OnChannelDataUpdated(UObject* TargetObj, google::protobuf::Message* ChannelData) {return true;}

virtual const google::protobuf::Message* GetStateFromChannelData(google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID, bool& bIsRemoved) = 0;
virtual const google::protobuf::Message* GetStateFromChannelData(google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID, bool& bIsRemoved) = 0;
/**
* @brief Set a replicator's state to the channel data. UChanneldReplicationComponent doesn't know what states are defined in the channel data, or how are they organized. So the child class should implement this logic.
* @param State The delta state of a replicator, collected during Tick(). If null, removed = true will be set for the state.
* @param ChannelData The data field in the ChannelDataUpdate message which will be sent to channeld.
* @param TargetClass The class associated with the replicator. E.g. AActor for FChanneldActorReplicator, and ACharacter for FChanneldCharacterReplicator.
* @param TargetObject The replicated object that associated with the state.
* @param NetGUID The NetworkGUID used for looking up the state in the channel data. Generally the key of the state map.
*/
virtual void SetStateToChannelData(const google::protobuf::Message* State, google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID) = 0;
virtual void SetStateToChannelData(const google::protobuf::Message* State, google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID) = 0;

virtual ~IChannelDataProcessor() {}
};
6 changes: 5 additions & 1 deletion Source/ChanneldUE/ChanneldNetConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ void UChanneldNetConnection::SendDestroyMessage(UObject* Object, EChannelCloseRe
}
}

void UChanneldNetConnection::SendRPCMessage(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg, Channeld::ChannelId ChId)
void UChanneldNetConnection::SendRPCMessage(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg, Channeld::ChannelId ChId, const FString& SubObjectPath)
{
if (GetMutableDefault<UChanneldSettings>()->bQueueUnexportedActorRPC)
{
Expand All @@ -318,6 +318,10 @@ void UChanneldNetConnection::SendRPCMessage(AActor* Actor, const FString& FuncNa
// RpcMsg.mutable_targetobj()->MergeFrom(*ChanneldUtils::GetRefOfObject(Actor));
RpcMsg.mutable_targetobj()->set_netguid(Driver->GuidCache->GetNetGUID(Actor).Value);
RpcMsg.set_functionname(TCHAR_TO_UTF8(*FuncName), FuncName.Len());
if (!SubObjectPath.IsEmpty())
{
RpcMsg.set_subobjectpath(TCHAR_TO_UTF8(*SubObjectPath), SubObjectPath.Len());
}
if (ParamsMsg)
{
RpcMsg.set_paramspayload(ParamsMsg->SerializeAsString());
Expand Down
2 changes: 1 addition & 1 deletion Source/ChanneldUE/ChanneldNetConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class CHANNELDUE_API UChanneldNetConnection : public UNetConnection
*/
void SendSpawnMessage(UObject* Object, ENetRole Role = ENetRole::ROLE_None, uint32 OwningChannelId = Channeld::InvalidChannelId, uint32 OwningConnId = 0, FVector* Location = nullptr);
void SendDestroyMessage(UObject* Object, EChannelCloseReason Reason = EChannelCloseReason::Destroyed);
void SendRPCMessage(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg = nullptr, Channeld::ChannelId ChId = Channeld::InvalidChannelId);
void SendRPCMessage(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg = nullptr, Channeld::ChannelId ChId = Channeld::InvalidChannelId, const FString& SubObjectPath = "");
// Flush the handshake packets that are queued before received AuthResultMessage to the server.
void FlushUnauthData();

Expand Down
42 changes: 33 additions & 9 deletions Source/ChanneldUE/ChanneldNetDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,17 @@ void UChanneldNetDriver::HandleCustomRPC(TSharedPtr<unrealpb::RemoteFunctionMess
//TSet<FNetworkGUID> UnmappedGUID;
bool bDelayRPC = false;
FName FuncName = UTF8_TO_TCHAR(Msg->functionname().c_str());
ReceivedRPC(Actor, FuncName, Msg->paramspayload(), bDelayRPC);
UObject* SubObject = nullptr;
if (Msg->subobjectpath().length() > 0)
{
SubObject = Actor->GetDefaultSubobjectByName(Msg->subobjectpath().c_str());
if(!SubObject)
{
UE_LOG(LogChanneld, Log, TEXT("Actor:%s, NetGuid:%d can not find Subobject:%s for Function:%s"),
*Actor->GetName(), Msg->targetobj().netguid(), *FString(Msg->subobjectpath().c_str()), *FuncName.ToString());
}
}
ReceivedRPC(Actor, FuncName, Msg->paramspayload(), bDelayRPC, SubObject);
if (bDelayRPC)
{
UE_LOG(LogChanneld, Log, TEXT("Deferred RPC '%s::%s' due to unmapped NetGUID: %d"), *Actor->GetName(), *FuncName.ToString(), Msg->targetobj().netguid());
Expand Down Expand Up @@ -887,8 +897,16 @@ void UChanneldNetDriver::ProcessRemoteFunction(class AActor* Actor, class UFunct
auto RepComp = Cast<UChanneldReplicationComponent>(Actor->FindComponentByClass(UChanneldReplicationComponent::StaticClass()));
if (RepComp)
{
UObject* TargetObject = Actor;
FString SubObjectPathName = "";
if (SubObject)
{
TargetObject = SubObject;
SubObjectPathName = SubObject->GetName();
}

bool bSuccess = true;
auto ParamsMsg = RepComp->SerializeFunctionParams(Actor, Function, Parameters, OutParms, bSuccess);
auto ParamsMsg = RepComp->SerializeFunctionParams(TargetObject, Function, Parameters, OutParms, bSuccess);
if (bSuccess)
{
UE_CLOG(bShouldLog && ParamsMsg.IsValid(), LogChanneld, VeryVerbose, TEXT("Serialized RPC parameters: %s"), UTF8_TO_TCHAR(ParamsMsg->DebugString().c_str()));
Expand All @@ -898,7 +916,7 @@ void UChanneldNetDriver::ProcessRemoteFunction(class AActor* Actor, class UFunct
// Server -> Client multicast RPC
if (ConnToChanneld->IsServer() && (Function->FunctionFlags & FUNC_NetMulticast))
{
if (ChannelDataView->SendMulticastRPC(Actor, FuncName, ParamsMsg))
if (ChannelDataView->SendMulticastRPC(Actor, FuncName, ParamsMsg, SubObjectPathName))
{
return;
}
Expand All @@ -909,7 +927,7 @@ void UChanneldNetDriver::ProcessRemoteFunction(class AActor* Actor, class UFunct
UChanneldNetConnection* NetConn = ConnToChanneld->IsClient() ? GetServerConnection() : Cast<UChanneldNetConnection>(Actor->GetNetConnection());
if (NetConn)
{
NetConn->SendRPCMessage(Actor, FuncName, ParamsMsg, OwningChId);
NetConn->SendRPCMessage(Actor, FuncName, ParamsMsg, OwningChId, SubObjectPathName);
return;
}
UE_LOG(LogChanneld, Warning, TEXT("Failed to send RPC %s::%s as the actor doesn't have any NetConn"), *Actor->GetName(), *FuncName);
Expand All @@ -920,6 +938,10 @@ void UChanneldNetDriver::ProcessRemoteFunction(class AActor* Actor, class UFunct
unrealpb::RemoteFunctionMessage RpcMsg;
RpcMsg.mutable_targetobj()->set_netguid(GuidCache->GetNetGUID(Actor).Value);
RpcMsg.set_functionname(TCHAR_TO_UTF8(*FuncName), FuncName.Len());
if (!SubObjectPathName.IsEmpty())
{
RpcMsg.set_subobjectpath(TCHAR_TO_UTF8(*SubObjectPathName), SubObjectPathName.Len());
}
if (ParamsMsg)
{
RpcMsg.set_paramspayload(ParamsMsg->SerializeAsString());
Expand Down Expand Up @@ -957,15 +979,17 @@ void UChanneldNetDriver::OnSentRPC(const unrealpb::RemoteFunctionMessage& RpcMsg
#endif
}

void UChanneldNetDriver::ReceivedRPC(AActor* Actor, const FName& FunctionName, const std::string& ParamsPayload, bool& bDeferredRPC)
void UChanneldNetDriver::ReceivedRPC(AActor* Actor, const FName& FunctionName, const std::string& ParamsPayload, bool& bDeferredRPC, UObject* SubObject)
{
const bool bShouldLog = FunctionName != ServerMovePackedFuncName && FunctionName != ClientMoveResponsePackedFuncName && FunctionName != ServerUpdateCameraFuncName;
UE_CLOG(bShouldLog, LogChanneld, Verbose, TEXT("Received RPC %s::%s"), *Actor->GetName(), *FunctionName.ToString());


UFunction* Function = Actor->FindFunction(FunctionName);
UObject* Obj = SubObject != nullptr ? SubObject : Actor;
UFunction* Function = Obj->FindFunction(FunctionName);
if (!Function)
{
UE_LOG(LogChanneld, Error, TEXT("RPC function %s doesn't exist on Actor %s"), *FunctionName.ToString(), *Actor->GetName());
UE_LOG(LogChanneld, Error, TEXT("RPC function %s doesn't exist on Obj %s"), *FunctionName.ToString(), *Actor->GetName());
return;
}

Expand All @@ -983,15 +1007,15 @@ void UChanneldNetDriver::ReceivedRPC(AActor* Actor, const FName& FunctionName, c
if (RepComp)
{
bool bSuccess = true;
TSharedPtr<void> Params = RepComp->DeserializeFunctionParams(Actor, Function, ParamsPayload, bSuccess, bDeferredRPC);
TSharedPtr<void> Params = RepComp->DeserializeFunctionParams(Obj, Function, ParamsPayload, bSuccess, bDeferredRPC);
if (bDeferredRPC)
{
return;
}

if (bSuccess)
{
Actor->ProcessEvent(Function, Params.Get());
Obj->ProcessEvent(Function, Params.Get());
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion Source/ChanneldUE/ChanneldNetDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class CHANNELDUE_API UChanneldNetDriver : public UNetDriver
UChanneldNetConnection* AddChanneldClientConnection(Channeld::ConnectionId ClientConnId, Channeld::ChannelId ChId);
void RemoveChanneldClientConnection(Channeld::ConnectionId ClientConnId);

void ReceivedRPC(AActor* Actor, const FName& FunctionName, const std::string& ParamsPayload, bool& bDeferredRPC);
void ReceivedRPC(AActor* Actor, const FName& FunctionName, const std::string& ParamsPayload, bool& bDeferredRPC, UObject* SubObject = nullptr);

UChanneldConnection* GetConnToChanneld() const { return ConnToChanneld; }

Expand Down
4 changes: 2 additions & 2 deletions Source/ChanneldUE/DefaultSpatialChannelDataProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ bool FDefaultSpatialChannelDataProcessor::UpdateChannelData(UObject* TargetObj,
}

const google::protobuf::Message* FDefaultSpatialChannelDataProcessor::GetStateFromChannelData(
google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID, bool& bIsRemoved)
google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID, bool& bIsRemoved)
{
if (TargetClass != UObject::StaticClass())
{
Expand All @@ -58,7 +58,7 @@ const google::protobuf::Message* FDefaultSpatialChannelDataProcessor::GetStateFr
}

void FDefaultSpatialChannelDataProcessor::SetStateToChannelData(const google::protobuf::Message* State,
google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID)
google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID)
{
if (TargetClass != UObject::StaticClass())
{
Expand Down
4 changes: 2 additions & 2 deletions Source/ChanneldUE/DefaultSpatialChannelDataProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ class CHANNELDUE_API FDefaultSpatialChannelDataProcessor : public IChannelDataPr

virtual bool UpdateChannelData(UObject* TargetObj, google::protobuf::Message* ChannelData) override;

virtual const google::protobuf::Message* GetStateFromChannelData(google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID, bool& bIsRemoved) override;
virtual void SetStateToChannelData(const google::protobuf::Message* State, google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID) override;
virtual const google::protobuf::Message* GetStateFromChannelData(google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID, bool& bIsRemoved) override;
virtual void SetStateToChannelData(const google::protobuf::Message* State, google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID) override;
};
4 changes: 2 additions & 2 deletions Source/ChanneldUE/FFlatStatesChannelDataProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ bool FFlatStatesChannelDataProcessor::Merge(const google::protobuf::Message* Src
return false;
}

const google::protobuf::Message* FFlatStatesChannelDataProcessor::GetStateFromChannelData(google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID, bool& bIsRemoved)
const google::protobuf::Message* FFlatStatesChannelDataProcessor::GetStateFromChannelData(google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID, bool& bIsRemoved)
{
bIsRemoved = false;
auto StateInProto = ChanneldReplication::FindReplicatorStateInProto(TargetClass);
Expand Down Expand Up @@ -64,7 +64,7 @@ const google::protobuf::Message* FFlatStatesChannelDataProcessor::GetStateFromCh
return State;
}

void FFlatStatesChannelDataProcessor::SetStateToChannelData(const google::protobuf::Message* State,google::protobuf::Message* ChannelData, UClass* TargetClass, uint32 NetGUID)
void FFlatStatesChannelDataProcessor::SetStateToChannelData(const google::protobuf::Message* State,google::protobuf::Message* ChannelData, UClass* TargetClass, UObject* TargetObject, uint32 NetGUID)
{
auto StateInProto = ChanneldReplication::FindReplicatorStateInProto(TargetClass);
if (!StateInProto)
Expand Down
4 changes: 2 additions & 2 deletions Source/ChanneldUE/FFlatStatesChannelDataProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CHANNELDUE_API FFlatStatesChannelDataProcessor : IChannelDataProcessor
public:
virtual bool Merge(const google::protobuf::Message* SrcMsg, google::protobuf::Message* DstMsg) override;
virtual const google::protobuf::Message* GetStateFromChannelData(google::protobuf::Message* ChannelData,
UClass* TargetClass, uint32 NetGUID, bool& bIsRemoved) override;
UClass* TargetClass, UObject* TargetObject, uint32 NetGUID, bool& bIsRemoved) override;
virtual void SetStateToChannelData(const google::protobuf::Message* State, google::protobuf::Message* ChannelData,
UClass* TargetClass, uint32 NetGUID) override;
UClass* TargetClass, UObject* TargetObject, uint32 NetGUID) override;
};
14 changes: 7 additions & 7 deletions Source/ChanneldUE/Replication/ChanneldReplicationComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,14 @@ bool UChanneldReplicationComponent::UpdateChannelData(google::protobuf::Message*

if (IsRemoved())
{
Processor->SetStateToChannelData(nullptr, ChannelData, Replicator->GetTargetClass(), NetGUID);
Processor->SetStateToChannelData(nullptr, ChannelData, Replicator->GetTargetClass(), Replicator->GetTargetObject(), NetGUID);
continue;
}

Replicator->Tick(FApp::GetDeltaTime());
if (Replicator->IsStateChanged())
{
Processor->SetStateToChannelData(Replicator->GetDeltaState(), ChannelData, Replicator->GetTargetClass(), NetGUID);
Processor->SetStateToChannelData(Replicator->GetDeltaState(), ChannelData, Replicator->GetTargetClass(), Replicator->GetTargetObject(), NetGUID);
Replicator->ClearState();
bUpdated = true;
}
Expand Down Expand Up @@ -277,7 +277,7 @@ void UChanneldReplicationComponent::OnChannelDataUpdated(google::protobuf::Messa
continue;
}
bool bIsRemoved = false;
auto State = Processor->GetStateFromChannelData(ChannelData, Replicator->GetTargetClass(), NetGUID, bIsRemoved);
auto State = Processor->GetStateFromChannelData(ChannelData, Replicator->GetTargetClass(), Replicator->GetTargetObject(), NetGUID, bIsRemoved);
if (State)
{
if (bIsRemoved)
Expand All @@ -302,11 +302,11 @@ void UChanneldReplicationComponent::OnChannelDataUpdated(google::protobuf::Messa
}
}

TSharedPtr<google::protobuf::Message> UChanneldReplicationComponent::SerializeFunctionParams(AActor* Actor, UFunction* Func, void* Params, FOutParmRec* OutParams, bool& bSuccess)
TSharedPtr<google::protobuf::Message> UChanneldReplicationComponent::SerializeFunctionParams(UObject* Object, UFunction* Func, void* Params, FOutParmRec* OutParams, bool& bSuccess)
{
for (auto& Replicator : Replicators)
{
if (Replicator->GetTargetObject() == Actor)
if (Replicator->GetTargetObject() == Object)
{
auto ParamsMsg = Replicator->SerializeFunctionParams(Func, Params, OutParams, bSuccess);
if (bSuccess)
Expand All @@ -320,11 +320,11 @@ TSharedPtr<google::protobuf::Message> UChanneldReplicationComponent::SerializeFu
return nullptr;
}

TSharedPtr<void> UChanneldReplicationComponent::DeserializeFunctionParams(AActor* Actor, UFunction* Func, const std::string& ParamsPayload, bool& bSuccess, bool& bDeferredRPC)
TSharedPtr<void> UChanneldReplicationComponent::DeserializeFunctionParams(UObject* Object, UFunction* Func, const std::string& ParamsPayload, bool& bSuccess, bool& bDeferredRPC)
{
for (auto& Replicator : Replicators)
{
if (Replicator->GetTargetObject() == Actor)
if (Replicator->GetTargetObject() == Object)
{
TSharedPtr<void> Params = Replicator->DeserializeFunctionParams(Func, ParamsPayload, bSuccess, bDeferredRPC);
if (bSuccess)
Expand Down
4 changes: 2 additions & 2 deletions Source/ChanneldUE/Replication/ChanneldReplicationComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ class CHANNELDUE_API UChanneldReplicationComponent : public UActorComponent, pub
virtual void OnChannelDataUpdated(google::protobuf::Message* ChannelData) override;
//~ End IChannelDataProvider Interface.

TSharedPtr<google::protobuf::Message> SerializeFunctionParams(AActor* Actor, UFunction* Func, void* Params, FOutParmRec* OutParams, bool& bSuccess);
TSharedPtr<void> DeserializeFunctionParams(AActor* Actor, UFunction* Func, const std::string& ParamsPayload, bool& bSuccess, bool& bDeferredRPC);
TSharedPtr<google::protobuf::Message> SerializeFunctionParams(UObject* Object, UFunction* Func, void* Params, FOutParmRec* OutParams, bool& bSuccess);
TSharedPtr<void> DeserializeFunctionParams(UObject* Object, UFunction* Func, const std::string& ParamsPayload, bool& bSuccess, bool& bDeferredRPC);
};
2 changes: 1 addition & 1 deletion Source/ChanneldUE/Replication/ChanneldReplicatorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class CHANNELDUE_API FChanneldReplicatorBase_BP : public FChanneldReplicatorBase
public:
FChanneldReplicatorBase_BP(UObject* InTargetObj, const FString& BlueprintPath) : FChanneldReplicatorBase(InTargetObj)
{
BpClass = LoadClass<AActor>(nullptr, *FString::Printf(TEXT("Blueprint'%s'"), *BlueprintPath));
BpClass = LoadClass<UObject>(nullptr, *FString::Printf(TEXT("Blueprint'%s'"), *BlueprintPath));
}
virtual UClass* GetTargetClass() override { return BpClass; }

Expand Down
3 changes: 2 additions & 1 deletion Source/ChanneldUE/View/ChannelDataView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -629,11 +629,12 @@ Channeld::ChannelId UChannelDataView::GetOwningChannelId(AActor* Actor) const
return GetOwningChannelId(GetNetId(Actor));
}

bool UChannelDataView::SendMulticastRPC(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg)
bool UChannelDataView::SendMulticastRPC(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg, const FString& SubObjectPathName)
{
unrealpb::RemoteFunctionMessage RpcMsg;
RpcMsg.mutable_targetobj()->set_netguid(GetNetId(Actor).Value);
RpcMsg.set_functionname(TCHAR_TO_UTF8(*FuncName), FuncName.Len());
RpcMsg.set_subobjectpath(TCHAR_TO_UTF8(*SubObjectPathName), SubObjectPathName.Len());
if (ParamsMsg)
{
RpcMsg.set_paramspayload(ParamsMsg->SerializeAsString());
Expand Down
2 changes: 1 addition & 1 deletion Source/ChanneldUE/View/ChannelDataView.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class CHANNELDUE_API UChannelDataView : public UObject
virtual Channeld::ChannelId GetOwningChannelId(const FNetworkGUID NetId) const;
virtual Channeld::ChannelId GetOwningChannelId(AActor* Actor) const;

virtual bool SendMulticastRPC(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg);
virtual bool SendMulticastRPC(AActor* Actor, const FString& FuncName, TSharedPtr<google::protobuf::Message> ParamsMsg, const FString& SubObjectPathName);

int32 SendChannelUpdate(Channeld::ChannelId ChId);
int32 SendAllChannelUpdates();
Expand Down
Loading

0 comments on commit 0d2a724

Please sign in to comment.