Shotgun weapon trace causes noticable lag

So I created a shotgun weapon class which simply calls fireweapon several times in a loop to create a nice spread of pellets. It works great unless playing on a network client. When you do so there is a noticeable delay in the movement of the character. He stops moving for a brief moment as observed on the listen server, a judder in movement is observed on the client as well.

This does not occur in standalone mode, or on listen servers. How can I prevent this and still have a shotgun in my game?

Here is the Fire Weapon Code, taken from Shootergame

void ABBWeapon::FireWeapon()
{
	if (MyPawn)
	{
		int32 RandSeed = FMath::Rand();
		FRandomStream WeaponRandomStream(RandSeed);
		float CurrentSpread = GetCurrentSpread();
		float ConeHalfAngle = FMath::DegreesToRadians(CurrentSpread * 0.5f);
		
		FRotator UnusedRot;
		FVector StartTrace;
		FVector AimDir = MyPawn->GetBaseAimRotation().Vector();
		MyPawn->Controller->GetPlayerViewPoint(StartTrace, UnusedRot);
		StartTrace = StartTrace + AimDir * ((MyPawn->GetActorLocation() - StartTrace) | AimDir);
		FVector ShootDir = WeaponRandomStream.VRandCone(AimDir, ConeHalfAngle, ConeHalfAngle);
		FVector EndTrace = StartTrace + ShootDir * WeaponRange;

		FHitResult Impact = WeaponTrace(StartTrace, EndTrace);
		ProcessInstantHit(Impact, StartTrace, ShootDir, RandSeed, CurrentSpread);

		CurrentFiringSpread = FMath::Min(WeaponSpreadMax, CurrentFiringSpread + WeaponSpreadIncrement);
	}
}

And then in a subclass for the shotgun FireWeapon looks like this:

void ABBShotGun::FireWeapon()
{
	for (int32 i = 0; i < PelletCount; i++)
	{
		Super::FireWeapon();
	}
}

Ideas?

EDIT: After more debugging, I discovered the culprit is the line ServerProcessInstantHit(Impact, Origin, ShootDir, RandSeed, AimSpread); Which is located in ProcessInstantHit below. All it does is call ProcessInstant Hit on the server. But clearly calling an RPC 15 times in quick succession is too much of an ask for the networking system.

Any idea’s on how to make this faster?

void ABBWeapon::ProcessInstantHit(FHitResult Impact, FVector Origin, FVector ShootDir, int32 RandSeed, float AimSpread)
{
	if (MyPawn && MyPawn->IsLocallyControlled() && GetNetMode() == NM_Client)
	{
		ServerProcessInstantHit(Impact, Origin, ShootDir, RandSeed, AimSpread);
	}

	if (Role == ROLE_Authority)
	{
		HitNotify.Origin = Origin;
		HitNotify.RandSeed = RandSeed;
		HitNotify.ReticleSpread = AimSpread;
	}

	if (GetNetMode() != NM_DedicatedServer)
	{
		SpawnImpactEffects(Impact);
	}

	// This actually deals the damage of the hit
	if (Impact.Actor != NULL)
	{
		if (GetNetMode() != NM_Client || Impact.Actor->Role == ROLE_Authority || Impact.Actor->bTearOff)
		{
			FPointDamageEvent PointDmg;
			PointDmg.DamageTypeClass = DamageType;
			PointDmg.HitInfo = Impact;
			PointDmg.ShotDirection = ShootDir;
			PointDmg.Damage = Damage;
			Impact.GetActor()->TakeDamage(PointDmg.Damage, PointDmg, MyPawn->Controller, this);
		}
	}
}

Hi. I dont know too much about programming yet so I am only commenting rather than answering. How many pellets does your shotgun fire? If its a bunch that might explain it.

If you are doing a large number of pellets, could you try reducing the number and still trying to get a meaningful average from them? Maybe it will work with relatively few pellets since its random anyways.

It’s at 15 at the moment, a good spread. I’ve tried 8 which is becoming too low. The delay is still present, but reduced. It becomes a non issue when 3-4 pellets are used, which is a little too low in this case

Maybe create a seperate firing function for firing the shotgun, that would change the firing process from
15 RPCs - 15 Pellets to 1 RPC - 15 Pellets.

Hi Constan7ine,

I personally don’t know much about networking code in particular myself but do know about C++ in general so I’ll try to be of some help.

It seems like a lot of the problem, as you have stated in your edit, is that the ServerProcessInstantHit is being run 15 times. I think it would be more efficient if you could use a pointer to a temporary array to store all 15 of the pellets so that you could pass them all into ABBShotgun::FireWeapon().

You can then use a separate function before ServerProcessInstantHit to see which pellets (Or just how many if they all do the same amount of damage) will hit the target. This would allow you to calculate all of the damage at once, so that you only need to run ServerProcessInstantHit once per client (In case the shotgun hits 2 players at once).

And for memory’s sake, after that you can destroy the temporary array (Or simply refill it with new values) when you’re done with it and use the same pointer for the next shot. I hope this helps.

Have a nice day