Multiplayer bugs becoming more prevalent - Harden & Improve Network / Multiplayer Support!

Oh okay, are you using Suggest Velocity node or something? It’s hard to say without seeing it all to be honest (probably good for another thread anyway). Either way, so long as Server is calculating everything and sets velocity as soon as object is spawned, client object will follow.

I went through this whole thing with ‘what runs in what order’… because OnPostLogin runs at a point you wouldn’t expect it would… anyway, my results/findings are here (a bit down in thread): Game Mode, replication, and running on clients - Multiplayer & Networking - Epic Developer Community Forums

To replicate a DateTime you can create a UStruct that wraps it and make your own serialization, that would do trick ^^

BeginPlay() is an interesting one because on Server, it fires when Gamemode calls ‘StartPlay’ - but on Clients (since they don’t have a GameMode) - it get’s called immediately as soon as a player loads into world. I’m not sure if that’s really a bug or not, but it did catch me out a lot in beginning. I think doing so allows actor to receive data from server, which is essential at very start of game for things like it’s network role and owner etc, and receiving RPC’s.

Construction Script thing is more of a general programming thing than something specific to Unreal. Constructor is always first thing that runs whenever you create a new instance of an object.

Awesome thread. Very interesting to know about, since i love to build stuff in multiplayer.

** Widget vanishing thing: **

Is this also happening if you simulate death? Like “Unpossess” then “DestroyActor” on Pawn and then Respawn it and “Possess” again?
Because i’m doing this in my Marketplace Project and clients have no problem in 4.10 with vanishing widgets.

Is there something more to it?

**SetOwner in Blueprints (and C++?): **

An important thing for replication on my end is SetOwner to allow a client to call a RunOnServer on an Actor that he is no owner of.
I had a simple setup with a door, an overlap collision and Client/Server. As soon as Client moved into Overlap, i filter OnBeginOverlap
for Server and let Server set Owner of Door to Client. Which, in my mind, should enable a RunOnServer call for client.
That simply did not work. To “workaround” this, i put RunOnServer event into Controller and passed it door actor to let Server
open it that way.

Already asked that a few months ago, but now, since someone mentioned SetOwner thing, i wanted to make sure that i’m not misunderstanding
SetOwner thing. Did i use it wrong or is it broken if that didn’t work?

**All in all… **

… i would also really love to see more stuff happening for Networking. ShooterGame is a good source, but as you said, fairly old.
And networking people are pretty rare. Most of time i feel like one of only devs who knows about networking and also shares that knowledge.

Not in my case, vehicles are persistent and remain in level until they are killed off. pilot however is spawned when hop-out of vehicle, so perhaps there is something to it there. if a player hops out of a vehicle, a new character is spawned for them and they take control of it. If they hop into a vehicle, character is destroyed. (This is a bit inefficient but was quickest way to to it instead of pooling them / hiding them out-of-world somewhere).

I think that there’s a possibility that widget is destroyed and rebuilt locally before client properly sets up new pawn it receives from server. Mind you, it strikes me as a bit weird that you can’t change pawn without having to rebuild widgets anyway.

As for door thing - In that case I would just check for overlap event on Server instead of Client, since they’re both in sync anyway right, and have Server open door object. (I may be missing something here though).

Yeah i forgot to mention that overlap is only enabling Input and then real opening happens by key press, which needs to be replicated of course.
Sorry wasn’t really awake when writing this :smiley:

Well, it sounds really awkward that your widgets disappear. I mean, as long as you don’t save them on Character that you destroy, it shouldn’t be affected, should it?
Where do you create and save widget, that it is affected by PlayerController possession?

I didn’t even know it is, until this thread and i never experienced that :open_mouth:

Hi TheJamsh,

Thanks for thorough thread! There’s some very valuable information in here that I would love to get to Docs team as we let them know what knowledge gaps exist between docs and community. I’ll be doing a pass of info to get for them, and I’ll pull from this thread. If there’s any particular information missing documentation, please point it out and I can pass it along as well.

