Dedicated Server update clients

This is your fourth or fifth post about this man, stick to one thread.

Ok I’m also digging into multiplayer so I’ll take a shot at your question. The event IncreaseIndex checks for the ROLE_Authority (there is also a function called HasAuthority() on AActor that returns true if you are on the server) and calls a ServerIncreaseIndex method that calls IncreaseIndex again, please don’t do this, you are falling into an endless loop here.

Now the UE4 Networking documentation states that NetMulticast RPCs called from the client will only execute on that invoking client, so this will not update on all clients as you’d like this to happen, you should call the NetMultiCast event if HasAuthority() is true (If you are on the server). I noted that you are replicating the index, keep in mind that you must use this option if that property is something that will change quite a lot during gameplay, if you are using NetMultiCast there is no need to replicate the property since the multicast will make every connected client run that function as well.

So you have two options, using NetMultiCast with no replicated index and call that from the server or use the replicated index, make a RPC running on server that’s reliable which modifies that property and that gets replicated to all clients automatically. In my opinion you rely on that property to be changed so I’d choose the latter.

A listen server only means that a client is working as a server, HasAuthority() should still work if you are using a dedicated server, but well if not then why don’t you use the replicated property and run a RPC to update it from server? that will be replicated to all clients.

I read on docs , but they dont really tell in what environment they used it . In some example of code , people call RPC function without check Authority, in my case HasAuthority never print or call the function. Im really confuse

Hello hello ,

Wanted to know if some one could help me with the NetMulticast ?
I dont understand how used it.

I explain , I try in my project to change a variable in the client class and set it to others clients.
If the client 1 change her variable value he replicate on the server and the server set the new value to the client 2.
example:
Player change Index → Server rpc to change Index → Server sends netmulticast rpc to all Clients to switch new Index.

I do some research , and I read the Netmulticast was a good idea if I want to update all clients by the server, but you know or have better idea im listening.

Thanks for you patience.

Player class :

#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"

UCLASS()
class BASEPROJECT_API APlayerCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	APlayerCharacter();
	virtual void Tick(float DeltaTime) override;
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	UFUNCTION()
		void IncreaseIndex();

	UFUNCTION(Reliable, Server, WithValidation)
		void ServerIncreaseIndex();
	virtual void ServerIncreaseIndex_Implementation();
	virtual bool ServerIncreaseIndex_Validate();

	UFUNCTION()
		void PlayMedia();
	UFUNCTION(NetMulticast, Reliable)
		void NetIncreaseIndex();
	virtual void NetIncreaseIndex_Implementation();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	void MoveForward(float Value);
	void MoveRight(float Value);
	void LookUpRate(float Value);
	void TurnRate(float Value);
	void ResetOrientationAndPosition();

public:

	UPROPERTY(EditAnywhere)
		UCameraComponent* FPC;

	UPROPERTY(EditAnywhere, Replicated)
		int		RepIndex;

private:

	UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
	USkeletalMeshComponent*	Mesh1P;

	float	baseTurnRate;
	float	baseLookUpRate;
};

APlayerCharacter::APlayerCharacter()
{
	PrimaryActorTick.bCanEverTick = true;
	bReplicateMovement = true;
	bReplicates = true;

	GetCapsuleComponent()->SetCapsuleHalfHeight(95.0f);
	GetCapsuleComponent()->SetCapsuleRadius(55.0f);
	GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);

	FPC = CreateDefaultSubobject<UCameraComponent>(TEXT("FPC"));
	FPC->SetupAttachment(GetCapsuleComponent());
	FPC->SetRelativeLocation(FVector(-39.f, 1.5f, 64));
	FPC->SetRelativeRotation(FQuat(0, 0, 0, 0));
	FPC->ProjectionMode = ECameraProjectionMode::Perspective;
	FPC->FieldOfView = 90;
	FPC->bLockToHmd = true;
	FPC->bUsePawnControlRotation = true;

	Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("PawnMesh1P"));
	Mesh1P->SetRelativeLocationAndRotation(FVector(0, 0, -148), FRotator(0.f, -90.f, 0.f));
	Mesh1P->SetupAttachment(GetCapsuleComponent());
	Mesh1P->bOnlyOwnerSee = true;
	Mesh1P->bOwnerNoSee = false;
	Mesh1P->bCastDynamicShadow = false;
	Mesh1P->bReceivesDecals = false;
	Mesh1P->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered;
	Mesh1P->PrimaryComponentTick.TickGroup = TG_PrePhysics;
	Mesh1P->SetCollisionObjectType(ECC_Pawn);
	Mesh1P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
	Mesh1P->SetCollisionResponseToAllChannels(ECR_Ignore);
	Mesh1P->SetupAttachment(FPC);
}

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

	baseTurnRate = 45.f;
	baseLookUpRate = 45.f;

	if (UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled())
		bUseControllerRotationYaw = false;
}

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

	GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::White, FString::FromInt(Role) + FString(" : ") + GetName() + FString::Printf(TEXT("/ RepIndex : %d"), RepIndex));

}

// Called to bind functionality to input
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
	InputComponent->BindAction("ResetVR", IE_Pressed, this, &APlayerCharacter::ResetOrientationAndPosition);
	InputComponent->BindAction("NextMedia", IE_Pressed, this, &APlayerCharacter::IncreaseIndex);

	InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
	InputComponent->BindAxis("TurnRate", this, &APlayerCharacter::TurnRate);
	InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
	InputComponent->BindAxis("LookUpRate", this, &APlayerCharacter::LookUpRate);
	InputComponent->BindAxis("MoveForward", this, &APlayerCharacter::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &APlayerCharacter::MoveRight);
}

void APlayerCharacter::TurnRate(float Value)
{
	AddControllerYawInput(Value * baseTurnRate * GetWorld()->GetDeltaSeconds());
}

void APlayerCharacter::LookUpRate(float Value)
{
	AddControllerPitchInput(Value * baseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void APlayerCharacter::MoveRight(float Value)
{
	if (UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled())
		AddMovementInput(FPC->GetRightVector(), Value, false);
	else
		AddMovementInput(GetActorRightVector(), Value, false);
}

void APlayerCharacter::MoveForward(float Value)
{
	if (UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled())
		AddMovementInput(FPC->GetForwardVector(), Value, false);
	else
		AddMovementInput(GetActorForwardVector(), Value, false);
}

void APlayerCharacter::ResetOrientationAndPosition()
{
	UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition(0, EOrientPositionSelector::OrientationAndPosition);
}

void APlayerCharacter::IncreaseIndex()
{
	RepIndex++;
	if (Role < ROLE_Authority)
		ServerIncreaseIndex();
	else
		NetIncreaseIndex();
}

void APlayerCharacter::ServerIncreaseIndex_Implementation()
{
	IncreaseIndex();
}

bool APlayerCharacter::ServerIncreaseIndex_Validate()
{
	return true;
}

void APlayerCharacter::NetIncreaseIndex_Implementation()
{
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Orange, FString::Printf(TEXT("NetMulticast RepIndex : %d"), RepIndex));
	UE_LOG(LogTemp, Warning, TEXT("NetMulticast RepIndex : %d"), RepIndex);
}

void APlayerCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(APlayerCharacter, RepIndex);
}

I cant multicast if HasAuthority() with Dedicated Server , I print , all the time Role < Authority, I think that check is used when you use Listen Server or others. This is the example I read Here.
So if I cant used the Authority check , I really dont know what can I do.