コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity】シンプルな非同期の Pub / Sub パターン

ソースコード

using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;

namespace Kogane
{
    /// <summary>
    /// 非同期の Pub / Sub パターン
    /// </summary>
    public static class AsyncMessageBroker
    {
        //================================================================================
        // 変数(static)
        //================================================================================
        private static Dictionary<Type, object> m_callbacksTable = new();

        //================================================================================
        // 関数(static)
        //================================================================================
#if UNITY_EDITOR
        /// <summary>
        /// Unity 再生時に呼び出されます
        /// </summary>
        [UnityEditor.InitializeOnEnterPlayMode]
        private static void InitializeOnEnterPlayMode()
        {
            m_callbacksTable = new();
        }
#endif

        /// <summary>
        /// コールバックを追加します
        /// </summary>
        public static void Add<T>( Func<T, UniTask> callback )
        {
            var type = typeof( T );

            if ( !m_callbacksTable.ContainsKey( type ) )
            {
                m_callbacksTable[ type ] = new List<Func<T, UniTask>>();
            }

            var callbacks = ( List<Func<T, UniTask>> )m_callbacksTable[ type ];
            callbacks.Add( callback );
        }

        /// <summary>
        /// コールバックを削除します
        /// </summary>
        public static void Remove<T>( Func<T, UniTask> callback )
        {
            var type = typeof( T );

            if ( !m_callbacksTable.ContainsKey( type ) ) return;
            if ( m_callbacksTable[ type ] == null ) return;

            var callbacks = ( List<Func<T, UniTask>> )m_callbacksTable[ type ];
            callbacks.Remove( callback );
        }

        /// <summary>
        /// データを送信します
        /// </summary>
        public static async UniTask SendAsync<T>( T data )
        {
            var type = typeof( T );

            if ( !m_callbacksTable.TryGetValue( type, out var value ) ) return;

            var callbacks = ( List<Func<T, UniTask>> )value;

            if ( callbacks is not { Count: > 0 } ) return;

            await UniTask.WhenAll( callbacks.Select( x => x( data ) ) );
        }
    }
}