As for two bug reports you linked to:

first was closed when we didn’t hear back from you. Can you follow up with Rudy and get him what he needs to enter a bug report? I understand you were speaking with Darnell about it, but I don’t know for certain if he entered anything. Thanks!

second wasn’t in Bug Reports section, so we missed it. We can’t always catch a possible bug if it’s not in right area, unfortunately, as we simply don’t have numbers on our staff. I’ve moved it over, because it does seem like either a bug or missing functionality to me. I’ll get some of our guys to look into it, and they may have some follow up questions for you. Then we can get a bug entered.

I don’t know when/if a networking pass will come for engine. I know that networking devs in particular have all been working hard on Paragon title, and some of that work may get moved over to our main branch at some point, but it has kept them from being able to focus on reports we’ve entered thus far. I’m hoping that once they have more time, they’ll be able to address some of these issues. But that will only happen if we continue to report them, so please continue letting us know about particular issues you run into!

Hey ,

All great stuff! If any of Networking folks have any time to spare (unlikely I know) and they could take a look at this thread and post their own thoughts, that too would be great, It would be good to get a discussion started with them. If they’re not on Paragon they’re probably on UT :smiley:

Another request I’d like to ask for:

ability to debug specific clients when using PIE and Visual Studio. Blueprint allows you to select which world you use for debugging / breakpoints etc. Visual Studio currently doesn’t seem to have a way of doing this, and only workaround I can think of is to package game, start a session and attach to client process. This is quite convoluted and difficult, whereas blueprint allows you to easily switch which world you’re debugging in realtime.

This feature is almost essential for tracking down issues!

Another request from Slack group, native support for origin re-basing in Multiplayer games.

Amazing,
Why I didn’t see this before. I’m having troubles to start learning MP simply because I always face bugs even in simple stuff. For example, editing weapons in runtime would crash game if client does it. Server can. Apparently, I had to untick replicate actor option, compile, tick option again, then compile again :-o
Also widget just doesn’t work for me. It never appears for clients.
I agree with previous posts, very little resources out there and most of them talking about almost same things.
Would be great if MP get more attention, more tutorials (real practical ones, I’m tired of seeing word “simple” in tutorials). And people in this page you can always share what you’ve learned and help beginners (like me) to learn.

Many thanks for thread and bringing this topic :slight_smile:

Happy new year to you all

Totally agree! More attention to MP and Networking is needed :mad: also make Blueprints faster according to https://forums.unrealengine.com/showthread.php?1105-Blueprint-Performance-Benchmark which is very important when it comes to multiplayer games.

It’s important to remember that Blueprints were conceived to make programming more open to artists, so that programmers weren’t always bottleneck of a project. Being able to make a game with them entirely is somewhat of a side-effect. Having worked on three MP titles in UE4 now, I would say that if you’re doing anything particularly hardcore or heavily Multiplayer orientated, C++ is king. You get a lot of fine control by doing so. BP is great, but MP support is very basic (and probably always will be).


This will be a bit of a difficult thread to control since a lot of MP ‘bugs’ can often be placed back to developers misunderstanding, since MP can be a complex beast. Always worth bearing that in mind when posting in this thread, but I’ll try to help ppl out to best of my knowledge :slight_smile: I’m no expert though…

Origin rebasing will never work in multiplayer. Or at least I dont see as reasonable solution. Server have it one version of world, how do you rebase origin to match all clients in world ? You will run into precision issues on server side.
Even if you figure it out, there is still problem with client server coordinate translation.
Segmented world could be an option,but that would probably require how world treated in Unreal, which means heavy refactoring on all Engine layers.

Segmented world of some kind is on trello backlog and I’ve tried if they have any plans on doing them sometime in future, but nobody has responded. Large world coordinate system question - Feedback & Requests - Epic Developer Community Forums

I imagine that Origin Rebasing would require server to be able to monitor multiple worlds at same time, but I agree it would be a massive undertaking. To be fair, if you’re making something on that scale and you don’t have a full time multiplayer / network engineer on your dev team then it’s time to advertise a job opportunity… It’s a full-time project long job if you want to do multiplayer on that scale.

