[Logs + NProf Included] Replication woes...

We’re seeing issues with a Multiplayer game we’re building, where we can’t seem to get reliable replication and data transfer working between server and clients despite the fact that the data is tagged as reliable. Even simple Boolean’s are not being replicated reliably, and often not at all. The screenshot below is an image of the Unreal NetworkProfiler tool, profiling just a few seconds of gameplay with a single attached client. Frankly I have no idea what I’m looking at or how to optimize anything, so can anyone tell me what I’m looking at?

Log is here:

Our architecture is quite unique in that 4 players need to be able to interact with one object. So what we have going on is the Players send information to their pawns, which relays that information to the appropriate actor. This gives us a headache straight away, because technically nobody ‘owns’ that actor. As such we have to do RPC calls for anything and everything we want to do to that object through the Pawn.

Alongside that, we also have a fairly substantial struct as part of that object, all of which must be reliably replicated out to the players, or they won’t be able to interact properly. Even in a local (127.0.0.1) networked game, we’re experiencing the issue of reliable variables and functions never being called or replicated. Tweaking with cull distance, relevancy and priority has little if any effect, and even then the lack of replication is so random I don’t think that these are the cause of the issue.

Our logic is sound, we’re 99% sure we’ve done everything we have to do. The end result is to have 32 players using this game over LAN, but even forcing a LAN connection on doesn’t always give us reliable replication. The game runs comfortably at 90+ FPS on a GTX 970 with little to no CPU time, so we’re not even doing anything particularly complex.

How can we better structure our system to replicate more reliably? This is eventually going to be part of a tourist attraction, and as such we need to be able to have faith in the system once it’s installed. Here is the struct that each of the 8 objects needs to replicate to all clients. Spawning in less players and objects does help, but still doesn’t feel very reliable and trustworthy. All we’re doing is manipulating the values of structs, there’s nothing particularly expensive or complex going on. Are we simply asking too much?



/* Struct About the units CURRENT Power States */
USTRUCT(BlueprintType)
struct FGESPowerVars
{
	GENERATED_USTRUCT_BODY()

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bAMP1_Active;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bAMP2_Active;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bBattery1_Active;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bBattery2_Active;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery1_PowerLevel;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery2_PowerLevel;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery1_HeatLevel;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery2_HeatLevel;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery1_CurrentPowerDemand;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery2_CurrentPowerDemand;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery1_CurrentHeatDemand;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery2_CurrentHeatDemand;


	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bAMP1_ChargingBattery1;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bAMP1_ChargingBattery2;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bAMP2_ChargingBattery1;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		bool bAMP2_ChargingBattery2;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<bool> Components_PoweredByBattery1;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<bool> Components_PoweredByBattery2;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<bool> Components_RequestingPower;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<bool> Components_Overheated;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<float> Components_CurrentHeatLevel;

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery1_CurrentChargeSpeed;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery2_CurrentChargeSpeed;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery1_AmpHeatValue;
	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		float Battery2_AmpHeatValue;

	FGESPowerVars()
		: bAMP1_Active(false)
		, bAMP2_Active(false)
		, bBattery1_Active(false)
		, bBattery2_Active(false)
		, Battery1_PowerLevel(0.f)
		, Battery2_PowerLevel(0.f)
		, Battery1_HeatLevel(0.f)
		, Battery2_HeatLevel(0.f)
		, bAMP1_ChargingBattery1(false)
		, bAMP1_ChargingBattery2(false)
		, bAMP2_ChargingBattery1(false)
		, bAMP2_ChargingBattery2(false)
		, Battery1_CurrentPowerDemand(0.f)
		, Battery2_CurrentPowerDemand(0.f)
		, Battery1_CurrentHeatDemand(0.f)
		, Battery2_CurrentHeatDemand(0.f)
		, Battery1_CurrentChargeSpeed(0.f)
		, Battery2_CurrentChargeSpeed(0.f)
		, Battery1_AmpHeatValue(0.f)
		, Battery2_AmpHeatValue(0.f)
	{
		Components_PoweredByBattery1.Init(6);
		Components_PoweredByBattery2.Init(6);
		Components_RequestingPower.Init(6);
		Components_Overheated.Init(6);
		Components_CurrentHeatLevel.Init(6);

		for (int index = 0; index <= 5; index++)
		{
			Components_PoweredByBattery1[index] = false;
			Components_PoweredByBattery2[index] = false;
			Components_Overheated[index] = false;
		}
	}
};

/* Struct About the units CURRENT Radio States */
USTRUCT(BlueprintType)
struct FGESRadioVars
{
	GENERATED_USTRUCT_BODY()

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		int32 RadioNumber;

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<float> Radios_RequiredFrequency;

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<float> Radios_CurrentFrequency;

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<int32> Radio_StationSelection;

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<bool> Radio_RequestState;

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		TArray<FString> Radio_StationNameList;

	UPROPERTY(BlueprintReadWrite, Category = "Hud")
		FString Radio_CurrentStationName;

	FGESRadioVars()
		: RadioNumber(0)
	{
		Radios_RequiredFrequency.Init(6);
		Radios_CurrentFrequency.Init(6);
		Radio_StationSelection.Init(6);
		Radio_RequestState.Init(6);

		for (int index = 0; index <= 5; index++)
		{
			Radio_RequestState[index] = false;
		}
	}
};