void FObjectReplicator::ReplicateCustomDeltaProperties( FOutBunch & Bunch, int32 & LastIndex, bool & bContentBlockWritten ) { if ( LifetimeCustomDeltaProperties.Num() == 0 ) { // No custom properties return; } UObject * Object = GetObject(); check( Object ); check( OwningChannel ); UNetConnection * OwningChannelConnection = OwningChannel->Connection; // Replicate those properties. for ( int32 i = 0; i < LifetimeCustomDeltaProperties.Num(); i++ ) { // Get info. const int32 RetireIndex = LifetimeCustomDeltaProperties[i]; FPropertyRetirement & Retire = Retirement[RetireIndex]; FRepRecord * Rep = &ObjectClass->ClassReps[RetireIndex]; UProperty * It = Rep->Property; int32 Index = Rep->Index; const int32 BitsWrittenBeforeThis = Bunch.GetNumBits(); // If this is a dynamic array, we do the delta here TSharedPtr<INetDeltaBaseState> & OldState = RecentCustomDeltaState.FindOrAdd( RetireIndex ); TSharedPtr<INetDeltaBaseState> NewState; // Update Retirement records with this new state so we can handle packet drops. FPropertyRetirement ** Rec = UpdateAckedRetirements( Retire, OwningChannelConnection->OutAckPacketId ); ValidateRetirementHistory( Retire ); // Our temp writer should always be in a reset state here check( TempBitWriter->GetNumBits() == 0 ); //----------------------------------------- // Do delta serialization on dynamic properties //----------------------------------------- const bool WroteSomething = SerializeCustomDeltaProperty( OwningChannelConnection, (void*)Object, It, Index, *TempBitWriter, NewState, OldState ); if ( !WroteSomething ) { continue; } check( TempBitWriter->GetNumBits() > 0 ); *Rec = new FPropertyRetirement(); // Remember what the old state was at this point in time. If we get a nak, we will need to revert back to this. (*Rec)->DynamicState = OldState; // Save NewState into the RecentCustomDeltaState array (old state is a reference into our RecentCustomDeltaState map) OldState = NewState; // Write header, and data to send to the actual bunch RepLayout->WritePropertyHeader( Object, ObjectClass, OwningChannel, It, Bunch, Index, LastIndex, bContentBlockWritten ); // Send property. Bunch.SerializeBits( TempBitWriter->GetData(), TempBitWriter->GetNumBits() ); // Reset our temp bit writer TempBitWriter->Reset(); } }
void FObjectReplicator::ReplicateCustomDeltaProperties( FOutBunch & Bunch, FReplicationFlags RepFlags, bool & bContentBlockWritten ) { if ( LifetimeCustomDeltaProperties.Num() == 0 ) { // No custom properties return; } UObject* Object = GetObject(); check( Object ); check( OwningChannel ); UNetConnection * OwningChannelConnection = OwningChannel->Connection; // Initialize a map of which conditions are valid bool ConditionMap[COND_Max]; const bool bIsInitial = RepFlags.bNetInitial ? true : false; const bool bIsOwner = RepFlags.bNetOwner ? true : false; const bool bIsSimulated = RepFlags.bNetSimulated ? true : false; const bool bIsPhysics = RepFlags.bRepPhysics ? true : false; ConditionMap[COND_None] = true; ConditionMap[COND_InitialOnly] = bIsInitial; ConditionMap[COND_OwnerOnly] = bIsOwner; ConditionMap[COND_SkipOwner] = !bIsOwner; ConditionMap[COND_SimulatedOnly] = bIsSimulated; ConditionMap[COND_AutonomousOnly] = !bIsSimulated; ConditionMap[COND_SimulatedOrPhysics] = bIsSimulated || bIsPhysics; ConditionMap[COND_InitialOrOwner] = bIsInitial || bIsOwner; ConditionMap[COND_Custom] = true; // Replicate those properties. for ( int32 i = 0; i < LifetimeCustomDeltaProperties.Num(); i++ ) { // Get info. const int32 RetireIndex = LifetimeCustomDeltaProperties[i]; FPropertyRetirement & Retire = Retirement[RetireIndex]; FRepRecord * Rep = &ObjectClass->ClassReps[RetireIndex]; UProperty * It = Rep->Property; int32 Index = Rep->Index; if (LifetimeCustomDeltaPropertyConditions.IsValidIndex(i)) { // Check the replication condition here ELifetimeCondition RepCondition = LifetimeCustomDeltaPropertyConditions[i]; check(RepCondition >= 0 && RepCondition < COND_Max); if (!ConditionMap[RepCondition]) { // We didn't pass the condition so don't replicate us continue; } } const int32 BitsWrittenBeforeThis = Bunch.GetNumBits(); // If this is a dynamic array, we do the delta here TSharedPtr<INetDeltaBaseState> & OldState = RecentCustomDeltaState.FindOrAdd( RetireIndex ); TSharedPtr<INetDeltaBaseState> NewState; // Update Retirement records with this new state so we can handle packet drops. // LastNext will be pointer to the last "Next" pointer in the list (so pointer to a pointer) FPropertyRetirement ** LastNext = UpdateAckedRetirements( Retire, OwningChannelConnection->OutAckPacketId ); check( LastNext != NULL ); check( *LastNext == NULL ); ValidateRetirementHistory( Retire ); FNetBitWriter TempBitWriter( OwningChannel->Connection->PackageMap, 0 ); //----------------------------------------- // Do delta serialization on dynamic properties //----------------------------------------- const bool WroteSomething = SerializeCustomDeltaProperty( OwningChannelConnection, (void*)Object, It, Index, TempBitWriter, NewState, OldState ); if ( !WroteSomething ) { continue; } *LastNext = new FPropertyRetirement(); // Remember what the old state was at this point in time. If we get a nak, we will need to revert back to this. (*LastNext)->DynamicState = OldState; // Save NewState into the RecentCustomDeltaState array (old state is a reference into our RecentCustomDeltaState map) OldState = NewState; // Write header, and data to send to the actual bunch RepLayout->WritePropertyHeader( Object, ObjectClass, OwningChannel, It, Bunch, Index, bContentBlockWritten ); const int NumStartingBits = Bunch.GetNumBits(); // Send property. Bunch.SerializeBits( TempBitWriter.GetData(), TempBitWriter.GetNumBits() ); NETWORK_PROFILER(GNetworkProfiler.TrackReplicateProperty(It, Bunch.GetNumBits() - NumStartingBits)); } }