X157 Dev Notes

One simulant attempts to share insight with others.

Mass Signals

Mass implements a form of signal handling to simulate Events for Entities.

Important code:

UMassSignalSubsystem

The Mass Signal Subsystem is a “Named Signal” Manager.

Signals do not contain any Event or other context data.

How to Send a Signal

SignalSubsystem.SignalEntity(SignalName, Entity);

There are other ways including SignalEntities (multiple entities), DelaySignalEntity, DelaySignalEntities, and others.

Read MassSignalSubsystem.h for more.

How to Register for Signals

FName SignalName ("MySignalName");
SignalSubsystem.GetSignalDelegateByName(SignalName).AddUObject(this, &ThisClass::OnSignalReceived);

How to Unregister for Signals

FName SignalName ("MySignalName");
SignalSubsystem.GetSignalDelegateByName(SignalName).RemoveAll(this);

How to Process Signal Events

To process signals in a processor, derive your class from UMassSignalProcessorBase. Do not override its signal handling, just implement the SignalEntities method.

If you need to receive signals in Gameplay or other code, do it like:

void UMyClass::OnSignalReceived(FName SignalName, TConstArrayView<FMassEntityHandle> Entities)
{
    // For each Entity in Entities, process the signal SignalName.
    // Do whatever you need to do for this signal.
}

UMassSignalProcessorBase

A Mass Processor abstract base class that:

Interesting example implementations in UE 5.7:

Mass Crowd also has some ZoneGraph Signal processors.

Subscribing to signals

In your derived processor, you will need to subscribe to whatever signals you want your processor to receive.

UMassStateTreeProcessor overrides UMassProcessor::InitializeInternal to achieve this, for your own custom UMySignalProcessor it would look for example like:

void UMySignalProcessor::InitializeInternal(UObject& Owner, const TSharedRef<FMassEntityManager>& EntityManager)
{
	Super::InitializeInternal(Owner, EntityManager);

	UMassSignalSubsystem* SignalSubsystem = UWorld::GetSubsystem<UMassSignalSubsystem>(Owner.GetWorld());

	SubscribeToSignal(*SignalSubsystem, FName("MySignalName1"));
	SubscribeToSignal(*SignalSubsystem, FName("MySignalName2"));
	SubscribeToSignal(*SignalSubsystem, FName("MySignalNameN"));

	// ... [snip] ...
}

Pure virtual SignalEntities

You must implement this method to do whatever you want to do when Signals are received.

/**
 * Actual method that derived class needs to implement to act on a signal that is raised for that frame
 * @param EntitySubsystem is the system to execute the lambdas on each entity chunk
 * @param Context is the execution context to be passed when executing the lambdas
 * @param EntitySignals Look up to retrieve for each entities their raised signal via GetSignalsForEntity
 */
 virtual void SignalEntities(FMassEntityManager& EntityManager, FMassExecutionContext& Context, FMassSignalNameLookup& EntitySignals)
    PURE_VIRTUAL(UMassSignalProcessorBase::SignalEntities, );

FMassSignalNameLookup

Used internally by UMassSignalProcessorBase

An efficient mapping of up to 64 signals per Entity.

The 64 signal limit can be worked around by using multiple instances of FMassSignalNameLookup together.

See MassSignalProcessorBase.cpp:85 for how UMassSignalProcessorBase circumvents the 64 signal limit.