I have just posted source code for my issue with OnRep functionality on Answerhub, but I am also posting example case here. comments explain what’s going on - but don’t expect this to be easy to decipher out of context.



// This function is called both Server & Client-Side based on a timer. ONLY  Server Packs  data into  compressed byte.
// This means, that  client is NEVER modifying  compressed byte, only  values that are derived from it. Therefore, OnRep should always fire, correct?
// This is done so that although clients can display  'heat ratio' of  current weapon, they cannot 'unlock' it when it cools down - only  server can.

void ABZGame_Weapon::ApplyCool()
{
	HeatProgressRatio = FMath::Clamp(HeatProgressRatio - WeaponConfig.HeatRecoverySpeed * WEAPON_COOLDOWN_DELTA, 0.f, 1.f);

	if (OwningGameObject) { OwningGameObject->UpdateFloatPropertyAllMaterials(OwningGameObject->HardPoints[WeaponIndex].MuzzleSocketName, HeatProgressRatio); }

	// Only server can open  HeatLock
	if (Role == ROLE_Authority && HeatProgressRatio <= WeaponConfig.EnableThreshold && bOverheatLocked == true)
	{
		bOverheatLocked = false;
	}

	if (Role == ROLE_Authority)
	{
		PackOverheatData();
	}

	if (HeatProgressRatio == 0.f)
	{
		GetWorldTimerManager().ClearTimer(TimerHandle_WeaponCooldown);
	}
}

// This function is called whenever a projectile is fired, or whenever  client reaches  point where it would fire a projectile, IF it was  server.
// This way, clients apply heat locally so that it appears responsive regardless of latency. We can likely trust  client here.
// Like before, ONLY  Server can modify  Packed Data.
//  client CAN lock their weapon, but they cannot UNLOCK it. This is fine, because  server will correct them, and we never want a client to be able to fire when  server says they can't.
// For rapid-fire weapons,  time it takes to recieve  lock status will be too slow.

void ABZGame_Weapon::ApplyHeat(const float HeatIncrease)
{
	HeatProgressRatio = FMath::Clamp(HeatProgressRatio + HeatIncrease, 0.f, 1.f);

	if (OwningGameObject) { OwningGameObject->UpdateFloatPropertyAllMaterials(OwningGameObject->HardPoints[WeaponIndex].MuzzleSocketName, HeatProgressRatio); }

	// If  timer hasn't already been set by ApplyCool, we can apply it here:
	if (HeatProgressRatio != 0.f && !GetWorldTimerManager().TimerExists(TimerHandle_WeaponCooldown))
	{
		GetWorldTimerManager().SetTimer(TimerHandle_WeaponCooldown, this, &ABZGame_Weapon::ApplyCool, WEAPON_COOLDOWN_DELTA, true, WEAPON_COOLDOWN_DELTA);
	}

	// This may need to be IsNearlyEqual if this is called after Ticking  ApplyCool
	if (HeatProgressRatio == 1.f)
	{
		bOverheatLocked = true;
		StopFire();
	}

 	if (Role == ROLE_Authority)
 	{
		PackOverheatData();
	}
}

// Packs  overheat data into a single byte.
// IN THIS CASE, I have added '1' to  initial struct so that replication still occurs when  cooldown is recieved. Without adding '1',  data doesn't cause OnRep to fire when  value is zero.
// TO circumvent this, remove  + 1 and use HeatProgressRatio * 126.0f instead.

void ABZGame_Weapon::PackOverheatData()
{
	if (HeatProgressRatio > 1.f && HeatProgressRatio < 0.f)
	{
		UE_LOG(LogBZOnline, Warning, TEXT("Weapon %s heat ratio clamped for Network Packing. Prev Value %f"), *GetNameSafe(this), HeatProgressRatio);
		HeatProgressRatio = FMath::Clamp(HeatProgressRatio, 0.f, 1.f);
	}

	// Add 1 to force replication even when Zero
	OverheatData = (HeatProgressRatio * 125.f) + 1;
	if (bOverheatLocked)
	{
		OverheatData = FMath::Clamp(OverheatData + 128, 0, 255);
		const bool bCheck = true;
	}
}

