TpLib Messaging, Events, and Persistence

TpLib has general-purpose messaging and Event functionality. Messages get sent to tiles, and tiles can post events.

Messages can be sent to tiles; for example, to notify a tile of the player’s position. Tiles can send events to subscribers of a .net event; for example, after receiving a message about the player’s position the tile can post an event that the tile’s position intersects that of the player.

  • SendMessage: Sends a message to a tile. Four overloads.
  • OnTileEvent: An event that Monobehaviours or other scripts can subscribe to in order to be notified of events that a Tile initiates via a call to PostTileEvent.
  • PostTileTriggerEvent: Allows a tile to notify subscribers to OnTileEvent that a tile wants it or them to do something.
  • PostTileSaveDataEvent: Allows a tile to notify subscribers (usually only one) to OnTileEvent that a tile wants it to save data from the tile.
  • AnySaveEvents: Property, Returns true if there are any queued SaveData events
  • AnyTriggerEvents: Property, Returns true if there are any queued Trigger Events.
  • GetFilteredEvents: Retrieves queued deferred events.
  • ClearQueuedTileEvents: Clears the queue

Using the built-in messaging and event functions requires implementation of one or two interfaces, depending on what you’re trying to do.

  • ITpMessaging specifies methods required for communication and events.
  • ITpPersistence specifies methods used for saving and restoring data.

Both interfaces are generic, and have type specifications for data sent to a tile and for data read from a tile. This is covered a bit later.

SendMessage

SendMessage is used to send messages to tiles. Using method overloads, the message can be sent to a particular tile on a particular Tilemap, or to all tiles of a particular Type, or to all tiles with a particular tag. Tiles which need to be recepients of SendMessage have to implement ITpMessaging.

As can be seen from the ITpMessaging interface, the message is sent to a method called MessageTarget. Depending on what you’re trying to accomplish, the method GetData can be used to retrieve data that the tile sets up in response to receiving a message.

PostEvent

TpLib.PostTileTriggerEvent and TpLib.PostTileSaveDataEvent are used by tiles to send messages to subscribers of OnTileEvent, who receive an instance of the event type when the event is invoked. TpLib saves the tile instance that sent the event, and the event subscriber can retrieve it, and other cached events, with TpLib.GetFilteredEvents. The cache can be cleared with Tplib.ClearQueuedTileEvents.

These two TpLib methods don’t require implementation of any interface methods. Also, multiple cached events from the same tile instance are not cached since only the instance reference is cached and that would not have changed.

PostTileXXXEvent is meant for MonoBehaviour components as subscribers to OnTileEvent, although this is not enforced. As usual, ensure that OnDisable or OnDestroy unsubscribe from the events.

Save and Restore

A simple save/restore system is built into TpLib. Tiles implementing ITpPersistence will have methods that can be used to get and restore data from and to individual tiles.

One possible way to do that is for a tile to use TpLib.PostTileSaveDataEvent to indicate when it has data to save. For example, this action can be in response to a SendMessage from a scene component.

This is only a framework, since what you save and restore is very specific to your project. The demo programs TopDownDemo and SaveRestore are examples of how to use this feature.

Types for these Interfaces

ITpMessaging and ITpPersistence provide a general framework for messaging and game data persistence. The implementation is up to you or you can ignore this optional feature completely. Both of these interfaces require you to implement the data structures that you want to use for messages and for saving/restoring data.

The important thing to note is that you can set up and use different data structures for both directions of data movement. Notation: We use T for the data type sent to a tile’s MessageTarget method, and TR for the data type returned from a tile’s GetData method. Alternatively, you can use the same data structure for both directions; i.e., T and TR can be the same class.

The data structures must all derive from an abstract class called MessagePacket (in ITpMessaging.cs). MessagePacket is a totally empty abstract class. This actually can be useful if, for example, you want to use ITpMessaging to send a message to a tile but don’t need to ever extract data from that tile when an event subscriber reacts. For that use case, a concrete empty class is provided for the GetData method: EmptyPacket.

If you have different data structures that you wish to use for different purposes, you can have multiple MessageTarget and/or multiple GetData methods in your tile class, one for each type of data structure. This requires multiple interface specifications on the Tile class declaration. For example, the TpAnimZoneBase class is declared like this:

public class TpAnimZoneBase : TpFlexAnimatedTile, ITpMessaging<PositionPacketOut,PositionPacketIn>

with implementations:

public void MessageTarget(PositionPacketIn sentPacket){…}
public PositionPacketOut GetData(){…}

In this case, T and TR are both of type PositionPacketIn.

The declaration below adds two more data types where T = Foo and TR = Bar:

public class TpAnimZoneBase : TpFlexAnimatedTile, ITpMessaging<PositionPacketOut,PositionPacketIn>, ITpMessaging<Bar,Foo>

and one would have to add these implementations:

public void MessageTarget(Foo inputParameter){…}
public Bar GetData(){…}

Each MessageTarget handles whatever actions are needed for the differing inputs, and the different GetData implementations provide any return data required.

If this seems overly-complex, the alternative for a general-purpose framework would be to use object, which introduces a lot of boxing and unboxing. The approach used here enforces static type safety, that is, the compiler will help prevent errors.

In Tilemap-based programs it is common to pass around Vector3Ints to denote a position on a tilemap. For this use case, a pair of identical simple classes is also provided: PositionPacketIn and PositionPacketOut. These are identical classes with just an internal position field, and both are provided to show that two different subclasses of the abstract MessagePacket class can be used with the same interface (ITpMessaging in this case).

For TilePlus tiles using ITpPersistence, strings are often sent to a tile to restore data (e.g., a string of JSON data). For this purpose the StringPacketIn class is available.

There are two demo scenes that show how to use ITpPersistence: TopDownDemo and SaveRestoreDemo. TopDownDemo also shows how to use ITpMessaging.