Download

Can't get actor to spawn properly (owner issue?)

Hi there, I am trying to spawn in a basic replicated projectile in my game, and for some reason it’s not working. I looked over the shooter game example and tons of threads online, but it’s just not making sense.

Basically when I fire my weapon, it only works on the server. If I fire it on a client, it doesn’t hit the server call whatsoever. I believe it is an owner issue, but I do not know how to fix it.

Weapon.h


// Fill out your copyright notice in the Description page of Project Settings.

#pragma once
#include "Projectile.h"
#include "Animation/SkeletalMeshActor.h"
#include "Weapon.generated.h"

UCLASS()
class DROPZONE_API AWeapon : public ASkeletalMeshActor
{
	GENERATED_BODY()

public:

	AWeapon();

	void SetOwnerTo(APawn* Owner);

	void Fire();

	UPROPERTY(EditDefaultsOnly, Category = Weapon)
		/** The class of projectile that this weapon spawns */
		TSubclassOf<class AProjectile> ProjectileClass;

	/** Called when the user tries to attack. */
	UFUNCTION(reliable, server, WithValidation)
	void ServerFire();


	
};


Weapon.cpp



// Fill out your copyright notice in the Description page of Project Settings.

#include "DropZone.h"
#include "Weapon.h"


AWeapon::AWeapon() {
	bReplicates = true;
	bAlwaysRelevant = true;
}

void AWeapon::Fire() {	
	ServerFire();
}

void AWeapon::SetOwnerTo(APawn* Owner) {
	SetOwner(Owner);
	Instigator = Owner;
}

void AWeapon::ServerFire_Implementation() {
	FTransform SpawnTransform = GetSkeletalMeshComponent()->GetSocketTransform("Muzzle");
	//Make sure that this is only called on the server
	if (Role == ROLE_Authority) {
		//Spawn a projectile
		if (ProjectileClass) {
			UWorld *World = GetWorld();

			const FVector SpawnLocation = SpawnTransform.GetLocation();
			const FRotator SpawnRotation = FRotator(0, 0, 0);
			UE_LOG(LogTemp, Log, TEXT("server weapon fire transform: %s"), *SpawnLocation.ToString());

			if (World) {
				AProjectile *Projectile = World->SpawnActor<AProjectile>(ProjectileClass, SpawnLocation, SpawnRotation);
			}

		}
	}
}

bool AWeapon::ServerFire_Validate() {
	return true;
}


Character BeginPlay



void ADropZoneCharacter::BeginPlay()
{
	Super::BeginPlay();
	
	//Grab the world and make sure it exists
	UWorld* World = GetWorld();
	
	if (World) {
		//Spawn a new weapon for this player based on the selected blueprint class, then check to see if it was spawned correctly
		CurrentWeapon = World->SpawnActor<AWeapon>(WeaponClass, FVector(0, 0, 0), FRotator(0, 0, 0));
		UE_LOG(LogTemp, Log, TEXT("set owner"));
		

		if (CurrentWeapon) {
			//Weapon->GetSkeletalMeshComponent()->AttachTo(GetMesh(), "hand_r", EAttachLocation::SnapToTarget);
			
			CurrentWeapon->AttachRootComponentTo(GetMesh(), "hand_r", EAttachLocation::SnapToTarget);
			CurrentWeapon->SetOwnerTo(this);
		}
	}
}


Projectile.h



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Actor.h"
#include "Projectile.generated.h"

UCLASS()
class DROPZONE_API AProjectile : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AProjectile();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;
	
};


Projectile.cpp



// Fill out your copyright notice in the Description page of Project Settings.

#include "DropZone.h"
#include "Projectile.h"


// Sets default values
AProjectile::AProjectile()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	bNetLoadOnClient = true;
	PrimaryActorTick.bCanEverTick = true;
	bReplicates = true;
	bAlwaysRelevant = true;
}

// Called when the game starts or when spawned
void AProjectile::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void AProjectile::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );
}




My projectile is just a basic actor with a static mesh component. I’m calling the weapons fire method from my characters fire action method.

Any help here would be much appreciated, I’m at my wits end here :frowning:

EDIT:

Don’t want to bump the thread but I did end up getting this working. There was something borked with the project, I re-made the project and everything worked as expected.

Recreated the entire thing in BP, and it’s the exact same problem. Not understanding what I’m doing wrong.

Hi, what do you mean “only works on server”?
if i remember correctly ShooterGame uses Server_ functions for clients to make something on server, and Client_ functions to do something on client when server does stuff, all other UFUNCTION’s called anywhere. so you basically asking server to make your projectile, which is gets created on server, and should pop up on clients too(if not, make sure projectile is replicated, check spawn collisions too), then to do own(only) client specific stuff you call Client_ functions to update states, subtract ammo, etc…

what you get with debug? check for transform if it correct and not at origin. if you are also using projectile movement component you probably don’t want to zero orientation.

you don’t need to pass spawntransform since all this data is already on server and this could potentially open ways for cheating.

also it would be easier to help if you show your class declaration.

Yeah I realize transform should be calculated server side - I knew someone would say something lol. This is just me messing around and trying different things in hope that something will make it work heh.

If I run two clients in PIE, one acting as the server and one acting as the client, the one acting as the server is the only one to produce the projectile. The client, when it calls “Fire” on the weapon, never calls “ServerFire” properly. If I look in the debugger, it actually calls it on the client for some weird reason. It seems like that, even knowing it’s a server RPC, it’s not treated as one.

I’m not overly concerned about orientation etc for now, I just want it replicated properly.

The projectile is replicated, and I even set it to always relevant just for testing purposes, but still nothing. I will post the source in a second here once it pulls down from git.

Not sure if this is the cause of the problem - ServerFire_Implementation should never fire on a client as far as I’m aware - but you need to add an authority check in your character’s BeginPlay. Since you’ve set the weapon to replicate, you should only be spawning it and setting its owner on the server.

I added an authority check on BeginPlay to make sure it’s the server that’s spawning the weapon and setting the owner, but I get the exact same behavior.

The way i have it in in Blueprint is on the Character’s Begin Play, SpawnActor WeaponBP, instigator is Self. Return Actor -> Set Current Weapon variable.

In the WeaponBP, on it’s Begin Play I set owner to instigator, AttachActorToComponent.

The Character’s InputAction Fire calls ServerFire() on Current Weapon, this is a Run on Server event.

ServerFire() -> Has Authority -> firing logic blah blah -> ServerSpawnProjectile() Run on Server

ServerSpawnProjectile() -> Has Authority -> SpawnActor ProjectileBP -> Return Actor -> Set Replicates

I was having the same issue you are and it was because I wasn’t setting the owner on the weapon’s begin play.

I setup a BeginPlay in the weapon, told it to attach to the pawn, and set the owner. 100% exact same behavior :frowning:

I just setup a quick chat message system to see if I couldn’t get replication working, and it turns out, I can’t.

I’ve done replication before, so I’m fairly certain my method for doing this is right, I think at this point I may be missing a header or something, I really don’t know!

When I setup the chat message system, I get these errors:

LogNet:Warning: UIpNetDriver::ProcesRemoteFunction: No owning connection for actor TDSGameStateBP_C_5. Function ServerChatMessage will not be processed.

Which to me seems odd, because it’s a game state, I shouldn’t have to set the owner of that should I?

EDIT:

Don’t want to bump the thread but I did end up getting this working. There was something borked with the project, I re-made the project and everything worked as expected.