Coder Social home page Coder Social logo

beatthat / notifications Goto Github PK

View Code? Open in Web Editor NEW
1.0 3.0 0.0 90 KB

Global system for pub/sub notification events by string 'type'.

License: MIT License

JavaScript 13.59% C# 86.41%
unity3d notifications pubsub observer observer-pattern messaging message-api loosely-coupled-design

notifications's Introduction

notifications

Notifications are a flexible, global pub/sub message system.

Install

From your unity project folder:

npm init --force && \
npm install beatthat/notifications

The package and all its dependencies will be installed under Assets/Plugins/packages.

In case it helps, a quick video of the above: https://youtu.be/Uss_yOiLNw8

USAGE

If you're using this notifications package, you probably encountered it through other beatthat unity3d packages that leverage notifications and also simplify their use. Will give some examples of those packages further down, but for now if you were using Notifications without any other support it would look like this:

using BeatThat.Notifications;

public static class StatusNotifications
{
    /// Notifications are identified by string types
    /// Usually, you want to define those types as constants somewhere
    public const string STATUS_UPDATED = "STATUS_UPDATED";
}

public class StatusObserver : MonoBehavior
{
    void Start()
    {
        NotificationBus.Add<string>(StatusNotifications.STATUS_UPDATED, this.OnStatusUpdated);
    }

    void OnStatusUpdated(string newStatus)
    {
        Debug.Log("got new status: " + newStatus);
    }
}

public class StatusPublisher : MonoBehavior
{
    public string status;

    public void SetStatus(string newStatus) 
    {
        this.status = d;
        NotificationsBus.Send(StatusNotifications.STATUS_UPDATED, newStatus)
    }
}

The example above is very contrived but the main idea is that StatusObserver can get status updates without needing to know anything about StatusPublisher. Instead they both depend on shared notification type.

A Practical Example: State Stores

The example above is really a simplication of State Stores, which are a common use case for notificitions. The basic is to have a global singleton that manages some state item and then observers of that state that can both access the state value and subscribe to on-update notifications.

A more usable version of the status-update example can be built using the state-stores package (in concert with a few other packages I will detail below)

/// pretend we have a slightly more complex 
/// StatusData struct for our state
public struct StatusData
{
    public string status;
    public bolean isHappy;
}

using BeatThat.Service;
using BeatThat.StateStores;
// register this singleton as implementation 
// of interface HasState<StatusData> (see beatthat/services below)
[RegisterService(HasState<StatusData>)]
public class StatusStore : StateStore<StatusData> 
{
    // Will expose the StatusData state as property `stateData`
    // Not shown how here, but just assume that state can be updated
}


using BeatThat.Controllers;
using BeatThat.DependencyInjection;
using BeatThat.StateStores;
public class StatusObserver : Controller 
/// extending Controller here mainly gives support for dependency-injection 
/// and simplified notificaton binding
{
    override protected void GoController() // called after dependencies injected
    {
        /// Bind is a wrapper for NotificationBus.Add 
        /// that handles cleanup, i.e. it makes sure 
        /// the registered callback is removed when this controller goes away
        Bind(State<StatusData>.UPDATED, this.OnStatusUpdated);
    }

    void OnStatusUpdated()
    {
        StatusData s = this.statusStore.stateData; // t
        Debug.Log("got new status: " + s.status + " with isHappy " + s.isHappy);
    }

    // dependency injection will set this property to our singleton service
    // based upon matching the registered interface HasState<StatusData>
    [Inject] HasState<StatusData> statusStore { get; set; }
}

For more details on the packages used above see:

The service package manages a container of global singleton services

The [RegisterService] attribute above triggers the creation of a global singleton registered for lookup by interface HasState<StatusData>

The dependency-injection package assigns references to service singletons

The [Inject] causes that property to be assigned with the registered HasState<StatusData> singleton

The controllers package simplifies use of dependency injection and notifications

Extending Controller gives out-of-box support for Dependency Injection and simplified notificaton binding. It isn't necessary to extend controller though. For example, you could alternatively enable dependency injection on a plain MonoBehavior like this:

void Start()
{
    // Something needs to call DependencyInjection.InjectDependencies.
    // The Controller base class would have done this for you
    BeatThat.DependencyInjection.InjectDependencies.On(this);
}

Making sure to cleanup/unregister notification listeners

If you're listening for notifications from a class that doesn't live forever0--e.g. a screen--it's important to always unregister any listeners attached to the NotificationBus. For example, if you have a screen that's listening for those StatusData notifications above, and then the user exits/destroys that screen, it will cause errors and memory leaks if the (now zombie/destroyed) screen continues receiving notifications.

This is another reason we use that Controller base class above. Because it has a Bind(string notificationType, System.Action callback) function that takes care of that cleanup for you.

If you were making a screen from raw MonoBehavior and wanted to implement register + cleanup of noticiations properly, it would look like this:

using BeatThat.Notifications;
class MyScreen : MonoBehavior
{
    private NotificationBinding binding;
    void OnEnable() {
        this.binding = NotificationBus.Add("somenotification", this.OnNotification);
    }

    void OnNotification() {
        // do whatever
    }

    void OnDisable() {
        if(this.binding != null) {
            this.binding.Unbind();
            this.binding = null;
        }
    }
}

...again for comparison, if we used the Controller base class the same thing would look like this:

using BeatThat.Controllers;
using BeatThat.Notifications;
class MyScreen : Controller
{
    override protected void OnGoController() {
        // we don't need to worry about cleaning up,
        // controller does that for us
        Bind("somenotification", this.OnNotification);
    }

    void OnNotification() {
        // do whatever
    }
}

notifications's People

Contributors

beatthat avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.