Replicated Events System

Hi all,

What I’d like to achieve is a system that can handle events and directly call a function from an specific client, through the entire server.

(My project is an FPS, so everything will be related to the genre)

For instance, whenever I have an enemy inside my screen for ‘x’ amount of seconds, an event/function will trigger the events handler (Inside Game Mode, maybe?), and the enemy will receive a message he’s being locked down.

I believe that the best way to achieve this is by getting the enemy’s Player State and, through server RPC call, get the Player Array, compare which one is the enemy’s and call a function inside it’s player state to warn him.

Also, I’m adding two Interface Classes, each one for my GameMode and PlayerState, respectively, to avoid casting. Those Interfaces will carry the messages and functions to be called to the event handler and for the player when receiving the messages.

  • Should I avoid Multicast?
  • Delegates?
  • Will Player State itself deliver the specific player id reference, inside the server?

I’m here to ask for some guidance on which is the best way to achieve my goal, since replication is not a subject I have mastered enough inside UE4++.

I’ll be posting my results here.

Update - Blueprints

Update:

First I made inside blueprints to validate my idea.

I was able to create the system by changing some of my original idea, after contacting eXi in private. (if you see this post, thanks, again!)

So, it was easier than I expected:

  • The player will aim to the target and call an event to Run On Server, if remote. Then, the server will get the Game Mode and send an interface message, passing the target’s Player State by parameter.
  • In my case, each type of message will be added inside this enum and the event handler will take care later.

2fa447f3bf5078ab231e5e60232fc8ef1ace770d.jpeg

The Event Handler is an Actor Component added in my Game Mode class.

  • Inside my game mode, I’ve managed to call a function inside the Event Handler (Through the Interface Event).
  • This function will receive the target’s Player State, get which player controller owns him and call a Client RPC inside the player controller.

26677ef8064402553947468bb8effcb8a3de293c.jpeg

Works like a charm!

Now I will put it in UE4++.

I’ll be posting later.

Update 2 - C++

Update 2: The code.

It was pretty quick to implement, since I just needed to follow what I’ve made in Blueprints.

Events Handler Component:

.h


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SHOOTERGAME_API USF_EventsHandlerComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	....

	virtual void SendMessageTo(EMessageType Message, APlayerState* Player);
	
};

.cpp - in my case, the Client call is a function inside the Player Controller defined as UFUNCTION(client, reliable).


void USF_EventsHandlerComponent::SendMessageTo(EMessageType Message, APlayerState* Player)
{
	if (!Player)
	{
		return;
	}
	AShooterPlayerController* PC = Cast<AShooterPlayerController>(Player->GetOwner());
	if (PC)
	{
		if (Message == EMessageType::MT_WarningMessage)
		{
			PC->ClientCall();
		}
	}
	else
	{
		GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Black, "Invalid PlayerController for Event", false);
	}

}

**Interface **- used to avoid dependencies and casting

.h


UENUM(BlueprintType)
enum class EMessageType: uint8
{
	MT_WarningMessage UMETA(DisplayName = "Warning Message")
};

...

class SHOOTERGAME_API ISF_EventsHandler
{
	GENERATED_IINTERFACE_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	
	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Interface")
	void WarningMessageTo(APlayerState* Player, EMessageType Message);
};

GameMode

.h


UCLASS()
class SHOOTERGAME_API ASF_GameModeTeamDeathmatch : public AShooterGame_TeamDeathMatch, public ISF_EventsHandler
{
	GENERATED_BODY()
        
        ....


	UPROPERTY()
	USF_EventsHandlerComponent* EventsHandler;
	
        UFUNCTION(BlueprintCallable, Category = "Energy Interface")
	virtual void WarningMessageTo_Implementation(APlayerState* Player, EMessageType Message);
	
};

.cpp



ASF_GameModeTeamDeathmatch::ASF_GameModeTeamDeathmatch(const FObjectInitializer& ObjectInitializer)
						   : Super(ObjectInitializer)
{
        ....

	EventsHandler = CreateDefaultSubobject<USF_EventsHandlerComponent>("EventsHandler");
}

void ASF_GameModeTeamDeathmatch::WarningMessageTo_Implementation(APlayerState* Player, EMessageType Message)
{
	EventsHandler->SendMessageTo(Message, Player);
}

Inside the PlayerController class, the ClientCall function will run as a Client RPC.

There’s just one thing left I could not identically reproduce and I had to workaround by defining the ClientCall function to call another method that can be finally overriden in blueprints, cause I could not make a Client RPC function overrideable in Blueprints so far.

For this, I’ve already posted in answerhub and hope someone could clarify this to me.

Well, tested and working inside c++.