Why does calling GEngine->AddOnScreenDebugMessage() in a client marked UFUNCTION get called on all devices?

This is what I seem to be getting when using the play button, with more then 1 client, also with dedicated server. It also looks like when the function is called on the dedicated server its shown on clients too.

I’m assuming this is because the client tells the server that its called this function and the server sends that to all other clients? Or am I just doing something wrong?

I think I am because it looks like the server is also running these functions, even if I marked them as client…

I have tried searching to answer your reason for why this occurs and I’m not able to find a good reason “why”, but I have found a work-around that requires a bit of work with a custom HUD class.


#pragma once

#include "GameFramework/HUD.h"
#include "WAWHUD.generated.h"

struct FInfoItem
	bool Expired;
	float ExpireTime;
	TSharedPtr<class FCanvasTextItem> TextItem;

	FInfoItem() : Expired(false), ExpireTime(0), TextItem(NULL) {}


	/* Main HUD update loop */
	virtual void DrawHUD() override;

	/* Add text for printing debug / client only messages */
	void AddText(const FString& Text, const FColor& Color, float Duration);

	/** Array of information strings to render (Waiting to respawn etc) */
	TArray<FInfoItem> InfoItems;

	float ShowInfoItems(float YOffset, float ScaleUI, float TextScale);


#include "WAWGame.h"

AWAWHUD::AWAWHUD(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)


void AWAWHUD::AddText(const FString& Text, const FColor& Color, float Duration)
	FInfoItem InfoItem;
	InfoItem.ExpireTime = GetWorld()->RealTimeSeconds + Duration;
	TSharedPtr<FCanvasTextItem> TextItem(new FCanvasTextItem(FVector2D(0, 0), FText::FromString(Text), GEngine->GetSmallFont(), Color));
	TextItem->BlendMode = SE_BLEND_Translucent;
	FFontRenderInfo fri = FFontRenderInfo();
	fri.bClipText = true;
	TextItem->FontRenderInfo = fri;
	InfoItem.TextItem = TextItem;

float AWAWHUD::ShowInfoItems(float YOffset, float ScaleUI, float TextScale)
	float Y = YOffset;
	float CanvasCentre = Canvas->ClipX / 2.0f; //Centered on the screen, set to zero or some other value if you it left-aligned

	bool ContainsExpiredMessage = false;
	for (int32 iItem = 0; iItem < InfoItems.Num(); ++iItem)
		float X = 0.0f;
		float SizeX, SizeY;
		FInfoItem& InfoItem = InfoItems[iItem];
		if (InfoItem.ExpireTime < GetWorld()->RealTimeSeconds)
			ContainsExpiredMessage = true;
			InfoItem.Expired = true;
			if (InfoItem.TextItem.IsValid())
				Canvas->StrLen(InfoItem.TextItem->Font, InfoItem.TextItem->Text.ToString(), SizeX, SizeY);
				//X = CanvasCentre - (SizeX * InfoItem.TextItem->Scale.X) / 2.0f;
				//Right align
				X = Canvas->ClipX - (SizeX * InfoItem.TextItem->Scale.X);
				Canvas->DrawItem((*(InfoItem.TextItem.Get())), X, Y);
				Y += SizeY * InfoItem.TextItem->Scale.Y;

	//If there were any expired messages then we need to safely remove them
	if (ContainsExpiredMessage)
		float RealTimeSeconds = GetWorld()->RealTimeSeconds;
		InfoItems.RemoveAll([&](FInfoItem InfoItem){
			return InfoItem.ExpireTime < RealTimeSeconds;

	return Y;

void AWAWHUD::DrawHUD()
	float ScaleUI = Canvas->ClipY / 1080.0f;
	float TextScale = 1.f;
	ShowInfoItems(0.f, ScaleUI, TextScale);

Then to add some text you just call the AddText function of the HUD.

float timeElapsed = GetWorld()->GetTimeSeconds();
FString AuthString = (Role == ROLE_Authority ? TEXT(" Server") : TEXT(" Client"));
FString Msg = FString::Printf(TEXT("%.02f (Client:%d): "), timeElapsed, PlayerState->PlayerId) + S + AuthString;
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::White, Msg);
	WAWHUD->AddText(Msg, FColor::Magenta, 5.f);

I hope that helps!