/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #ifndef AZFRAMEWORK_TARGETMANAGEMENTAPI_H #define AZFRAMEWORK_TARGETMANAGEMENTAPI_H #include #include #include #include #include #include #include #include #include #include #include #include AZ_DECLARE_BUDGET(AzFramework); namespace AZ { class ReflectContext; } namespace AzFramework { typedef AZ::u64 MsgSlotId; // meant to be a crc32, but using AZ::u64 so it can be other stuff (pointers) // id for the local application static const AZ::u32 k_selfNetworkId = static_cast(-1); enum TargetFlags { TF_NONE = 0, TF_ONLINE = (1 << 0), TF_DEBUGGABLE = (1 << 1), // can we debug this guy (set breakpoints and step and so on)? TF_RUNNABLE = (1 << 2), // can we emit script to this guy? (execute remote?) TF_SELF = (1 << 3), // target represents local application (self) }; class TargetManagementComponent; class TargetInfo final { friend class TargetManagementComponent; friend class TargetManagementNetworkImpl; public: AZ_CLASS_ALLOCATOR(TargetInfo, AZ::OSAllocator, 0); AZ_TYPE_INFO(TargetInfo, "{4D166C31-D7F4-4d49-B897-16365B8B0716}"); TargetInfo(time_t lastSeen = 0, const AZStd::string& displayName = "", AZ::u32 networkId = 0, TargetFlags flags = (TargetFlags)0) : m_lastSeen(lastSeen) , m_displayName(displayName) , m_persistentId(0) , m_networkId(networkId) , m_flags(flags) {} bool IsSelf() const; bool IsValid() const; const char* GetDisplayName() const; AZ::u32 GetPersistentId() const; int GetNetworkId() const; AZ::u32 GetStatusFlags() const; bool IsIdentityEqualTo(const TargetInfo& other) const; private: time_t m_lastSeen; // how long ago was this process seen? Used internally for filtering and showing the user the GUI even when the target is temporarily disconnected. AZStd::string m_displayName; AZ::u32 m_persistentId; // this string is set by the target and its CRC is currently used to determine desired targets. AZ::u32 m_networkId; // this is the actual connection id, used for gridmate communications, and is NOT persistent. AZ::u32 m_flags; // status flags }; typedef AZStd::unordered_map TargetContainer; class TmMsg { friend class TargetManagementComponent; public: AZ_CLASS_ALLOCATOR(TmMsg, AZ::OSAllocator, 0); AZ_RTTI(TmMsg, "{E16CA6C5-5C78-4AD0-8E9B-A8C1FB4D1DA8}"); TmMsg() : m_msgId(0) , m_senderTargetId(0) , m_customBlob(NULL) , m_customBlobSize(0) , m_refCount(0) , m_isBlobOwner(false) , m_immediateSelfDispatch(false) {} TmMsg(MsgSlotId msgId) : m_msgId(msgId) , m_senderTargetId(0) , m_customBlob(NULL) , m_customBlobSize(0) , m_refCount(0) , m_isBlobOwner(false) , m_immediateSelfDispatch(false) {} virtual ~TmMsg() { if (m_isBlobOwner) { azfree(const_cast(m_customBlob), AZ::OSAllocator); } } void AddCustomBlob(const void* blob, size_t blobSize, bool ownBlob = false) { m_customBlob = blob; m_customBlobSize = static_cast(blobSize); m_isBlobOwner = ownBlob; } void SetImmediateSelfDispatchEnabled(bool immediateSelfDispatchEnabled) { m_immediateSelfDispatch = immediateSelfDispatchEnabled; } bool IsImmediateSelfDispatchEnabled() const { return m_immediateSelfDispatch; } const void* GetCustomBlob() const { return m_customBlob; } size_t GetCustomBlobSize() const { return m_customBlobSize; } MsgSlotId GetId() const { return m_msgId; } AZ::u32 GetSenderTargetId() const { return m_senderTargetId; } protected: MsgSlotId m_msgId; AZ::u32 m_senderTargetId; const void* m_customBlob; AZ::u32 m_customBlobSize; bool m_isBlobOwner; bool m_immediateSelfDispatch; //--------------------------------------------------------------------- // refcount //--------------------------------------------------------------------- template friend struct AZStd::IntrusivePtrCountPolicy; AZ_FORCE_INLINE void add_ref() { ++m_refCount; } AZ_FORCE_INLINE void release() { if (--m_refCount == 0) { delete this; } } size_t m_refCount; //--------------------------------------------------------------------- }; typedef AZStd::intrusive_ptr TmMsgPtr; typedef AZStd::deque TmMsgQueue; // Systems that intend to receive messages should connect to this bus based on the message Id. class TmMsgEvents : public AZ::EBusTraits { public: ////////////////////////////////////////////////////////////////////////// // EBusTraits overrides typedef AZ::OSStdAllocator AllocatorType; typedef MsgSlotId BusIdType; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; ////////////////////////////////////////////////////////////////////////// virtual ~TmMsgEvents() {} virtual void OnReceivedMsg(TmMsgPtr msg) = 0; }; typedef AZ::EBus TmMsgBus; class TmMsgCallback : public TmMsgBus::Handler { public: AZ_CLASS_ALLOCATOR(TmMsgCallback, AZ::OSAllocator, 0); typedef AZStd::function MsgCB; TmMsgCallback(const MsgCB& cb = NULL) : m_cb(cb) {} void OnReceivedMsg(TmMsgPtr msg) override { if (m_cb) { m_cb(msg); } } protected: MsgCB m_cb; }; // this is the bus you should implement if you're interested in receiving broadcasts from teh target manager // about network and target status. class TargetManagerClient : public AZ::EBusTraits { public: typedef AZ::EBus Bus; typedef AZStd::recursive_mutex MutexType; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; // broadcast to all static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; // many handlers static const bool EnableEventQueue = true; virtual void DesiredTargetConnected(bool connected) { (void)connected; } virtual void TargetJoinedNetwork(TargetInfo info) { (void)info; } virtual void TargetLeftNetwork(TargetInfo info) { (void)info; } virtual void DesiredTargetChanged(AZ::u32 newTargetID, AZ::u32 oldTargetID) { (void)newTargetID; (void)oldTargetID; } virtual ~TargetManagerClient() {} }; // this is the bus the targetmanager itself implements - send messages to this bus to talk to it! class TargetManager : public AZ::EBusTraits { public: typedef AZ::EBus Bus; static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; // there's only one target manager right now static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; // theres only one target manager right now virtual ~TargetManager() { } // call this function to retrieve the list of currently known targets - this is mainly used for GUIs // when they come online and attempt to enum (they won't have been listening for target coming and going) // you will only be shown targets that have been seen in a reasonable amount of time. virtual void EnumTargetInfos(TargetContainer& infos) = 0; // set the desired target, which we'll specifically keep track of. // the target controls who gets lua commands, tweak stuff, that kind of thing virtual void SetDesiredTarget(AZ::u32 desiredTargetID) = 0; virtual void SetDesiredTargetInfo(const TargetInfo& targetInfo) = 0; // retrieve what it was set to. virtual TargetInfo GetDesiredTarget() = 0; // given id, get info. virtual TargetInfo GetTargetInfo(AZ::u32 desiredTargetID) = 0; // check if target is online virtual bool IsTargetOnline(AZ::u32 desiredTargetID) = 0; virtual bool IsDesiredTargetOnline() = 0; // set/get the name that is going to identify the local node in the neighborhood virtual void SetMyPersistentName(const char* name) = 0; virtual const char* GetMyPersistentName() = 0; virtual TargetInfo GetMyTargetInfo() const = 0; // set/get the name of the neighborhood we want to connect to virtual void SetNeighborhood(const char* name) = 0; virtual const char* GetNeighborhood() = 0; // send a message to a remote target virtual void SendTmMessage(const TargetInfo& target, const TmMsg& msg) = 0; // manually force messages for a specific id to be delivered. virtual void DispatchMessages(MsgSlotId id) = 0; }; }; #endif // AZFRAMEWORK_TARGETMANAGEMENTAPI_H #pragma once