这个模块是EBus的具体实现,在这里将EBus需要各个模块的功能组合起来,实现一些完整的EBus功能。

一些预定义的数据结构

NullMutex

    /**
     * A dummy mutex that performs no locking.
     * EBuses that do not support multithreading use this mutex
     * as their EBusTraits::MutexType.
     */
    struct NullMutex
    {
        void lock() {}
        bool try_lock() { return true; }
        void unlock() {}
    };

无锁的EBus使用的Mutex。

NullBusId

    /**
     * Indicates that EBusTraits::BusIdType is not set.
     * EBuses with multiple addresses must set the EBusTraits::BusIdType.
     */
    struct NullBusId
    {
        NullBusId() {};
        NullBusId(int) {};
    };
 
    /// @cond EXCLUDE_DOCS
    inline bool operator==(const NullBusId&, const NullBusId&) { return true; }
    inline bool operator!=(const NullBusId&, const NullBusId&) { return false; }
    /// @endcond
    
    /**
     * Indicates that EBusTraits::BusIdOrderCompare is not set.
     * EBuses with ordered address IDs must specify a function for
     * EBusTraits::BusIdOrderCompare.
     */
    struct NullBusIdCompare;

不使用Address功能的EBus使用的BusId和它的比较函数。

NullLockGuard

    namespace Internal
    {
        // Lock guard used when there is a NullMutex on a bus, or during dispatch
        // on a bus which supports LocklessDispatch.
        template <class Lock>
        struct NullLockGuard
        {
            explicit NullLockGuard(Lock&) {}
            NullLockGuard(Lock&, AZStd::adopt_lock_t) {}
 
            void lock() {}
            bool try_lock() { return true; }
            void unlock() {}
        };
    }

不使用Mutex时,没有任何功能的LockGuard。

EBusImplTraits

包含了EBusTraits的内部的各种数据结构。

        template <class Interface, class BusTraits>
        struct EBusImplTraits
        {
            /**
             * Properties that you use to configure an EBus.
             * For more information, see EBusTraits.
             */
            using Traits = BusTraits;
 
            /**
             * Allocator used by the EBus.
             * The default setting is AZStd::allocator, which uses AZ::SystemAllocator.
             */
            using AllocatorType = typename Traits::AllocatorType;
 
            /**
             * The class that defines the interface of the EBus.
             */
            using InterfaceType = Interface;
 
            /**
             * The events defined by the EBus interface.
             */
            using Events = Interface;
 
            /**
             * The type of ID that is used to address the EBus.
             * Used only when the address policy is AZ::EBusAddressPolicy::ById
             * or AZ::EBusAddressPolicy::ByIdAndOrdered.
             * The type must support `AZStd::hash<ID>` and
             * `bool operator==(const ID&, const ID&)`.
             */
            using BusIdType = typename Traits::BusIdType;
 
            /**
             * Sorting function for EBus address IDs.
             * Used only when the AddressPolicy is AZ::EBusAddressPolicy::ByIdAndOrdered.
             * If an event is dispatched without an ID, this function determines
             * the order in which each address receives the event.
             *
             * The following example shows a sorting function that meets these requirements.
             * @code{.cpp}
             * using BusIdOrderCompare = AZStd::less<BusIdType>; // Lesser IDs first.
             * @endcode
             */
            using BusIdOrderCompare = typename Traits::BusIdOrderCompare;
 
            /**
             * Locking primitive that is used when connecting handlers to the EBus or executing events.
             * By default, all access is assumed to be single threaded and no locking occurs.
             * For multithreaded access, specify a mutex of the following type.
             * - For simple multithreaded cases, use AZStd::mutex.
             * - For multithreaded cases where an event handler sends a new event on the same bus
             *   or connects/disconnects while handling an event on the same bus, use AZStd::recursive_mutex.
             */
            using MutexType = typename Traits::MutexType;
 
            /**
             * Contains all of the addresses on the EBus.
             */
            using BusesContainer = AZ::Internal::EBusContainer<Interface, Traits>;
 
            /**
             * Locking primitive that is used when executing events in the event queue.
             */
            using EventQueueMutexType = AZStd::conditional_t<AZStd::is_same<typename Traits::EventQueueMutexType, NullMutex>::value, // if EventQueueMutexType==NullMutex use MutexType otherwise EventQueueMutexType
                MutexType, typename Traits::EventQueueMutexType>;
 
            /**
             * Pointer to an address on the bus.
             */
            using BusPtr = typename BusesContainer::BusPtr;
 
            /**
             * Pointer to a handler node.
             */
            using HandlerNode = typename BusesContainer::HandlerNode;
 
            /**
             * Specifies whether the EBus supports an event queue.
             * You can use the event queue to execute events at a later time.
             * To execute the queued events, you must call
             * `<BusName>::ExecuteQueuedEvents()`.
             * By default, the event queue is disabled.
             */
            static constexpr bool EnableEventQueue = Traits::EnableEventQueue;
            static constexpr bool EventQueueingActiveByDefault = Traits::EventQueueingActiveByDefault;
            static constexpr bool EnableQueuedReferences = Traits::EnableQueuedReferences;
 
            /**
             * True if the EBus supports more than one address. Otherwise, false.
             */
            static constexpr bool HasId = Traits::AddressPolicy != EBusAddressPolicy::Single;
 
            /**
             * The following Lock Guard classes are exposed so that it's possible to override them with custom lock/unlock functionality
             * when using custom types for the EBus MutexType.
             */
 
            /**
            * Template Lock Guard class that wraps around the Mutex
            * The EBus uses for Dispatching Events.
            * This is not the EBus Context Mutex if LocklessDispatch is true
            */
            template <typename DispatchMutex>
            using DispatchLockGuard = typename Traits::template DispatchLockGuard<DispatchMutex, Traits::LocklessDispatch>;
 
            /**
             * Template Lock Guard class that protects connection / disconnection. 
             */
            template<typename ContextMutex>
            using ConnectLockGuard = typename Traits::template ConnectLockGuard<ContextMutex>;
 
            /**
             * Template Lock Guard class that protects bind calls. 
             */
            template<typename ContextMutex>
            using BindLockGuard = typename Traits::template BindLockGuard<ContextMutex>;
 
            /**
             * Template Lock Guard class that protects callstack tracking.
             */
            template<typename ContextMutex>
            using CallstackTrackerLockGuard = typename Traits::template CallstackTrackerLockGuard<ContextMutex>;
        };