// Fired when  client recieves  overheat data, and they can determine from  values whether they are locked or not.
// Remove "OverheatData -= 1" and change /125.f to /126.f to test  replication issue.

void ABZGame_Weapon::OnRep_OverheatData()
{
	const bool RcvdLock = (OverheatData > 127) ? true : false;
	if (bOverheatLocked != RcvdLock)
	{
		bOverheatLocked = RcvdLock;
		if (bOverheatLocked == true)
		{
			// On Burst Finished - Shouldn't be required if this is done properly!
		}
	}

	if (RcvdLock)
	{
		OverheatData = FMath::Clamp(OverheatData - 128, 0, 255);
	}

	OverheatData -= 1;
	HeatProgressRatio = OverheatData / 125.f;
	if (OwningGameObject) { OwningGameObject->UpdateFloatPropertyAllMaterials(OwningGameObject->HardPoints[WeaponIndex].MuzzleSocketName, HeatProgressRatio); }
}

// Called on  local firing client only.

void ABZGame_Weapon::FireWeapon()
{
	if (WeaponConfig.SalvoCount > 1)
	{
		HandleSalvo();
	}
	else
	{
		// Simulation - FX, Audio & Heat
		if (MyPawn && MyPawn->IsLocallyControlled())
		{
			if (GetNetMode() != NM_DedicatedServer) { SimulateWeaponFire(); }
			if (WeaponConfig.HeatPerShot != 0.f) { ApplyHeat(WeaponConfig.HeatPerShot); }
		}

		ServerFireProjectile(GetMuzzleLocation(), GetAdjustedAim());
	}
}

// Called on  Server Only (obviously)

void ABZGame_Weapon::ServerFireProjectile_Implementation(FVector Origin, FVector_NetQuantizeNormal ShootDir)
{
	UseAmmo();

	//  server runs  firing simulation for non-local pawns only, since it's already simulated for itself in FireWeapon or HandleFiring
	if (MyPawn && !MyPawn->IsLocallyControlled())
	{
		if (GetNetMode() != NM_DedicatedServer) { SimulateWeaponFire(); }
		if (WeaponConfig.HeatPerShot != 0.f && MyPawn && !MyPawn->IsLocallyControlled()) { ApplyHeat(WeaponConfig.HeatPerShot); }
	}

	const FTransform SpawmTM(ShootDir.Rotation(), Origin);
	ABZGame_Ordnance* Projectile = bUseOrdnanceCaching ? FindFirstInactiveOrdnance() : Cast<ABZGame_Ordnance>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, WeaponConfig.OrdnanceClass, SpawmTM, ESpawnActorCollisionHandlingMethod::AlwaysSpawn, this));
	if (Projectile)
	{
		if (!bUseOrdnanceCaching)
		{
			Projectile->SetOwningWeapon(this);
			UGameplayStatics::FinishSpawningActor(Projectile, SpawmTM);
		}

		Projectile->InitializeProjectile(SpawmTM);
	}
}


EDIT: Sod it, here’s source code to replicate widget issue too. This is almost identical to ShooterGame’s method - except it uses a User Widget instead of a Slate Widget. Swapping Pawn possession mid game is easy enough to try yourself.



void ABZGame_PlayerController::ClientGameStarted_Implementation()
{
	bAllowGameActions = true;

	// Enable controls mode now  game has started
	SetIgnoreMoveInput(false);

	if (BZPlayerHUD.IsValid())
	{
		BZPlayerHUD->SetMatchState(EBZGameMatchState::Playing);
		BZPlayerHUD->ShowScoreboard(false);
		BZPlayerHUD->ShowUI(true);
	}

	bGameEndedFrame = false;

	// Send round start event
	const auto Events = Online::GetEventsInterface();
	ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player);

	if (LocalPlayer != nullptr && Events.IsValid())
	{
		auto UniqueId = LocalPlayer->GetPreferredUniqueNetId();

		if (UniqueId.IsValid())
		{
			FOnlineEventParms Params;

			// Generate a new session id
			Events->SetPlayerSessionId(*UniqueId, FGuid::NewGuid());
			Events->TriggerEvent(*UniqueId, TEXT("PlayerSessionStart"), Params);

			bHasSentStartEvents = true;
		}
	}
}

