// Copyright Epic Games, Inc. All Rights Reserved. #include "NetPredictionTestDriver.h" #include "HAL/PlatformMath.h" #include "NetPredictionMockPackageMap.h" #include "NetPredictionTestChannel.h" #include "NetworkPredictionModelDefRegistry.h" #include "NetworkPredictionProxyInit.h" #include "NetworkPredictionReplicationProxy.h" #include "NetworkPredictionTests.h" #include namespace UE::Net::Private { const uint8 FNetPredictionTestDriver::ChangeFlagsBitsNeeded = 1 + FPlatformMath::FloorLog2(static_cast(EChangeFlags::MaxFlagPlusOne) - 1); struct FTestNetPredictionModelDef : public FNetworkPredictionModelDef { NP_MODEL_BODY(); using Simulation = FNetPredictionTestDriver; using StateTypes = FNetPredictionTestStateTypes; using Driver = FNetPredictionTestDriver; static const TCHAR* GetName() { return TEXT("TestModelDef"); } }; NP_MODEL_REGISTER(FTestNetPredictionModelDef); bool FNetPredictionTestSyncState::ShouldReconcile(const FNetPredictionTestSyncState& AuthorityState) const { return AutoCounter != AuthorityState.AutoCounter || InputCounter != AuthorityState.InputCounter; } void FNetPredictionTestSyncState::Interpolate(const FNetPredictionTestSyncState* From, const FNetPredictionTestSyncState* To, float Percent) { UE_LOG(LogNetworkPredictionTests, Verbose, TEXT("Interpolate: from {%.2f, %.2f} to {%.2f, %.2f}, pct %.2f."), From->AutoCounter, From->InputCounter, To->AutoCounter, To->InputCounter, Percent); AutoCounter = FMath::Lerp(From->AutoCounter, To->AutoCounter, Percent); InputCounter = FMath::Lerp(From->InputCounter, To->InputCounter, Percent); } FNetPredictionTestDriver::FNetPredictionTestDriver(UNetworkPredictionWorldManager* WorldManager, ENetMode Mode, TSharedPtr InClientToServer, TSharedPtr InServerToClient) : ClientToServer(InClientToServer) , ServerToClient(InServerToClient) { ReplicationProxy_ServerRPC.Init(&Proxy, EReplicationProxyTarget::ServerRPC); ReplicationProxy_Autonomous.Init(&Proxy, EReplicationProxyTarget::AutonomousProxy); ReplicationProxy_Simulated.Init(&Proxy, EReplicationProxyTarget::SimulatedProxy); FNetworkPredictionProxy::FInitParams Params = {WorldManager, Mode, GetReplicationProxies(), this, this}; Proxy.Init(Params); } void FNetPredictionTestDriver::ProduceInput(const int32 DeltaTimeMS, FNetPredictionTestInputCmd* Cmd) { UE_LOG(LogNetworkPredictionTests, Verbose, TEXT("ProduceInput: %s. SimFrame: %d"), *DebugName, Proxy.GetPendingFrame()); Cmd->bIncrement = bInputPressed; } void FNetPredictionTestDriver::SimulationTick(const FNetSimTimeStep& TimeStep, const TNetSimInput& SimInput, const TNetSimOutput& SimOutput) { UE_LOG(LogNetworkPredictionTests, Verbose, TEXT("SimulationTick: %s. Frame: %d"), *DebugName, TimeStep.Frame); SimOutput.Sync->InputCounter = SimInput.Sync->InputCounter; if (SimInput.Cmd->bIncrement) { SimOutput.Sync->InputCounter += 1.0f; } SimOutput.Sync->AutoCounter = SimInput.Sync->AutoCounter + 1.0f; } void FNetPredictionTestDriver::InitializeSimulationState(FNetPredictionTestSyncState* OutSync, void* OutAux) { UE_LOG(LogNetworkPredictionTests, Verbose, TEXT("InitializeSimulationState: %s"), *DebugName); OutSync->AutoCounter = 0.0f; OutSync->InputCounter = 0.0f; } void FNetPredictionTestDriver::FinalizeFrame(const FNetPredictionTestSyncState* SyncState, const void* AuxState) { UE_LOG(LogNetworkPredictionTests, Verbose, TEXT("FinalizeFrame: %s. AutoCounter: %.2f, InputCounter: %.2f"), *DebugName, SyncState->AutoCounter, SyncState->InputCounter); } void FNetPredictionTestDriver::SetHiddenForInterpolation(bool bInHidden) { bHidden = bInHidden; } void FNetPredictionTestDriver::CallServerRPC() { FServerReplicationRPCParameter ProxyParameter(ReplicationProxy_ServerRPC); FNetBitWriter Ar(1024 * 8 * 2); bool bOutSuccess = false; ProxyParameter.NetSerialize(Ar, UNetPredictionMockPackageMap::Get(), bOutSuccess); ClientToServer->Send(Ar); } void FNetPredictionTestDriver::ReceiveServerRPCs() { while (ClientToServer->HasPendingData()) { FNetBitReader Ar = ClientToServer->Receive(); FServerReplicationRPCParameter ProxyParameter; bool bOutSuccess = false; ProxyParameter.NetSerialize(Ar, UNetPredictionMockPackageMap::Get(), bOutSuccess); ProxyParameter.NetSerializeToProxy(ReplicationProxy_ServerRPC); } } void FNetPredictionTestDriver::NetSerialize(FArchive& Ar, EChangeFlags Flags) { bool bSuccess = false; Ar.SerializeBits(&Flags, ChangeFlagsBitsNeeded); if (EnumHasAnyFlags(Flags, EChangeFlags::PredictionProxyChanged)) { Proxy.NetSerialize(Ar, UNetPredictionMockPackageMap::Get(), bSuccess); } if (EnumHasAnyFlags(Flags, EChangeFlags::ReplicationProxyChanged)) { // Emulate the replication conditions from UNetworkPredictionComponent if (Proxy.GetCachedHasNetConnection()) { ReplicationProxy_Autonomous.NetSerialize(Ar, UNetPredictionMockPackageMap::Get(), bSuccess); } else { ReplicationProxy_Simulated.NetSerialize(Ar, UNetPredictionMockPackageMap::Get(), bSuccess); } } } FNetPredictionTestObject::FNetPredictionTestObject( UNetworkPredictionWorldManager* ServerWorldManager, UNetworkPredictionWorldManager* ClientWorldManager, ENetRole ClientRole) : ClientToServer(MakeShared()) , ServerToClient(MakeShared()) , ServerObject(ServerWorldManager, NM_DedicatedServer, ClientToServer, ServerToClient) , ClientObject(ClientWorldManager, NM_Client, ClientToServer, ServerToClient) { ServerObject.Proxy.InitForNetworkRole(ENetRole::ROLE_Authority, ClientRole == ENetRole::ROLE_AutonomousProxy); ClientObject.Proxy.InitForNetworkRole(ClientRole, ClientRole == ENetRole::ROLE_AutonomousProxy); } void FNetPredictionTestObject::ServerSend() { ServerObject.ReplicationProxy_Autonomous.OnPreReplication(); ServerObject.ReplicationProxy_Simulated.OnPreReplication(); // Simple emulation of not sending changed properties. // Note this only works when no "packets" are "dropped" in the tests, which is currently the case FNetPredictionTestDriver::EChangeFlags Flags = FNetPredictionTestDriver::EChangeFlags::None; if (!ProxyShadowState.Identical(&ServerObject.Proxy, 0)) { Flags |= FNetPredictionTestDriver::EChangeFlags::PredictionProxyChanged; ProxyShadowState = ServerObject.Proxy; } // Emulate the replication conditions from UNetworkPredictionComponent if (ServerObject.Proxy.GetCachedHasNetConnection()) { if (!AutonomousProxyShadowState.Identical(&ServerObject.ReplicationProxy_Autonomous, 0)) { Flags |= FNetPredictionTestDriver::EChangeFlags::ReplicationProxyChanged; AutonomousProxyShadowState = ServerObject.ReplicationProxy_Autonomous; } } else { if (!SimulatedProxyShadowState.Identical(&ServerObject.ReplicationProxy_Simulated, 0)) { Flags |= FNetPredictionTestDriver::EChangeFlags::ReplicationProxyChanged; SimulatedProxyShadowState = ServerObject.ReplicationProxy_Simulated; } } FNetBitWriter TempWriter(1024 * 8 * 2); ServerObject.NetSerialize(TempWriter, Flags); ServerToClient->Send(TempWriter); } void FNetPredictionTestObject::ClientReceive() { while(ServerToClient->HasPendingData()) { FNetBitReader TempReader = ServerToClient->Receive(); ClientObject.NetSerialize(TempReader, FNetPredictionTestDriver::EChangeFlags()); } } }