Warning
Warning: Unity Simulation is deprecated as of December 2023, and is no longer available.
Publisher/Subscriber convenience classes
While you can always implement your own classes which leverage our IPublisher and ISubscriber interfaces as described in Communicating with external processes, we've included a few boilerplate classes that should help accelerate the development of simple publisher/subscriber behaviors.
Using the Communication boilerplate classes
using UnityEngine;
namespace Unity.Simulation.Foundation
{
public abstract class PublisherBehaviour<T> : MonoBehaviour where T : IMessage
{
protected IPublisher Publisher { get; set; }
public bool CanPublish => Connector != null && Publisher != null;
[field: SerializeField]
public virtual string Topic { get; set; }
protected virtual void Start()
{
var connector = ConnectorInjector.FindConnector(this);
if (connector == null)
{
Debug.LogWarning(
$"{name}'s {GetType().Name} couldn't find a valid connector, can't publish to {Topic}");
Publisher = null;
return;
}
Publisher = connector.RegisterPublisher<T>(Topic);
}
public virtual void Publish(T msg)
{
Publisher.Publish(msg);
}
}
public class BoolPublisherExample : PublisherBehaviour<BoolMsg> {}
public abstract class AutoPublisher<T> : PublisherBehaviour<T> where T : IMessage
{
float m_TimeUntilNextPublish = 0f;
[field: SerializeField]
public float PublishFrequency { get; set; } = 0.01f;
[field: SerializeField]
public bool PublishInFixedUpdate { get; set; } = false;
float PublishPeriod => 1.0f / PublishFrequency;
protected abstract T CreateMessage();
protected virtual void Update()
{
if (PublishInFixedUpdate)
{
return;
}
CheckTimeAndMaybePublish();
}
protected void FixedUpdate()
{
if (!PublishInFixedUpdate)
{
return;
}
CheckTimeAndMaybePublish();
}
void CheckTimeAndMaybePublish()
{
m_TimeUntilNextPublish -= Time.deltaTime;
if (m_TimeUntilNextPublish <= 0f)
{
var message = CreateMessage();
Publish(message);
m_TimeUntilNextPublish += PublishPeriod;
}
}
}
public abstract class SubscriberBehaviour<T> : MonoBehaviour where T : IMessage
{
protected IConnector Connector { get; set; }
protected abstract System.Action<T> Callback { get; }
[field: SerializeField]
public virtual string Topic { get; set; }
protected virtual void Start()
{
Connector = ConnectorInjector.FindConnector(this);
if (Connector == null)
{
Debug.LogWarning(
$"{name}'s {GetType().Name} couldn't find a valid connector, can't subscribe to {Topic}");
return;
}
// We wrap the callback here with our own in order to error-check and log before invocation
Connector.Subscribe<T>(Topic, msg => ReceiveMessage(msg, Callback));
}
void ReceiveMessage(T msg, System.Action<T> callback)
{
if (callback == null)
{
Debug.LogError($"{name} cannot invoke callback for {msg.MessageTypeId.MessageTypeName} because " +
$"the callback has been destroyed.");
return;
}
TimeDebug.StepInEditorLog($"Received: {msg}");
callback.Invoke(msg);
}
}
}
PublisherBehaviour
A PublisherBehaviour contains a minimal implementation of the logic needed to Publish a message. Note that it does NOT include logic for determining how to populate a message or when to publish it.
Specifying Type
Unity does not allow generically defined MonoBehaviours in Scenes. So, although the entirety of this class's logic is implemented here in its virtual members, for each Message type you wish to publish you must create a new child class for the specific type.
Example Publisher implementation
This is all that's required to create a Publisher for a given type. However, note that no logic is implemented in Update. While this class CAN publish bool messages, you would need to either override Update or create another Component to hold the logic for when and what it should publish.
AutoPublisher
If you want your Publisher to automatically publish on a fixed frequency, you can inherit from AutoPublisher instead.
Providing the message
When using AutoPublisher, you only need to provide the message to be published. This is done by overriding this CreateMessage method with your implementation which populates the fields of the expected message type and returns it.
SubscriberBehaviours
Like the PublisherBehaviour, SubscriberBehaviours are the minimum necessary implementation for listening to a Topic and subsequently handling its Message.
Define the Callback
SubscriberBehaviours are a little more complicated. You must, at a minimum, provide a Callback to be invoked when the Subscriber receives a Message on its Topic.
Updated 2022-08-31T23:11:26.000Z