Message System

Hey Guys,

I want to use the message system to send events from one class to many different classes.
I thought this is possible with the MessageBus. From my understanding I register all my objects that should receive a certain message as listeners and another object then publishes the message.
But somehow I am too stupid to work out how to implement it. I think with a small piece of example code, like one listener class and one who publishes something I should be fine to figure the rest out.

Cheers

Search for FMessageEndpoint::Builder in the code base. You will find many examples. If you still run into problems, let us know what exactly the errors are, so we can figure out what you’re missing. Thanks!

For a relatively simple use case check out EngineService.cpp and EngineServiceMessages.h

Cool, thanks so far for the answer. But still not really working out.
I looked up the code in the code base in FAutomationControllerManager. In this class I found the following code lines:

MessageEndpoint = FMessageEndpoint::Builder("FAutomationControllerModule")
	.Handling<FAutomationWorkerFindWorkersResponse>(this, &FAutomationControllerManager::HandleFindWorkersResponseMessage)
	.Handling<FAutomationWorkerPong>(this, &FAutomationControllerManager::HandlePongMessage)
	.Handling<FAutomationWorkerRequestNextNetworkCommand>(this, &FAutomationControllerManager::HandleRequestNextNetworkCommandMessage)
	.Handling<FAutomationWorkerRequestTestsReply>(this, &FAutomationControllerManager::HandleRequestTestsReplyMessage)
	.Handling<FAutomationWorkerRunTestsReply>(this, &FAutomationControllerManager::HandleRunTestsReplyMessage)
	.Handling<FAutomationWorkerScreenImage>(this, &FAutomationControllerManager::HandleReceivedScreenShot)
	.Handling<FAutomationWorkerWorkerOffline>(this, &FAutomationControllerManager::HandleWorkerOfflineMessage);

From my understanding so far the class handles these 7 Messages which can be published be any other class with the same MessageEndpoint. Am I correct so far?
So now I try to create my own MessageEndpoint:

MessageEndpoint = FMessageEndpoint::Builder("AWolfCharacter")
	.Handling<FWolfCharacterHide>(this, &AWolfCharacter::HandleWolfCharacterHide);

But I always get the following error message

1>…\WolfCharacter.cpp(52): error C2440: ‘’ : cannot convert from ‘const char [15]’ to ‘FMessageEndpoint::Builder’
1> Source or target has incomplete type

Is there any tutorial about this? Because its very very hard to figure this all out through code only.

Cheers

That’s an odd error. Did you include the following in your module?

#include "MessageEndpoint.h"
#include "MessageEndpointBuilder.h"

Also, a couple more notes for your information:

  • The Messaging system supports two paradigms: request-response and publish-subscribe. Typically, you use publish-subscribe to locate services initially, and after that you send messages directly between endpoints via request-response. In order for messages to be handled by an endpoint, a handler function must be registered for either paradigm.
  • The Handling<> methods only register the handlers, which means that if a message should be received by this endpoint then the registered function will handle it. If no handler is registered, the message will not be handled. A message will be received by an endpoint if either (a) it was sent directly to the endpoint (i.e. request-response), or (b) it was published and the endpoint had a subscription to the message type (i.e. publish-subscribe). However, subscription does not happen automatically as part of registering a handler, but has to be done explicitly via MessageEndpoint->Subscribe<FWolfCharacterHide>(). This means that for publish-subscribe you have to do both, register a handler and subscribe to the message type. Subscription is not needed for messages that are sent directly to one or more endpoints using their endpoint addresses.
  • Because the UObject sub-system is not quite thread-safe yet, a small hack is currently needed for all UStructs that serve as messages. You have to declare the type trait TStructOpsTypeTraits with WithMessageHandling=true. Take a look at EngineServiceMessages.h for examples. We are planning to fix this soon so that this hack will not be needed in the future, and any UStruct type can be used as messages.

Hey,

thx for the answer and the good explanations. I am a little bit closer now, but got the next error :wink:

…WolfCharacter.cpp(52): error C2664: ‘FMessageEndpointBuilder &FMessageEndpointBuilder::Handling(HandlerType ,void (__cdecl AWolfCharacter:: )(const MessageType &,const TSharedRef &))’ : cannot convert argument 2 from 'void (__cdecl AWolfCharacter:: )(void)’ to ‘void (__cdecl AWolfCharacter::* )(const MessageType &,const TSharedRef &)’
1> with
1> [
1> HandlerType=AWolfCharacter
1> , MessageType=FWolfCharacterHide
1> ]
1> and
1> [
1> MessageType=FWolfCharacterHide
1> ]
1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast*

My code to set up the character as a receiver of a message looks like that:
MessageEndpoint = FMessageEndpoint::Builder(“AWolfCharacter”).Handling(this, &AWolfCharacter::HandleWolfCharacterHide);

How can I setup my character as a receiver? I looked up several examples in code like ScreenShotManager, but its still quite hard to figure out.

Cheers

I don’t know if the template parameter got stripped in your comment, but make sure you have:

.Handling<FWolfCharacterHide>(this, &AWolfCharacter::HandleWolfCharacterHide)

Also, make sure that the signature of your handler is correct. It should be something like:

AWolfCharacter::HandleWolfCharacterHide(const FWolfCharacterHide& Message, const IMessageContextRef& Context)

Hey,

thnaks, After including the headers and the correct function definition I am a little bit closer. But now struggeling with the next problem. When I publish a message it is not received.
I have another class from which I want to send the message. I created a messageEndpoint there as well and use the publish method.

MessageEndpoint = FMessageEndpoint::Builder("ASwitchingMechanic");

MessageEndpoint->Publish<FWolfCharacterHide>(NewMessage);

The corresponding method HandelWolfCharacterHide is never triggered.
Any clues what I am doing wrong?

Cheers

Found it. Just forgot to subsribe to MessageEndpoint.
In most of the example MessageEndpoints do not subsrcibe and are adressed directly. Is there any performance reason for this?

Cheers

It’s just part of the particular protocols being used. In general, we use publish-subscribe only for service discovery, and once a service endpoint address is known, we use request-response to talk to the service directly.

Publish-subscribe can be slightly more expensive if many endpoints are subscribed to the same message type. It can also add a little bit of extra processing to any computer on the network, because their message router needs to process published messages to check whether anyone is subscribed. We currently use UDP multicast for published message, UDP unicast for sent messages. If a message is sent to more than one recipient, UDP multicast will be used.

Just a reminder, if you want to send messages between processes or computers, make sure that the UdpMessaging transport plug-in is enabled. It does the actual work of translating messages between the in-process message bus and the network.