1 /// \file 2 /// \brief Ready event plugin. This enables a set of systems to create a signal event, set this signal as ready or unready, and to trigger the event when all systems are ready 3 /// 4 /// This file is part of RakNet Copyright 2003 Jenkins Software LLC 5 /// 6 /// Raknet is available under the terms of the GPLv3 license, see /usr/local/share/licenses/raknet-3.9.2_10,1/GPLv3. 7 8 #include "NativeFeatureIncludes.h" 9 #if _RAKNET_SUPPORT_ReadyEvent==1 10 11 #ifndef __READY_EVENT_H 12 #define __READY_EVENT_H 13 14 class RakPeerInterface; 15 #include "PluginInterface2.h" 16 #include "DS_OrderedList.h" 17 18 /// \defgroup READY_EVENT_GROUP ReadyEvent 19 /// \brief Peer to peer synchronized ready and unready events 20 /// \details 21 /// \ingroup PLUGINS_GROUP 22 23 /// \ingroup READY_EVENT_GROUP 24 /// Returns the status of a remote system when querying with ReadyEvent::GetReadyStatus 25 enum ReadyEventSystemStatus 26 { 27 /// ----------- Normal states --------------- 28 /// The remote system is not in the wait list, and we have never gotten a ready or complete message from it. 29 /// This is the default state for valid events 30 RES_NOT_WAITING, 31 /// We are waiting for this remote system to call SetEvent(thisEvent,true). 32 RES_WAITING, 33 /// The remote system called SetEvent(thisEvent,true), but it still waiting for other systems before completing the ReadyEvent. 34 RES_READY, 35 /// The remote system called SetEvent(thisEvent,true), and is no longer waiting for any other systems. 36 /// This remote system has completed the ReadyEvent 37 RES_ALL_READY, 38 39 /// Error code, we couldn't look up the system because the event was unknown 40 RES_UNKNOWN_EVENT, 41 }; 42 43 /// \brief Peer to peer synchronized ready and unready events 44 /// \details For peer to peer networks in a fully connected mesh.<BR> 45 /// Solves the problem of how to tell if all peers, relative to all other peers, are in a certain ready state.<BR> 46 /// For example, if A is connected to B and C, A may see that B and C are ready, but does not know if B is ready to C, or vice-versa.<BR> 47 /// This plugin uses two stages to solve that problem, first, everyone I know about is ready. Second, everyone I know about is ready to everyone they know about.<BR> 48 /// The user will get ID_READY_EVENT_SET and ID_READY_EVENT_UNSET as the signal flag is set or unset<BR> 49 /// The user will get ID_READY_EVENT_ALL_SET when all systems are done waiting for all other systems, in which case the event is considered complete, and no longer tracked.<BR> 50 /// \sa FullyConnectedMesh2 51 /// \ingroup READY_EVENT_GROUP 52 class ReadyEvent : public PluginInterface2 53 { 54 public: 55 // Constructor 56 ReadyEvent(); 57 58 // Destructor 59 virtual ~ReadyEvent(); 60 61 // -------------------------------------------------------------------------------------------- 62 // User functions 63 // -------------------------------------------------------------------------------------------- 64 /// Sets or updates the initial ready state for our local system. 65 /// If eventId is an unknown event the event is created. 66 /// If eventId was previously used and you want to reuse it, call DeleteEvent first, or else you will keep the same event signals from before 67 /// Systems previously or later added through AddToWaitList() with the same \a eventId when isReady=true will get ID_READY_EVENT_SET 68 /// Systems previously added through AddToWaitList with the same \a eventId will get ID_READY_EVENT_UNSET 69 /// For both ID_READY_EVENT_SET and ID_READY_EVENT_UNSET, eventId is encoded in bytes 1 through 1+sizeof(int) 70 /// \param[in] eventId A user-defined identifier to wait on. This can be a sequence counter, an event identifier, or anything else you want. 71 /// \param[in] isReady True to signal we are ready to proceed with this event, false to unsignal 72 /// \return True on success. False (failure) on unknown eventId 73 bool SetEvent(int eventId, bool isReady); 74 75 /// When systems can call SetEvent() with isReady==false, it is possible for one system to return true from IsEventCompleted() while the other systems return false 76 /// This can occur if a system SetEvent() with isReady==false while the completion message is still being transmitted. 77 /// If your game has the situation where some action should be taken on all systems when IsEventCompleted() is true for any system, then call ForceCompletion() when the action begins. 78 /// This will force all systems to return true from IsEventCompleted(). 79 /// \param[in] eventId A user-defined identifier to immediately set as completed 80 bool ForceCompletion(int eventId); 81 82 /// Deletes an event. We will no longer wait for this event, and any systems that we know have set the event will be forgotten. 83 /// Call this to clear memory when events are completed and you know you will never need them again. 84 /// \param[in] eventId A user-defined identifier 85 /// \return True on success. False (failure) on unknown eventId 86 bool DeleteEvent(int eventId); 87 88 /// Returns what was passed to SetEvent() 89 /// \return The value of isReady passed to SetEvent(). Also returns false on unknown event. 90 bool IsEventSet(int eventId); 91 92 /// Returns if the event is about to be ready and we are negotiating the final packets. 93 /// This will usually only be true for a very short time, after which IsEventCompleted should return true. 94 /// While this is true you cannot add to the wait list, or SetEvent() isReady to false anymore. 95 /// \param[in] eventId A user-defined identifier 96 /// \return True if any other system has completed processing. Will always be true if IsEventCompleted() is true 97 bool IsEventCompletionProcessing(int eventId) const; 98 99 /// Returns if the wait list is a subset of the completion list. 100 /// Call this after all systems you want to wait for have been added with AddToWaitList 101 /// If you are waiting for a specific number of systems (such as players later connecting), also check GetRemoteWaitListSize(eventId) to be equal to 1 less than the total number of participants. 102 /// \param[in] eventId A user-defined identifier 103 /// \return True on completion. False (failure) on unknown eventId, or the set is not completed. 104 bool IsEventCompleted(int eventId) const; 105 106 /// Returns if this is a known event. 107 /// Events may be known even if we never ourselves referenced them with SetEvent, because other systems created them via ID_READY_EVENT_SET. 108 /// \param[in] eventId A user-defined identifier 109 /// \return true if we have this event, false otherwise 110 bool HasEvent(int eventId); 111 112 /// Returns the total number of events stored in the system. 113 /// \return The total number of events stored in the system. 114 unsigned GetEventListSize(void) const; 115 116 /// Returns the event ID stored at a particular index. EventIDs are stored sorted from least to greatest. 117 /// \param[in] index Index into the array, from 0 to GetEventListSize() 118 /// \return The event ID stored at a particular index 119 int GetEventAtIndex(unsigned index) const; 120 121 /// Adds a system to wait for to signal an event before considering the event complete and returning ID_READY_EVENT_ALL_SET. 122 /// As we add systems, if this event was previously set to true with SetEvent, these systems will get ID_READY_EVENT_SET. 123 /// As these systems disconnect (directly or indirectly through the router) they are removed. 124 /// \note If the event completion process has already started, you cannot add more systems, as this would cause the completion process to fail 125 /// \param[in] eventId A user-defined number previously passed to SetEvent that has not yet completed 126 /// \param[in] addressArray An address to wait for event replies from. Pass UNASSIGNED_SYSTEM_ADDRESS for all currently connected systems. Until all systems in this list have called SetEvent with this ID and true, and have this system in the list, we won't get ID_READY_EVENT_COMPLETE 127 /// \return True on success, false on unknown eventId (this should be considered an error), or if the completion process has already started. 128 bool AddToWaitList(int eventId, SystemAddress address); 129 130 /// Removes systems from the wait list, which should have been previously added with AddToWaitList 131 /// \note Systems that directly or indirectly disconnect from us are automatically removed from the wait list 132 /// \param[in] address The system to remove from the wait list. Pass UNASSIGNED_SYSTEM_ADDRESS for all currently connected systems. 133 /// \return True on success, false on unknown eventId (this should be considered an error) 134 bool RemoveFromWaitList(int eventId, SystemAddress address); 135 136 /// Returns if a particular system is waiting on a particular event. 137 /// \param[in] eventId A user-defined identifier 138 /// \param[in] The address of the system we are checking up on 139 /// \return True if this system is waiting on this event, false otherwise. 140 bool IsInWaitList(int eventId, SystemAddress address); 141 142 /// Returns the total number of systems we are waiting on for this event. 143 /// Does not include yourself 144 /// \param[in] eventId A user-defined identifier 145 /// \return The total number of systems we are waiting on for this event. 146 unsigned GetRemoteWaitListSize(int eventId) const; 147 148 /// Returns the system address of a system at a particular index, for this event. 149 /// \param[in] eventId A user-defined identifier 150 /// \param[in] index Index into the array, from 0 to GetWaitListSize() 151 /// \return The system address of a system at a particular index, for this event. 152 SystemAddress GetFromWaitListAtIndex(int eventId, unsigned index) const; 153 154 /// For a remote system, find out what their ready status is (waiting, signaled, complete). 155 /// \param[in] eventId A user-defined identifier 156 /// \param[in] address Which system we are checking up on 157 /// \return The status of this system, for this particular event. \sa ReadyEventSystemStatus 158 ReadyEventSystemStatus GetReadyStatus(int eventId, SystemAddress address); 159 160 /// This channel will be used for all RakPeer::Send calls 161 /// \param[in] newChannel The channel to use for internal RakPeer::Send calls from this system. Defaults to 0. 162 void SetSendChannel(unsigned char newChannel); 163 164 // ---------------------------- ALL INTERNAL AFTER HERE ---------------------------- 165 /// \internal 166 /// Status of a remote system 167 struct RemoteSystem 168 { 169 MessageID lastSentStatus, lastReceivedStatus; 170 SystemAddress systemAddress; 171 }; 172 static int RemoteSystemCompBySystemAddress( const SystemAddress &key, const RemoteSystem &data ); 173 /// \internal 174 /// An event, with a set of systems we are waiting for, a set of systems that are signaled, and a set of systems with completed events 175 struct ReadyEventNode 176 { 177 int eventId; // Sorted on this 178 MessageID eventStatus; 179 DataStructures::OrderedList<SystemAddress,RemoteSystem,ReadyEvent::RemoteSystemCompBySystemAddress> systemList; 180 }; 181 static int ReadyEventNodeComp( const int &key, ReadyEvent::ReadyEventNode * const &data ); 182 183 184 protected: 185 // -------------------------------------------------------------------------------------------- 186 // Packet handling functions 187 // -------------------------------------------------------------------------------------------- 188 virtual PluginReceiveResult OnReceive(Packet *packet); 189 virtual void OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ); 190 virtual void OnRakPeerShutdown(void); 191 192 void Clear(void); 193 /* 194 bool AnyWaitersCompleted(unsigned eventIndex) const; 195 bool AllWaitersCompleted(unsigned eventIndex) const; 196 bool AllWaitersReady(unsigned eventIndex) const; 197 void SendAllReady(unsigned eventId, SystemAddress address); 198 void BroadcastAllReady(unsigned eventIndex); 199 void SendReadyStateQuery(unsigned eventId, SystemAddress address); 200 void BroadcastReadyUpdate(unsigned eventIndex); 201 bool AddToWaitListInternal(unsigned eventIndex, SystemAddress address); 202 bool IsLocked(unsigned eventIndex) const; 203 bool IsAllReadyByIndex(unsigned eventIndex) const; 204 */ 205 206 void SendReadyStateQuery(unsigned eventId, SystemAddress address); 207 void SendReadyUpdate(unsigned eventIndex, unsigned systemIndex, bool forceIfNotDefault); 208 void BroadcastReadyUpdate(unsigned eventIndex, bool forceIfNotDefault); 209 void RemoveFromAllLists(SystemAddress address); 210 void OnReadyEventQuery(Packet *packet); 211 void PushCompletionPacket(unsigned eventId); 212 bool AddToWaitListInternal(unsigned eventIndex, SystemAddress address); 213 void OnReadyEventForceAllSet(Packet *packet); 214 void OnReadyEventPacketUpdate(Packet *packet); 215 void UpdateReadyStatus(unsigned eventIndex); 216 bool IsEventCompletedByIndex(unsigned eventIndex) const; 217 unsigned CreateNewEvent(int eventId, bool isReady); 218 bool SetEventByIndex(int eventIndex, bool isReady); 219 220 DataStructures::OrderedList<int, ReadyEventNode*, ReadyEvent::ReadyEventNodeComp> readyEventNodeList; 221 unsigned char channel; 222 }; 223 224 #endif 225 226 #endif // _RAKNET_SUPPORT_* 227