Skip to content

Latest commit

 

History

History
294 lines (210 loc) · 10.5 KB

README.md

File metadata and controls

294 lines (210 loc) · 10.5 KB

Logo

ecs-messages

License bage Version Unity Entities Tests

Overview

This messaging system can be used as bridge between MonoBehavior logic and ECS logic.
Also it serves as commucation tool between ECS systems for some cases.

Key features:

  • Simple API that ease to read
  • Handling messages lifetime(creation details, auto deleting according to configured rules, etc)
  • Supports IComponentData as message content
  • Multiple worlds support

Tested with Unity DOTS ECS v1.0.10 and Unity 2022.3.0 LTS

Installation

Add package via Package Manager -> Add package from git URL.
Package path in "manifest.json" should looks like:
https://github.com/CortexDeveloper/ecs-messages.git?path=src/ecs-messages/Assets/Package#x.x.x"

Where "x.x.x" is version of package.
Also pay attention that package code located in "src/ecs-messages/Assets/Package".

Everything is message

Or simply clone repository into your project.

Initialization

Service must be initialized for each world separetely. For this purposes use API below in your entry point.

World defaultWorld = World.DefaultGameObjectInjectionWorld;
//pass world and parent system group for messages internal systems
MessageBroadcaster.InitializeInWorld(defaultWorld, defaultWorld.GetOrCreateSystemManaged<SimulationSystemGroup>());

Internal systems contains ones that remove messages automatically.
So, it's better to place it under parent system group close to the end of your systems execution order.

Let's look on quick example.

If you post OneFrame message and expect it to processed in SystemGroupC - that's fine.
Because ECSMessages internal systems was initialized in SystemGroupD after SystemGroupC.

But if you post OneFrame message and trying to process it in SystemGroupE - that's not ok.
Because message would be deleted inside internal system before it reach SystemGroupD.

Systems execution order

So, that's the reason why ECSMessages systems should be placed after systems that depends on it.

Disposing

Service also have API to dispose from world.

World defaultWorld = World.DefaultGameObjectInjectionWorld;

MessageBroadcaster.DisposeFromWorld(defaultWorld);

Use Cases

UI and ECS

There are a lot of reasons to implement UI logic via Object Oriented Design.
So we need somehow connect our ECS gameplay parts and interface elements.
For example start match by clicking button or do something on swiping up on mobile phone.

UI magic

Gameplay and Non-Gameplay/Meta Game

It also OK for communication between ECS Systems without carying about entities-messages creation and deleting.
As example we can talk about achivements. Player lost match but game designer wants to give him achivement as reward.
So, CharacterDeathSystem just post message that available only for one frame via service API and hopes that AchievementsListenerSystem will catch it and send analytics data.

Semantic of messages

In ECS we can say that commands and events are entities with bunch of special components.
So, from computer point of view they looks almost identicaly but not for developer.
Both are messages but with different semantic.
The difference between them in reasons why they were sent to world.
Event notifies that owner of this event changed its own state.
Command, despite they also just an entity with some components, have intention to change someones state.
In classic OOP paradigm command is a peace of logic that have form of object. But in ECS we can operate only with data.

Everything is message

Event - entity with bunch of components that notifies world about owner changed state.
Command - entity with bunch of components that have intetion to change someones state.

Features

Lifetime Types

Message can be one of three types:

OneFrame - message will live only one frame and then would be deleted.
Removing handled by service.

TimeInterval - message will live amount of time that was configured on message creation.
Messages with limited lifetime bound to real time.
Auto deleting still managed by service.

Unlimited - unmanaged by service type.
Special messages that might be useful for cases when you don't know exactly the lifetime.
In this case you should manually deal with it and delete message after usage.

Multiple Worlds

Messages can be posted via EntityCommandBuffer or EntityManager. Both of them belong to some world.
So, if you want to post message in certain world just use ECB or EM from proper one.

Code Examples

Post API

One Frame Messages

Messages of this type will be alive only for one frame and then would be automatically deleted.
Pay attention that dividing messages to "events" and "commands" performed for semantic purposes.
That helps to quickly catch the intention of this message.

Case: Pause game
var ecb = yourEntityCommandBufferSystem.CreateCommandBuffer();

// It will be automatically deleted after one frame
MessageBroadcaster
    .PrepareMessage()
    .AliveForOneFrame()
    .Post(ecb, new PauseGameCommand());

// Message component must implement an interface IMessageComponent
public struct PauseGameCommand : IComponentData, IMessageComponent { }
Case: Start game by clicking Start button
var ecb = yourEntityCommandBufferSystem.CreateCommandBuffer();

MessageBroadcaster
    .PrepareMessage()
    .AliveForOneFrame()
    .Post(ecb, new StartMatchCommand
    {
        DifficultyLevel = Difficulty.Hard,
        MatchLength = 300f,
        EnemiesCount = 25
    });

public struct StartMatchCommand : IComponentData, IMessageComponent
{
    public Difficulty DifficultyLevel;
    public float MatchLength;
    public int EnemiesCount;
}

Time Interval Messages

Case: Informing that quest available only for 600 seconds(10 minutes)
// It will be automatically deleted after 1 minute
MessageBroadcaster
    .PrepareMessage()
    .AliveForSeconds(60f)
    .Post(ecb, new QuestAvailabilityData { Quest = Quests.SavePrincess });

Unlimited Lifetime Messages

Case: Notify that quest is completed
// It would be posted as usual message but should be deleted manually
// There is no special system for this type that handling deleting automaticaly
MessageBroadcaster
    .PrepareMessage()
    .AliveForUnlimitedTime()
    .Post(ecb, new QuestCompletedEvent { Value = Quests.KillDiablo });

Immediate Post API

For some cases it's necessary to post message not via ECB system but right now via EntityManager.
Here is alternative way how to post message.

Case: Post pause message immediately
// The only difference here is last method to post message
// It needs EntityManager instead of ECB
var entityManager = yourWorld.EntityManager;

Entity messageEntity = MessageBroadcaster
    .PrepareMessage()
    .AliveForOneFrame()
    .PostImmediate(entityManager, new PauseGameCommand());

Pay attention that PostImmediate method returns message entity.
Thats give you an oportunity to do whatever you want with message and control its lifetime manually.

Remove API

Messages removing is supoused to be automated by service.
In case you realy need to manually delete message you can use EntityManager or EntityCommandBuffer API.
As far as message is just an entity with bunch of components, there is no special way of removing them from World.

If you need to delete messages of certain type use broadcaster API below.

// removes all messages with given T component
MessageBroadcaster.RemoveAllMessagesWith<T>(ecb);

Editor Features

Stats Window

Stats window located here ECSMessages/Stats.

Editor Stats

Message Entity

There is an example of components on message entity.
They might be useful for debug purposes. Each message have unique ID and stores creation time.

Message Entity

Message Entity Editor Name

There is an optional feature that allows you to name message.
Pass FixedString64Bytes instance to method PrepareMessage to give a name to message.

MessageBroadcaster
    .PrepareMessage(new FixedString64Bytes("PauseGameCommand"))
    .AliveForOneFrame()
    .Post(ecb, new PauseGameCommand());

Samples

Check package samples to explore more examples.

Contacts

Feel free to ask me any questions.
cortexdeveloper@gmail.com