Unreal属性同步机制

发布时间 2023-06-30 21:02:12作者: billin

因为工作需要,需要整理一下属性复制流程

//复制准备
void AActor::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker)
{
	// Attachment replication gets filled in by GatherCurrentMovement(), but in the case of a detached root we need to trigger remote detachment.
	AttachmentReplication.AttachParent = nullptr;
	AttachmentReplication.AttachComponent = nullptr;
    //打包移动相关的属性到ReplicatedMovement结构体中,准备复制
	GatherCurrentMovement();

	DOREPLIFETIME_ACTIVE_OVERRIDE(AActor, ReplicatedMovement, IsReplicatingMovement());

	// Don't need to replicate AttachmentReplication if the root component replicates, because it already handles it.
	DOREPLIFETIME_ACTIVE_OVERRIDE(AActor, AttachmentReplication, RootComponent && !RootComponent->GetIsReplicated());


	PRAGMA_DISABLE_DEPRECATION_WARNINGS
	UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass());
	if (BPClass != nullptr)
	{
		BPClass->InstancePreReplication(this, ChangedPropertyTracker);
	}
	PRAGMA_ENABLE_DEPRECATION_WARNINGS
}

 

打包移动相关属性,包括子对象

//移动属性打包,包括子对象属性打包
void AActor::GatherCurrentMovement()
{
    // 需要复制移动属性 || 包含子对象
	if (IsReplicatingMovement() || (RootComponent && RootComponent->GetAttachParent()))
	{
		bool bWasAttachmentModified = false;
		bool bWasRepMovementModified = false;
        //暂存附加的旧对象
		AActor* OldAttachParent = AttachmentReplication.AttachParent;
		USceneComponent* OldAttachComponent = AttachmentReplication.AttachComponent;
	    //附加复制对象重置为空
		AttachmentReplication.AttachParent = nullptr;
		AttachmentReplication.AttachComponent = nullptr;
        
		UPrimitiveComponent* RootPrimComp = Cast<UPrimitiveComponent>(GetRootComponent());
		//需要物理模拟,打包物理属性进行同步
        if (RootPrimComp && RootPrimComp->IsSimulatingPhysics())
		{
			FRigidBodyState RBState;
			RootPrimComp->GetRigidBodyState(RBState);

			ReplicatedMovement.FillFrom(RBState, this);
			
			// Technically, the values might have stayed the same, but we'll just assume they've changed.
			bWasRepMovementModified = true;
		}
        //如果存在根组件
		else if (RootComponent != nullptr)
		{
			// If we are attached, don't replicate absolute position, use AttachmentReplication instead.
			if (RootComponent->GetAttachParent() != nullptr)
			{
				// Networking for attachments assumes the RootComponent of the AttachParent actor. 
				// If that's not the case, we can't update this, as the client wouldn't be able to resolve the Component and would detach as a result.
				AttachmentReplication.AttachParent = RootComponent->GetAttachParent()->GetAttachmentRootActor();
				if (AttachmentReplication.AttachParent != nullptr)
				{
                    //复制移动修正属性到AttachmentReplication
					AttachmentReplication.LocationOffset = RootComponent->GetRelativeLocation();
					AttachmentReplication.RotationOffset = RootComponent->GetRelativeRotation();
					AttachmentReplication.RelativeScale3D = RootComponent->GetRelativeScale3D();
					AttachmentReplication.AttachComponent = RootComponent->GetAttachParent();
					AttachmentReplication.AttachSocket = RootComponent->GetAttachSocketName();

					// Technically, the values might have stayed the same, but we'll just assume they've changed.
					bWasAttachmentModified = true;
				}
			}
            //如果自身就是根组件
			else
			{
				ReplicatedMovement.Location = FRepMovement::RebaseOntoZeroOrigin(RootComponent->GetComponentLocation(), this);
				ReplicatedMovement.Rotation = RootComponent->GetComponentRotation();
				ReplicatedMovement.LinearVelocity = GetVelocity();
				ReplicatedMovement.AngularVelocity = FVector::ZeroVector;

				// Technically, the values might have stayed the same, but we'll just assume they've changed.
				bWasRepMovementModified = true;
			}

			bWasRepMovementModified = (bWasRepMovementModified || ReplicatedMovement.bRepPhysics);
			ReplicatedMovement.bRepPhysics = false;
		}
        //如果Movement数据有修改,make dirty
		if (bWasRepMovementModified)
		{
			MARK_PROPERTY_DIRTY_FROM_NAME(AActor, ReplicatedMovement, this);
		}
        //如果关联对象有修改,make dirty
		if (bWasAttachmentModified ||
			OldAttachParent != AttachmentReplication.AttachParent ||
			OldAttachComponent != AttachmentReplication.AttachComponent)
		{
			MARK_PROPERTY_DIRTY_FROM_NAME(AActor, AttachmentReplication, this);
		}
	}
}