traits中定义了EBus中的各种数据类型,它们大都从模板参数BusTraits中获得。

EBusEventer

        /**
         * Dispatches events to handlers that are connected to a specific address on an EBus.
         * @tparam Bus       The EBus type.
         * @tparam Traits    A class that inherits from EBusTraits and configures the EBus.
         *                   This parameter may be left unspecified if the `Interface` class
         *                   inherits from EBusTraits.
         */
        template <class Bus, class Traits>
        struct EBusEventer
        {
            /**
             * The type of ID that is used to address the EBus.
             * Used only when the address policy is AZ::EBusAddressPolicy::ById
             * or AZ::EBusAddressPolicy::ByIdAndOrdered.
             * The type must support `AZStd::hash<ID>` and
             * `bool operator==(const ID&, const ID&)`.
             */
            using BusIdType = typename Traits::BusIdType;
 
            /**
             * Pointer to an address on the bus.
             */
            using BusPtr = typename Traits::BusPtr;
 
            /**
             * An event handler that can be attached to multiple addresses.
             */
            using MultiHandler = typename Traits::BusesContainer::MultiHandler;
 
            /**
             * Acquires a pointer to an EBus address.
             * @param[out] ptr A pointer that will point to the specified address
             * on the EBus. An address lookup can be avoided by calling Event() with
             * this pointer rather than by passing an ID, but that is only recommended
             * for performance-critical code.
             * @param id The ID of the EBus address that the pointer will be bound to.
             */
            static void Bind(BusPtr& ptr, const BusIdType& id);
        };

用于分发事件到连接至某个特定地址的EBus的handlers。但是这里只有一个Bind函数,具体的定义如下:

        template <class Bus, class Traits>
        inline void EBusEventer<Bus, Traits>::Bind(BusPtr& ptr, const BusIdType& id)
        {
            auto& context = Bus::GetOrCreateContext();
            typename Traits::template BindLockGuard<decltype(context.m_contextMutex)> lock(context.m_contextMutex);
            context.m_buses.Bind(ptr, id);
        }

context.m_buses是一个EBusContainer,所以这里使用的是EBusContainer的Bind函数,它的功能是将这个id绑定到一个BusPtr,可以理解为给EBus赋予一个id。
这个struct实际的功能感觉和描述并不相符,它里面没有任何分发事件的行为,只有一个bind函数。

EBusEventEnumerator

