[GFFrameWork] event system

Posted by sloppstack on Fri, 29 Nov 2019 20:54:32 +0100

Preface

Event throwing and event receiving are also common decoupling methods in game development. I understand that the design mode spectator mode has similar principles, so the event system is still a very important part in a framework. The native event system is not a large system, and there is not much code. The main idea is to register and monitor.

Code

EventManager

//-------------------------------------------
// Copyright © Aladdin. All rights reserved.
// Homepage: http://dingxiaowei.cn/
// Author: Aladdin
// Time: 2019/3/22 11:02:40
//-------------------------------------------

using GF.Debug;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace GF.EventSystem
{
    /// <summary>
    ///Message distributor
    /// </summary>
    public class EventManager
    {
        private static EventManager instance;
        public static EventManager Instance
        {
            get
            {
                if (null == instance)
                    instance = new EventManager();
                return instance;
            }
            set
            {
                instance = value;
            }
        }
        /// <summary>
        ///Delegation event
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sender"></param>
        /// <param name="evt"></param>
        public delegate void EventHandler<T>(object sender, T evt);

        /// <summary>
        ///Register event dictionary
        /// </summary>
        public Dictionary<Type, List<object>> handlers = new Dictionary<Type, List<object>>();

        /// <summary>
        ///Register events
        /// </summary>
        ///< typeparam name = "t" > class type < / typeparam >
        ///< param name = "handler" > function < / param >
        public void Register<T>(EventHandler<T> handler)
        {
            Debugger.Log("Registration event:" + handler.Method.Name);
            Register(typeof(T), handler);
        }

        private void Register<T>(Type EventType, EventHandler<T> handler)
        {
            if (!handlers.ContainsKey(EventType))
            {
                handlers.Add(EventType, new List<object>());
            }
            if (!handlers[EventType].Contains(handler))
            {
                handlers[EventType].Add(handler);
            }
        }

        /// <summary>
        ///Distribute events
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sender"></param>
        /// <param name="evt"></param>
        public void Publish<T>(object sender, T evt)
        {
            subscribe(null, typeof(T), evt);
        }

        /// <summary>
        ///Send notification event
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sender"></param>
        /// <param name="EventType"></param>
        /// <param name="evt"></param>
        private void publish<T>(object sender, Type EventType, T evt)
        {
            if (handlers.ContainsKey(EventType))
            {
                Debugger.Log("public event key:" + typeof(T));
                //Remove all invalid events
                handlers[EventType].RemoveAll(delegate (object handler) { return handler == null; });

                for (int i = 0; i < handlers[EventType].Count; i++)
                {
                    object handler = handlers[EventType][i];
                    MethodInfo method = handler.GetType().GetMethod("Invoke");
                    method.Invoke(handler, new object[] { sender, evt });
                }
            }
            else
            {
                Debugger.Log(string.Format("<color=red>Unregistered Key:{0}</color>", EventType));
            }
        }


        /// <summary>
        ///Logout event
        /// </summary>
        ///< typeparam name = "t" > type < / typeparam >
        ///< param name = "handler" > register function name < / param >
        public void UnRegister<T>(EventHandler<T> handler)
        {
            UnRegister(typeof(T), handler);
        }

        private void UnRegister<T>(Type EventType, EventHandler<T> handler)
        {
            if (handlers.ContainsKey(EventType))
            {
                handlers[EventType].Remove(handler);
                Debugger.Log("Remove Event:" + handler);

                if (0 == handlers[EventType].Count)//Remove the dictionary Key when the registration event is empty
                {
                    handlers.Remove(EventType);
                }
            }
        }

        /// <summary>
        ///Clear registration event
        /// </summary>
        public void Clear()
        {
            handlers.Clear();
        }
    }
}

Use

Monitoring messages

EventManager.Instance.Register<FishRoundData>(onFrameData);

Cancel listening

EventManager.Instance.UnRegister<FishRoundData>(onFrameData);

Listen to message callback
private void onFrameData(object sender, FishRoundData data)
{

}
Distribution message

EventManager.Instance.Publish<FishRoundData>(this, roundData.Value);

Improvement

We can abstract the event structure we want to listen to, and then directly inherit this base class for every new message added. In this way, we can listen to the message callback as a unified method, and then force data to become a custom event structure.

Event base class GFEventArgs
  /// <summary>
    ///The base class of the class that contains event data in the game framework.
    /// </summary>
    public abstract class GFEventArgs : EventArgs
    {
        /// <summary>
        ///Initializes a new instance of a class in the game framework that contains event data.
        /// </summary>
        public GFEventArgs()
        {

        }
    }
Game event base class
/// <summary>
    ///Game logic event base class.
    /// </summary>
    public abstract class GameEventArgs : GFEventArgs
    {

    }
EventManager
internal sealed class EventManager1
{
    private readonly List<GameEventArgs> m_EventPool;

    public EventManager1()
    {
        m_EventPool = new List<GameEventArgs>();
    }

    public bool Check(int id, EventHandler<GameEventArgs> handler)
    {
        //Check event
    }

    public void Subscribe(int id, EventHandler<GameEventArgs> handler)
    {
        //Subscription message
    }

    public void Unsubscribe(int id, EventHandler<GameEventArgs> handler)
    {
        //Cancel subscription
    }

    public void Fire(object sender, GameEventArgs e)
    {
        //Put into event response queue
    }

    public void FireNow(object sender, GameEventArgs e)
    {
        //Immediate response
    }
}

Use

Event.Subscribe(OpenUIFormSuccessEventArgs.EventId, OnOpenUIFormSuccess);

private void OnOpenUIFormSuccess(object sender, GameEventArgs e)
{
    OpenUIFormSuccessEventArgs ne = (OpenUIFormSuccessEventArgs)e;
    // Determine if userData is yourself
    if (ne.UserData != this)
    {
        return;
    }
    Log.Debug("UI_Menu: Congratulations, you have successfully called me.");
}

GFFramework address

https://github.com/dingxiaowei/GFFrameWork

More tutorials

http://dingxiaowei.cn/

Topics: github