Spawning actors on client, server spawns two actors for client

Hello,

I’m creating a default weapon spawning for my game, and I made the actor spawning on the server, but for some reason, if the code is executed on the server side, it spawns 1 weapon, but for the client, it spawns two actors. Can’t explain that to myself.

Here’s the setup:


void ABaseHero::EventSpawnDefaultWeapons()
{
	if (HasAuthority())
	{
		SpawnDefaultWeapons(this);
	}
	else
	{
		ServerSpawnDefaultWeapons(this);
	}
}

void ABaseHero::ServerSpawnDefaultWeapons_Implementation(ABaseHero* Hero)
{
	SpawnDefaultWeapons(Hero);
}

void ABaseHero::SpawnDefaultWeapons(ABaseHero* Hero)
{
	// get transform
	FTransform Transform = Hero->GetActorTransform();

	//spawn params
	FActorSpawnParameters Params;
	Params.Instigator = Hero;
	Params.Owner = Hero;

	//Spawn first weapon
	AWeapon* WeaponTemp = GetWorld()->SpawnActor<AWeapon>(DefaultPrimaryWeapon, Transform, Params);
	WeaponTemp->bHasBeenPickedUp = true;

	FAttachmentTransformRules rules = FAttachmentTransformRules(EAttachmentRule::SnapToTarget, false);

	if (WeaponTemp)
	{
		Hero->Inventory->PrimaryWeaponSlot = WeaponTemp;
		Hero->Inventory->PrimaryWeaponSlot->SetOwner(Hero);
		Hero->Inventory->PrimaryWeaponSlot->AttachToComponent(Hero->GetMesh(), rules, TEXT("GunSocket"));
	}

	//Spawn second weapon
	//WeaponTemp = nullptr;
	//
	//WeaponTemp = GetWorld()->SpawnActor<AWeapon>(DefaultSecondaryWeapon, Transform, Params);
	//WeaponTemp->bHasBeenPickedUp = true;
	//
	//if (WeaponTemp)
	//{
	//	Hero->Inventory->SecondaryWeaponSlot = WeaponTemp;
	//	Hero->Inventory->SecondaryWeaponSlot->SetOwner(Hero);
	//	Hero->Inventory->SecondaryWeaponSlot->AttachToComponent(Hero->GetMesh(), rules, TEXT("WeaponHolsterSecondary"));
	//}

	this->HudDisplayMessage = "";
}

Any ideas why?

Replication only works from server to client. Your actor probably is set to replicated (as it should be)…

BUT

You are probably calling ABaseHero:EventSpawnDefaultWeapons on BOTH server and client. This means the server spawns one actor and replicates it and your client also spawns a 2nd actor, but it’s not allowed to replicate it (being a client). This leads to having the “server-shoved” actor along with their own, “local” actor.

Just make sure the ABaseHero:EventSpawnDefaultWeapons is only called by the server.

Why are you passing “this” as a parameter to the server rpc? The way server rpcs work is they call the servers instance of that object. Then the server makes changes to the servers instance and the values get sent down to the client if they are set to replicated.

My guess is it has something to do with that and also try not to even need to call the SpawnDefaultWeapons from the client and just let the server determine when to do that.

So instead of passing my hero reference, I can just use this-> inside the function and it will work?

Well my idea is when the client spawns, I it asks the server to spawn for him default weapons. I first thought of let the gamemode handle that, but had some issues so moved it to client.

Okay guys finally fixed it thanks to @Vlád !

Doing it like:


if(HasAuthority())
{
EventSpawnWeapons();
}

worked fine!!!