用于寻找连接在某个EBus上的handler。

        /**
         * Provides functionality that requires enumerating over handlers that are connected
         * to an EBus. It can enumerate over all handlers or just the handlers that are connected
         * to a specific address on an EBus.
         * @tparam Bus       The EBus type.
         * @tparam Traits    A class that inherits from EBusTraits and configures the EBus.
         *                   This parameter may be left unspecified if the `Interface` class
         *                   inherits from EBusTraits.
         */
        template <class Bus, class Traits>
        struct EBusEventEnumerator
        {
            /**
             * The type of ID that is used to address the EBus.
             * Used only when the address policy is AZ::EBusAddressPolicy::ById
             * or AZ::EBusAddressPolicy::ByIdAndOrdered.
             * The type must support `AZStd::hash<ID>` and
             * `bool operator==(const ID&, const ID&)`.
             */
            using BusIdType = typename Traits::BusIdType;
 
            /**
             * Pointer to an address on the bus.
             */
            using BusPtr = typename Traits::BusPtr;
 
            /**
             * Finds the first handler that is connected to a specific address on the EBus.
             * This function is only for special cases where you know that a particular
             * component's handler is guaranteed to exist.
             * Even if the returned pointer is valid (not null), it might point to a handler
             * that was deleted. Prefer dispatching events using EBusEventer.
             * @param id        Address ID.
             * @return          A pointer to the first handler on the EBus, even if the handler
             *                  was deleted.
             */
            static typename Traits::InterfaceType* FindFirstHandler(const BusIdType& id);
 
            /**
             * Finds the first handler at a cached address on the EBus.
             * This function is only for special cases where you know that a particular
             * component's handler is guaranteed to exist.
             * Even if the returned pointer is valid (not null), it might point to a handler
             * that was deleted. Prefer dispatching events using EBusEventer.
             * @param ptr       Cached address ID.
             * @return          A pointer to the first handler on the specified EBus address,
             *                  even if the handler was deleted.
             */
            static typename Traits::InterfaceType* FindFirstHandler(const BusPtr& ptr);
 
            /**
             * Returns the total number of event handlers that are connected to a specific
             * address on the EBus.
             * @param id    Address ID.
             * @return      The total number of handlers that are connected to the EBus address.
             */
            static size_t GetNumOfEventHandlers(const BusIdType& id);
        };
 

同样通过Traits来获取类型信息,其中有3个静态函数,两个FindFirstHandler功能是相同的,通过BusId/BusPtr来找到第一个连接在它们上面的Handler。GetNumOfEventHandlers计算连接到此EBus上的Handler上数量(它没有BusPtr版本,只有BusId版本)。
具体实现:

        template <class Bus, class Traits>
        typename Traits::InterfaceType * EBusEventEnumerator<Bus, Traits>::FindFirstHandler(const BusIdType& id)
        {
            typename Traits::InterfaceType* result = nullptr;
            Bus::EnumerateHandlersId(id, [&result](typename Traits::InterfaceType* handler)
            {
                result = handler;
                return false;
            });
            return result;
        }

这里调用了EnumerateHandlersId函数,在BusContainer中出现过,它的功能是在该id的EBus上执行一个函数,就像for_each一样,这里的函数就是将它的hander赋值给result,并且第一次就返回false,实现拿到第一个handler就停止的目的。
GetNumOfEventHandlers实现:

        template <class Bus, class Traits>
        size_t EBusEventEnumerator<Bus, Traits>::GetNumOfEventHandlers(const BusIdType& id)
        {
            size_t size = 0;
            Bus::EnumerateHandlersId(id, [&size](typename Bus::InterfaceType*)
            {
                ++size;
                return true;
            });
            return size;
        }

同样使用了EnumerateHandlersId函数,对所有handler进行计数。

EBusBroadcaster

用于分发事件至所有handler,与EBusEventer向对,EBusEventer只分发至某个EBus上的handler。

        /**
         * Dispatches an event to all handlers that are connected to an EBus.
         * @tparam Bus       The EBus type.
         * @tparam Traits    A class that inherits from EBusTraits and configures the EBus.
         *                   This parameter may be left unspecified if the `Interface` class
         *                   inherits from EBusTraits.
         */
        template <class Bus, class Traits>
        struct EBusBroadcaster
        {
            /**
             * An event handler that can be attached to only one address at a time.
             */
            using Handler = typename Traits::BusesContainer::Handler;
        };

这里没有任何实现,看起来EBusBroadcaster和EBusEventer都不具备它们应有的功能,对应的功能位于EBusContainer中,这是未实现的设计?

EBusNullQueue

不能实现排序功能的EBus使用的数据结构。

        /**
         * Data type that is used when an EBus doesn't support queuing.
         */
        struct EBusNullQueue
        {
        };

里面什么都没有。

EBusBroadcastQueue