bool ABZGame_InGameHUD::ShowUI(bool bEnable, bool bFocus /*= false*/)
{
	if (bIsUIVisible == bEnable)
	{
		// If  UI is already enabled, disable it in favor of  new request
		if (bEnable)
		{
			ToggleUI();
		}
		else
		{
			return false;
		}
	}

	if (bEnable)
	{
		ABZGame_PlayerController* MyPC = Cast<ABZGame_PlayerController>(PlayerOwner);
		if (MyPC == NULL /*|| MyPC->IsGameMenuVisible()*/)
		{
			return false;
		}
	}

	bIsUIVisible = bEnable;
	if (bIsUIVisible && ScoreboardWidget)
	{
		ActiveGameWidget = CreateWidget<UBZGame_InGameWidget>(PlayerOwner, GameWidget);
		if (ActiveGameWidget)
		{
			ActiveGameWidget->AddToViewport(0);

			if (bFocus)
			{
				ActiveGameWidget->SetKeyboardFocus();
			}
		}
	}
	else if (ActiveGameWidget)
	{
		ActiveGameWidget->RemoveFromParent();

		if (bFocus)
		{
			// Make Sure Viewport Has Focus
			FSlateApplication::Get().SetAllUserFocusToGameViewport();
		}
	}

	return true;
}


Hi everyone,

I’m sorry you have been running into issues with multiplayer. networking team has actually been really busy helping out on Paragon, and in meantime, we have been accumulating a backlog of engine networking bugs. Once Paragon work settles down a bit, we are planning on spending more time on fixing these bugs, including ones that have been mentioned in this thread.

I’m one who added option and changed default setting. This was actually changed in 4.9, and mentioned in 4.9 release notes:

This was done as part of a bandwidth optimization push, and there was some debate internally on whether to change default or not. UT was already using lower precision for their replicated movement, and ultimately we decided on on default that would use less bandwidth.

If there were other changes you noticed that weren’t documented, please mention them so that we can figure out what happened and try to make sure all future changes do get documented.

This could be difficult due to fact that Visual Studio itself isn’t aware of UE4’s World/PIE setup. It might be possible to do something with a Visual Studio extension, but that’s getting outside my area of expertise. I can offer some tips that might make debugging multiple PIE worlds a little easier in Visual Studio, though:

  • If you have access to a UWorld pointer at some level of callstack which you’re debugging, you can check it’s value, or world’s name, to distinguish which world is currently being debugged (assuming there aren’t world pointers pointing between PIE instances - this would be weird).
  • If you’re debugging something that happens within, say, UWorld::Tick call, you can do something like print a log message with world’s name at beginning of tick. Then when you hit a breakpoint, log message should be near bottom, indicating world that’s ticking.
  • If you need to distinguish between a server PIE world and a client PIE world, you can add a watch on world’s NetDriver->ServerConnection member. If world is a server, it will be null. If it’s a client, it will be non-null.

we cant have our pawn locally controlled if we check box “movement replication” because server will correct our client position every time we try to move our pawn locally…

but i read on answerhub that we can make client authorative on his position, this still work? i read this:

but i cant found any game ini setting, i just found a DefaultGame.ini and i tried to put those line inside it, but this dont work, client isnt authorative, or i did something wrong but cant find what

if someone know how to force client to be authorative, tell me pls, or where to find this game ini settings file?

i dont care about players cheating, and i care about good and reactive control for players. i need to know if i can enable my pawn to be client authorative on his position

Is there any progress on 1024+ chars replication?