Question about intended use of NetDeltaSerialize

Steps to Reproduce

  • Add the following code a C++ project:

`class FTestStructDeltaState : public INetDeltaBaseState
{
public:
bool IsStateEqual(INetDeltaBaseState* Other) override
{
return TestValue == static_cast<FTestStructDeltaState*>(Other)->TestValue;
}

public:
int32 TestValue = 0;
};

USTRUCT()
struct FTestStruct
{
GENERATED_BODY()

public:
UPROPERTY()
int32 TestValue = 0;

bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaInfo)
{
if (DeltaInfo.Writer)
{
// Save current state
auto NewState = static_cast<FTestStructDeltaState*>(DeltaInfo.NewState->Get());
if (NewState == nullptr)
{
NewState = new FTestStructDeltaState();
*DeltaInfo.NewState = TSharedPtr(NewState);
}

NewState->TestValue = TestValue;

// Nothing to do if value didn’t change compared to old state
const auto OldState = static_cast<FTestStructDeltaState*>(DeltaInfo.OldState);
if (OldState && OldState->TestValue == TestValue)
{
return false;
}

// Send difference between last sent state and current value
int32 DeltaToWrite = TestValue - (OldState ? OldState->TestValue : 0);
(*DeltaInfo.Writer) << DeltaToWrite;

GEngine->AddOnScreenDebugMessage(INDEX_NONE,
1.0f,
FColor::Blue,
*FString::Printf(TEXT(“Sent delta %i → %i”), DeltaToWrite, TestValue));
}
else if (DeltaInfo.Reader)
{
int32 ReceivedDelta;
(*DeltaInfo.Reader) << ReceivedDelta;

TestValue += ReceivedDelta;

GEngine->AddOnScreenDebugMessage(INDEX_NONE,
1.0f,
FColor::Green,
*FString::Printf(TEXT(“Received delta %i → %i”),
ReceivedDelta,
TestValue));
}

return true;
}
};

template <>
struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2
{
public:
enum
{
WithNetDeltaSerializer = true,
};
};

UCLASS()
class AMyTestPawn : public APawn
{
GENERATED_BODY()

public:
AMyTestPawn()
{
bReplicates = true;
}

UPROPERTY(Replicated)
FTestStruct TestStruct;

UFUNCTION(Exec)
void ChangeTestValue()
{
if (HasAuthority())
{
++TestStruct.TestValue;
}
}

void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyTestPawn, TestStruct);
}
};`* Configure AMyTestPawn as your pawn class in your game mode

  • Go to Edit -> Editor Preferences -> Play and enable network emulation for everyone with the “Bad” profile
  • Start PIE as a listen server with two players
  • On the server instance, keep executing the ChangeTestValue function via the console
  • Observe that some deltas will not arrive on the client, leading to the values going out of sync over time