EBusBroadcaster的升级版,按顺序广播一个事件至所有handler。

 
        /**
         * EBus functionality related to the queuing of events and functions.
         * This is specifically for queuing events and functions that will
         * be broadcast to all handlers on the EBus.
         * @tparam Bus       The EBus type.
         * @tparam Traits    A class that inherits from EBusTraits and configures the EBus.
         *                   This parameter may be left unspecified if the `Interface` class
         *                   inherits from EBusTraits.
         */
        template <class Bus, class Traits>
        struct EBusBroadcastQueue
        {
            /**
             * Executes queued events and functions.
             * Execution will occur on the thread that calls this function.
             * @see QueueBroadcast(), EBusEventQueue::QueueEvent(), QueueFunction(), ClearQueuedEvents()
             */
            static void ExecuteQueuedEvents()
            {
                if (auto* context = Bus::GetContext())
                {
                    context->m_queue.Execute();
                }
            }
 
            /**
             * Clears the queue without calling events or functions.
             * Use in situations where memory must be freed immediately, such as shutdown.
             * Use with care. Cleared queued events will never be executed, and those events might have been expected.
             */
            static void ClearQueuedEvents()
            {
                if (auto* context = Bus::GetContext(false))
                {
                    context->m_queue.Clear();
                }
            }
 
            static size_t QueuedEventCount()
            {
                if (auto* context = Bus::GetContext(false))
                {
                    return context->m_queue.Count();
                }
                return 0;
            }
 
            /**
             * Sets whether function queuing is allowed.
             * This does not affect event queuing.
             * Function queuing is allowed by default when EBusTraits::EnableEventQueue
             * is true. It is never allowed when EBusTraits::EnableEventQueue is false.
             * @see QueueFunction, EBusTraits::EnableEventQueue
             * @param isAllowed Set to true to allow function queuing. Otherwise, set to false.
             */
            static void AllowFunctionQueuing(bool isAllowed) { Bus::GetOrCreateContext().m_queue.SetActive(isAllowed); }
 
            /**
             * Returns whether function queuing is allowed.
             * @return True if function queuing is allowed. Otherwise, false.
             * @see QueueFunction, AllowFunctionQueuing
             */
            static bool IsFunctionQueuing()
            {
                auto* context = Bus::GetContext();
                return context ? context->m_queue.IsActive() : Traits::EventQueueingActiveByDefault;
            }
 
            /**
            * Helper to Queue a Broadcast only when function queueing is available
            * @param func          Function pointer of the event to dispatch.
            * @param args          Function arguments that are passed to each handler.
            */
            template <class Function, class ... InputArgs>
            static void TryQueueBroadcast(Function&& func, InputArgs&& ... args);
 
            /**
             * Enqueues an asynchronous event to dispatch to all handlers.
             * The event is not executed until ExecuteQueuedEvents() is called.
             * @param func          Function pointer of the event to dispatch.
             * @param args          Function arguments that are passed to each handler.
             */
            template <class Function, class ... InputArgs>
            static void QueueBroadcast(Function&& func, InputArgs&& ... args);
 
            /**
            * Helper to Queue a Reverse Broadcast only when function queueing is available
            * @param func          Function pointer of the event to dispatch.
            * @param args          Function arguments that are passed to each handler.
            */
            template <class Function, class ... InputArgs>
            static void TryQueueBroadcastReverse(Function&& func, InputArgs&& ... args);
 
            /**
             * Enqueues an asynchronous event to dispatch to all handlers in reverse order.
             * The event is not executed until ExecuteQueuedEvents() is called.
             * @param func          Function pointer of the event to dispatch.
             * @param args          Function arguments that are passed to each handler.
             */
            template <class Function, class ... InputArgs>
            static void QueueBroadcastReverse(Function&& func, InputArgs&& ... args);
 
            /**
             * Enqueues an arbitrary callable function to be executed asynchronously.
             * The function is not executed until ExecuteQueuedEvents() is called.
             * The function might be unrelated to this EBus or any handlers.
             * Examples of callable functions are static functions, lambdas, and
             * bound-member functions.
             *
             * One use case is to determine when a batch of queued events has finished.
             * When the function is executed, we know that all events that were queued
             * before the function have finished executing.
             *
             * @param func Callable function.
             * @param args Arguments for `func`.
             */
            template <class Function, class ... InputArgs>
            static void QueueFunction(Function&& func, InputArgs&& ... args);
        };

这个结构体的功能就是对EBusQueuePolicy的应用,它作为一个数据保存在EBus中,其中有一个队列message,里面保存了很多函数,