1 /// \file 2 /// \brief Contains the third iteration of the ReplicaManager class. 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_ReplicaManager3==1 10 11 #ifndef __REPLICA_MANAGER_3 12 #define __REPLICA_MANAGER_3 13 14 #include "DS_Multilist.h" 15 #include "RakNetTypes.h" 16 #include "RakNetTime.h" 17 #include "BitStream.h" 18 #include "PacketPriority.h" 19 #include "PluginInterface2.h" 20 #include "NetworkIDObject.h" 21 22 /// \defgroup REPLICA_MANAGER_GROUP3 ReplicaManager3 23 /// \brief Third implementation of object replication 24 /// \details 25 /// \ingroup REPLICA_MANAGER_GROUP 26 27 namespace RakNet 28 { 29 class Connection_RM3; 30 class Replica3; 31 32 33 /// \internal 34 /// \ingroup REPLICA_MANAGER_GROUP3 35 struct PRO 36 { 37 /// Passed to RakPeerInterface::Send(). Defaults to ReplicaManager3::SetDefaultPacketPriority(). 38 PacketPriority priority; 39 40 /// Passed to RakPeerInterface::Send(). Defaults to ReplicaManager3::SetDefaultPacketReliability(). 41 PacketReliability reliability; 42 43 /// Passed to RakPeerInterface::Send(). Defaults to ReplicaManager3::SetDefaultOrderingChannel(). 44 char orderingChannel; 45 46 /// Passed to RakPeerInterface::Send(). Defaults to 0. 47 uint32_t sendReceipt; 48 49 bool operator==( const PRO& right ) const; 50 bool operator!=( const PRO& right ) const; 51 }; 52 53 54 /// \brief System to help automate game object construction, destruction, and serialization 55 /// \details ReplicaManager3 tracks your game objects and automates the networking for replicating them across the network<BR> 56 /// As objects are created, destroyed, or serialized differently, those changes are pushed out to other systems.<BR> 57 /// To use:<BR> 58 /// <OL> 59 /// <LI>Derive from Connection_RM3 and implement Connection_RM3::AllocReplica(). This is a factory function where given a user-supplied identifier for a class (such as name) return an instance of that class. Should be able to return any networked object in your game. 60 /// <LI>Derive from ReplicaManager3 and implement AllocConnection() and DeallocConnection() to return the class you created in step 1. 61 /// <LI>Derive your networked game objects from Replica3. All pure virtuals have to be implemented, however defaults are provided for Replica3::QueryConstruction(), Replica3::QueryRemoteConstruction(), and Replica3::QuerySerialization() depending on your network architecture. 62 /// <LI>When a new game object is created on the local system, pass it to ReplicaManager3::Reference(). 63 /// <LI>When a game object is destroyed on the local system, and you want other systems to know about it, call Replica3::BroadcastDestruction() 64 /// </OL> 65 /// <BR> 66 /// At this point, all new connections will automatically download, get construction messages, get destruction messages, and update serialization automatically. 67 /// \ingroup REPLICA_MANAGER_GROUP3 68 class RAK_DLL_EXPORT ReplicaManager3 : public PluginInterface2 69 { 70 public: 71 ReplicaManager3(); 72 virtual ~ReplicaManager3(); 73 74 /// \brief Implement to return a game specific derivation of Connection_RM3 75 /// \details The connection object represents a remote system connected to you that is using the ReplicaManager3 system.<BR> 76 /// It has functions to perform operations per-connection.<BR> 77 /// AllocConnection() and DeallocConnection() are factory functions to create and destroy instances of the connection object.<BR> 78 /// It is used if autoCreate is true via SetAutoManageConnections() (true by default). Otherwise, the function is not called, and you will have to call PushConnection() manually<BR> 79 /// \note If you do not want a new network connection to immediately download game objects, SetAutoManageConnections() and PushConnection() are how you do this. 80 /// \sa SetAutoManageConnections() 81 /// \param[in] systemAddress Address of the system you are adding 82 /// \param[in] rakNetGUID GUID of the system you are adding. See Packet::rakNetGUID or RakPeerInterface::GetGUIDFromSystemAddress() 83 /// \return The new connection instance. 84 virtual Connection_RM3* AllocConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID) const=0; 85 86 /// \brief Implement to destroy a class instanced returned by AllocConnection() 87 /// \details Most likely just implement as {delete connection;}<BR> 88 /// It is used if autoDestroy is true via SetAutoManageConnections() (true by default). Otherwise, the function is not called and you would then be responsible for deleting your own connection objects. 89 /// \param[in] connection The pointer instance to delete 90 virtual void DeallocConnection(Connection_RM3 *connection) const=0; 91 92 /// \brief Enable or disable automatically assigning connections to new instances of Connection_RM3 93 /// \details ReplicaManager3 can automatically create and/or destroy Connection_RM3 as systems connect or disconnect from RakPeerInterface.<BR> 94 /// By default this is on, to make the system easier to learn and setup.<BR> 95 /// If you don't want all connections to take part in the game, or you want to delay when a connection downloads the game, set \a autoCreate to false.<BR> 96 /// If you want to delay deleting a connection that has dropped, set \a autoDestroy to false. If you do this, then you must call PopConnection() to remove that connection from being internally tracked. You'll also have to delete the connection instance on your own.<BR> 97 /// \param[in] autoCreate Automatically call ReplicaManager3::AllocConnection() for each new connection. Defaults to true. 98 /// \param[in] autoDestroy Automatically call ReplicaManager3::DeallocConnection() for each dropped connection. Defaults to true. 99 void SetAutoManageConnections(bool autoCreate, bool autoDestroy); 100 101 /// \brief Track a new Connection_RM3 instance 102 /// \details If \a autoCreate is false for SetAutoManageConnections(), then you need this function to add new instances of Connection_RM3 yourself.<BR> 103 /// You don't need to track this pointer yourself, you can get it with GetConnectionAtIndex(), GetConnectionByGUID(), or GetConnectionBySystemAddress().<BR> 104 /// \param[in] newConnection The new connection instance to track. 105 bool PushConnection(RakNet::Connection_RM3 *newConnection); 106 107 /// \brief Stop tracking a connection 108 /// \details On call, for each replica returned by GetReplicasCreatedByGuid(), QueryActionOnPopConnection() will be called. Depending on the return value, this may delete the corresponding replica.<BR> 109 /// If autoDestroy is true in the call to SetAutoManageConnections() (true by default) then this is called automatically when the connection is lost. In that case, the returned connection instance is deleted.<BR> 110 /// \param[in] guid of the connection to get. Passed to ReplicaManager3::AllocConnection() originally. 111 RakNet::Connection_RM3 * PopConnection(RakNetGUID guid); 112 113 /// \brief Adds a replicated object to the system. 114 /// \details Anytime you create a new object that derives from Replica3, and you want ReplicaManager3 to use it, pass it to Reference().<BR> 115 /// Remote systems already connected will potentially download this object the next time ReplicaManager3::Update() is called, which happens every time you call RakPeerInterface::Receive().<BR> 116 /// \param[in] replica3 The object to start tracking 117 void Reference(RakNet::Replica3 *replica3); 118 119 /// \brief Removes a replicated object from the system. 120 /// \details The object is not deallocated, it is up to the caller to do so.<BR> 121 /// This is called automatically from the destructor of Replica3, so you don't need to call it manually unless you want to stop tracking an object before it is destroyed. 122 /// \param[in] replica3 The object to stop tracking 123 void Dereference(RakNet::Replica3 *replica3); 124 125 /// \brief Removes multiple replicated objects from the system. 126 /// \details Same as Dereference(), but for a list of objects.<BR> 127 /// Useful with the lists returned by GetReplicasCreatedByGuid(), GetReplicasCreatedByMe(), or GetReferencedReplicaList().<BR> 128 /// \param[in] replicaListIn List of objects 129 void DereferenceList(DataStructures::Multilist<ML_STACK, Replica3*> &replicaListIn); 130 131 /// \brief Returns all objects originally created by a particular system 132 /// \details Originally created is defined as the value of Replica3::creatingSystemGUID, which is automatically assigned in ReplicaManager3::Reference().<BR> 133 /// You do not have to be directly connected to that system to get the objects originally created by that system.<BR> 134 /// \param[in] guid GUID of the system we are referring to. Originally passed as the \a guid parameter to ReplicaManager3::AllocConnection() 135 /// \param[out] List of Replica3 instances to be returned 136 void GetReplicasCreatedByGuid(RakNetGUID guid, DataStructures::Multilist<ML_STACK, Replica3*> &replicaListOut); 137 138 /// \brief Returns all objects originally created by your system 139 /// \details Calls GetReplicasCreatedByGuid() for your own system guid. 140 /// \param[out] List of Replica3 instances to be returned 141 void GetReplicasCreatedByMe(DataStructures::Multilist<ML_STACK, Replica3*> &replicaListOut); 142 143 /// \brief Returns the entire list of Replicas that we know about. 144 /// \details This is all Replica3 instances passed to Reference, as well as instances we downloaded and created via Connection_RM3::AllocReference() 145 /// \param[out] List of Replica3 instances to be returned 146 void GetReferencedReplicaList(DataStructures::Multilist<ML_STACK, Replica3*> &replicaListOut); 147 148 /// \brief Returns the number of replicas known about 149 /// \details Returns the size of the list that would be returned by GetReferencedReplicaList() 150 /// \return How many replica objects are in the list of replica objects 151 unsigned GetReplicaCount(void) const; 152 153 /// \brief Returns a replica by index 154 /// \details Returns one of the items in the list that would be returned by GetReferencedReplicaList() 155 /// \param[in] index An index, from 0 to GetReplicaCount()-1. 156 /// \return A Replica3 instance 157 Replica3 *GetReplicaAtIndex(unsigned index); 158 159 /// \brief Returns the number of connections 160 /// \details Returns the number of connections added with ReplicaManager3::PushConnection(), minus the number removed with ReplicaManager3::PopConnection() 161 /// \return The number of registered connections 162 DataStructures::DefaultIndexType GetConnectionCount(void) const; 163 164 /// \brief Returns a connection pointer previously added with PushConnection() 165 /// \param[in] index An index, from 0 to GetConnectionCount()-1. 166 /// \return A Connection_RM3 pointer 167 Connection_RM3* GetConnectionAtIndex(unsigned index) const; 168 169 /// \brief Returns a connection pointer previously added with PushConnection() 170 /// \param[in] sa The system address of the connection to return 171 /// \return A Connection_RM3 pointer, or 0 if not found 172 Connection_RM3* GetConnectionBySystemAddress(SystemAddress sa) const; 173 174 /// \brief Returns a connection pointer previously added with PushConnection.() 175 /// \param[in] guid The guid of the connection to return 176 /// \return A Connection_RM3 pointer, or 0 if not found 177 Connection_RM3* GetConnectionByGUID(RakNetGUID guid) const; 178 179 /// \param[in] Default ordering channel to use for object creation, destruction, and serializations 180 void SetDefaultOrderingChannel(char def); 181 182 /// \param[in] Default packet priority to use for object creation, destruction, and serializations 183 void SetDefaultPacketPriority(PacketPriority def); 184 185 /// \param[in] Default packet reliability to use for object creation, destruction, and serializations 186 void SetDefaultPacketReliability(PacketReliability def); 187 188 /// \details Every \a intervalMS milliseconds, Connection_RM3::OnAutoserializeInterval() will be called.<BR> 189 /// Defaults to 30.<BR> 190 /// Pass with 0 to disable.<BR> 191 /// If you want to control the update interval with more granularity, use the return values from Replica3::Serialize().<BR> 192 /// \param[in] intervalMS How frequently to autoserialize all objects. This controls the maximum number of game object updates per second. 193 void SetAutoSerializeInterval(RakNetTime intervalMS); 194 195 /// \brief Return the connections that we think have an instance of the specified Replica3 instance 196 /// \details This can be wrong, for example if that system locally deleted the outside the scope of ReplicaManager3, if QueryRemoteConstruction() returned false, or if DeserializeConstruction() returned false. 197 /// \param[in] replica The replica to check against. 198 /// \param[out] connectionsThatHaveConstructedThisReplica Populated with connection instances that we believe have \a replica allocated 199 void GetConnectionsThatHaveReplicaConstructed(Replica3 *replica, DataStructures::Multilist<ML_STACK, Connection_RM3*> &connectionsThatHaveConstructedThisReplica); 200 201 /// \brief Defines the unique instance of ReplicaManager3 if multiple instances are on the same instance of RakPeerInterface 202 /// \details ReplicaManager3 supports multiple instances of itself attached to the same instance of rakPeer, in case your game has multiple worlds.<BR> 203 /// Call SetWorldID with a different number for each instance.<BR> 204 /// The default worldID is 0.<BR> 205 /// To use multiple worlds, you will also need to call ReplicaManager3::SetNetworkIDManager() to have a different NetworkIDManager instance per world 206 void SetWorldID(unsigned char id); 207 208 /// \return Whatever was passed to SetWorldID(), or 0 if it was never called. 209 unsigned char GetWorldID(void) const; 210 211 /// \details Sets the networkIDManager instance that this plugin relys upon.<BR> 212 /// Uses whatever instance is attached to RakPeerInterface if unset.<BR> 213 /// To support multiple worlds, you should set it to a different manager for each instance of the plugin 214 /// \param[in] _networkIDManager The externally allocated NetworkIDManager instance for this plugin to use. 215 void SetNetworkIDManager(NetworkIDManager *_networkIDManager); 216 217 /// Returns what was passed to SetNetworkIDManager(), or the instance on RakPeerInterface if unset. 218 NetworkIDManager *GetNetworkIDManager(void) const; 219 220 /// \details Send a network command to destroy one or more Replica3 instances 221 /// Usually you won't need this, but use Replica3::BroadcastDestruction() instead. 222 /// The objects are unaffected locally 223 /// \param[in] replicaList List of Replica3 objects to tell other systems to destroy. 224 /// \param[in] exclusionAddress Which system to not send to. UNASSIGNED_SYSTEM_ADDRESS to send to all. 225 void BroadcastDestructionList(DataStructures::Multilist<ML_STACK, Replica3*> &replicaList, SystemAddress exclusionAddress); 226 227 /// \internal 228 /// \details Tell other systems that have this replica to destroy this replica.<BR> 229 /// You shouldn't need to call this, as it happens in the Replica3 destructor 230 void BroadcastDestruction(Replica3 *replica, SystemAddress exclusionAddress); 231 232 /// \internal 233 /// \details Frees internal lists.<BR> 234 /// Externally allocated pointers are not deallocated 235 void Clear(void); 236 237 /// \internal 238 PRO GetDefaultSendParameters(void) const; 239 240 protected: 241 virtual PluginReceiveResult OnReceive(Packet *packet); 242 virtual void Update(void); 243 virtual void OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ); 244 virtual void OnNewConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, bool isIncoming); 245 virtual void OnRakPeerShutdown(void); 246 virtual void OnDetach(void); 247 248 void OnConstructionExisting(unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset); 249 PluginReceiveResult OnConstruction(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset); 250 PluginReceiveResult OnSerialize(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, RakNetTime timestamp, unsigned char packetDataOffset); 251 PluginReceiveResult OnDownloadStarted(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset); 252 PluginReceiveResult OnDownloadComplete(Packet *packet, unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset); 253 void OnLocalConstructionRejected(unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset); 254 void OnLocalConstructionAccepted(unsigned char *packetData, int packetDataLength, RakNetGUID senderGuid, unsigned char packetDataOffset); 255 256 RakNet::Connection_RM3 * PopConnection(DataStructures::DefaultIndexType index); 257 Replica3* GetReplicaByNetworkID(NetworkID networkId); 258 DataStructures::DefaultIndexType ReferenceInternal(RakNet::Replica3 *replica3); 259 260 DataStructures::Multilist<ML_STACK, Connection_RM3*> connectionList; 261 DataStructures::Multilist<ML_STACK, Replica3*> userReplicaList; 262 263 PRO defaultSendParameters; 264 RakNetTime autoSerializeInterval; 265 RakNetTime lastAutoSerializeOccurance; 266 unsigned char worldId; 267 NetworkIDManager *networkIDManager; 268 bool autoCreateConnections, autoDestroyConnections; 269 270 friend class Connection_RM3; 271 }; 272 273 static const int RM3_NUM_OUTPUT_BITSTREAM_CHANNELS=8; 274 275 /// \ingroup REPLICA_MANAGER_GROUP3 276 struct LastSerializationResultBS 277 { 278 RakNet::BitStream bitStream[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS]; 279 bool indicesToSend[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS]; 280 }; 281 282 /// Represents the serialized data for an object the last time it was sent. Used by Connection_RM3::OnAutoserializeInterval() and Connection_RM3::SendSerializeIfChanged() 283 /// \ingroup REPLICA_MANAGER_GROUP3 284 struct LastSerializationResult 285 { 286 LastSerializationResult(); 287 ~LastSerializationResult(); 288 289 /// The replica instance we serialized 290 RakNet::Replica3 *replica; 291 //bool neverSerialize; 292 // bool isConstructed; 293 294 void AllocBS(void); 295 LastSerializationResultBS* lastSerializationResultBS; 296 }; 297 298 /// Parameters passed to Replica3::Serialize() 299 /// \ingroup REPLICA_MANAGER_GROUP3 300 struct SerializeParameters 301 { 302 /// Write your output for serialization here 303 /// If nothing is written, the serialization will not occur 304 /// Write to any or all of the NUM_OUTPUT_BITSTREAM_CHANNELS channels available. Channels can hold independent data 305 RakNet::BitStream outputBitstream[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS]; 306 307 /// Last bitstream we sent for this replica to this system. 308 /// Read, but DO NOT MODIFY 309 RakNet::BitStream* lastSentBitstream[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS]; 310 311 /// Set to non-zero to transmit a timestamp with this message. 312 /// Defaults to 0 313 /// Use RakNet::GetTime() for this 314 RakNetTime messageTimestamp; 315 316 /// Passed to RakPeerInterface::Send(). Defaults to ReplicaManager3::SetDefaultPacketPriority(). 317 /// Passed to RakPeerInterface::Send(). Defaults to ReplicaManager3::SetDefaultPacketReliability(). 318 /// Passed to RakPeerInterface::Send(). Defaults to ReplicaManager3::SetDefaultOrderingChannel(). 319 PRO pro[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS]; 320 321 /// Passed to RakPeerInterface::Send(). 322 RakNet::Connection_RM3 *destinationConnection; 323 324 /// For prior serializations this tick, for the same connection, how many bits have we written so far? 325 /// Use this to limit how many objects you send to update per-tick if desired 326 BitSize_t bitsWrittenSoFar; 327 328 /// When this object was last serialized to the connection 329 /// 0 means never 330 RakNetTime whenLastSerialized; 331 332 /// Current time, in milliseconds. 333 /// curTime - whenLastSerialized is how long it has been since this object was last sent 334 RakNetTime curTime; 335 }; 336 337 /// \ingroup REPLICA_MANAGER_GROUP3 338 struct DeserializeParameters 339 { 340 RakNet::BitStream serializationBitstream[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS]; 341 bool bitstreamWrittenTo[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS]; 342 RakNetTime timeStamp; 343 RakNet::Connection_RM3 *sourceConnection; 344 }; 345 346 /// \ingroup REPLICA_MANAGER_GROUP3 347 enum SendSerializeIfChangedResult 348 { 349 SSICR_SENT_DATA, 350 SSICR_DID_NOT_SEND_DATA, 351 SSICR_NEVER_SERIALIZE, 352 }; 353 354 /// \brief Each remote system is represented by Connection_RM3. Used to allocate Replica3 and track which instances have been allocated 355 /// \details Important function: AllocReplica() - must be overridden to create an object given an identifier for that object, which you define for all objects in your game 356 /// \ingroup REPLICA_MANAGER_GROUP3 357 class RAK_DLL_EXPORT Connection_RM3 358 { 359 public: 360 Connection_RM3(SystemAddress _systemAddress, RakNetGUID _guid); 361 virtual ~Connection_RM3(); 362 363 /// \brief Class factory to create a Replica3 instance, given a user-defined identifier 364 /// \details Identifier is returned by Replica3::WriteAllocationID() for what type of class to create.<BR> 365 /// This is called when you download a replica from another system.<BR> 366 /// See Replica3::Dealloc for the corresponding destruction message.<BR> 367 /// Return 0 if unable to create the intended object. Note, in that case the other system will still think we have the object and will try to serialize object updates to us. Generally, you should not send objects the other system cannot create.<BR> 368 /// \sa Replica3::WriteAllocationID(). 369 /// Sample implementation:<BR> 370 /// {RakNet::RakString typeName; allocationIdBitstream->Read(typeName); if (typeName=="Soldier") return new Soldier; return 0;}<BR> 371 /// \param[in] allocationIdBitstream user-defined bitstream uniquely identifying a game object type 372 /// \param[in] replicaManager3 Instance of ReplicaManager3 that controls this connection 373 /// \return The new replica instance 374 virtual Replica3 *AllocReplica(RakNet::BitStream *allocationIdBitstream, ReplicaManager3 *replicaManager3)=0; 375 376 /// \brief Get list of all replicas that are constructed for this connection 377 /// \param[out] objectsTheyDoHave Destination list. Returned in sorted ascending order, sorted on the value of the Replica3 pointer. 378 virtual void GetConstructedReplicas(DataStructures::Multilist<ML_STACK, Replica3*> &objectsTheyDoHave); 379 380 /// Returns true if we think this remote connection has this replica constructed 381 /// \param[in] replica3 Which replica we are querying 382 /// \return True if constructed, false othewise 383 bool HasReplicaConstructed(RakNet::Replica3 *replica); 384 385 /// When a new connection connects, before sending any objects, SerializeOnDownloadStarted() is called 386 /// \param[out] bitStream Passed to DeserializeOnDownloadStarted() SerializeOnDownloadStarted(RakNet::BitStream * bitStream)387 virtual void SerializeOnDownloadStarted(RakNet::BitStream *bitStream) {(void) bitStream;} 388 389 /// Receives whatever was written in SerializeOnDownloadStarted() 390 /// \param[in] bitStream Written in SerializeOnDownloadStarted() DeserializeOnDownloadStarted(RakNet::BitStream * bitStream)391 virtual void DeserializeOnDownloadStarted(RakNet::BitStream *bitStream) {(void) bitStream;} 392 393 /// When a new connection connects, after constructing and serialization all objects, SerializeOnDownloadComplete() is called 394 /// \param[out] bitStream Passed to DeserializeOnDownloadComplete() SerializeOnDownloadComplete(RakNet::BitStream * bitStream)395 virtual void SerializeOnDownloadComplete(RakNet::BitStream *bitStream) {(void) bitStream;} 396 397 /// Receives whatever was written in DeserializeOnDownloadComplete() 398 /// \param[in] bitStream Written in SerializeOnDownloadComplete() DeserializeOnDownloadComplete(RakNet::BitStream * bitStream)399 virtual void DeserializeOnDownloadComplete(RakNet::BitStream *bitStream) {(void) bitStream;} 400 401 /// \return The system address passed to the constructor of this object GetSystemAddress(void)402 SystemAddress GetSystemAddress(void) const {return systemAddress;} 403 404 /// \return Returns the RakNetGUID passed to the constructor of this object GetRakNetGUID(void)405 RakNetGUID GetRakNetGUID(void) const {return guid;} 406 407 /// List of enumerations for how to get the list of valid objects for other systems 408 enum ConstructionMode 409 { 410 /// For every object that does not exist on the remote system, call Replica3::QueryConstruction() every tick. 411 /// Do not call Replica3::QueryDestruction() 412 /// Do not call Connection_RM3::QueryReplicaList() 413 QUERY_REPLICA_FOR_CONSTRUCTION, 414 415 /// For every object that does not exist on the remote system, call Replica3::QueryConstruction() every tick. Based on the call, the object may be sent to the other system. 416 /// For every object that does exist on the remote system, call Replica3::QueryDestruction() every tick. Based on the call, the object may be deleted on the other system. 417 /// Do not call Connection_RM3::QueryReplicaList() 418 QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION, 419 420 /// Do not call Replica3::QueryConstruction() or Replica3::QueryDestruction() 421 /// Call Connection_RM3::QueryReplicaList() to determine which objects exist on remote systems 422 /// This can be faster than QUERY_REPLICA_FOR_CONSTRUCTION and QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION for large worlds 423 /// See GridSectorizer.h under /Source for code that can help with this 424 QUERY_CONNECTION_FOR_REPLICA_LIST 425 }; 426 427 /// \brief Return whether or not downloads to our system should all be processed the same tick (call to RakPeer::Receive() ) 428 /// \details Normally the system will send ID_REPLICA_MANAGER_DOWNLOAD_STARTED, ID_REPLICA_MANAGER_CONSTRUCTION for all downloaded objects, 429 /// ID_REPLICA_MANAGER_SERIALIZE for each downloaded object, and lastly ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE. 430 /// This enables the application to show a downloading splash screen on ID_REPLICA_MANAGER_DOWNLOAD_STARTED, a progress bar, and to close the splash screen and activate all objects on ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE 431 /// However, if the application was not set up for this then it would result in incomplete objects spread out over time, and cause problems 432 /// If you return true from QueryGroupDownloadMessages(), then these messages will be returned all in one tick, returned only when the download is complete 433 /// \note ID_REPLICA_MANAGER_DOWNLOAD_STARTED calls the callback DeserializeOnDownloadStarted() 434 /// \note ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE calls the callback DeserializeOnDownloadComplete() QueryGroupDownloadMessages(void)435 virtual bool QueryGroupDownloadMessages(void) const {return false;} 436 437 /// \brief Queries how to get the list of objects that exist on remote systems 438 /// \details The default of calling QueryConstruction for every known object is easy to use, but not efficient, especially for large worlds where many objects are outside of the player's circle of influence.<BR> 439 /// QueryDestruction is also not necessarily useful or efficient, as object destruction tends to happen in known cases, and can be accomplished by calling Replica3::BroadcastDestruction() 440 /// QueryConstructionMode() allows you to specify more efficient algorithms than the default when overriden. 441 /// \return How to get the list of objects that exist on the remote system. You should always return the same value for a given connection QueryConstructionMode(void)442 virtual ConstructionMode QueryConstructionMode(void) const {return QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION;} 443 444 /// \brief Callback used when QueryConstructionMode() returns QUERY_CONNECTION_FOR_REPLICA_LIST 445 /// \details This advantage of this callback is if that there are many objects that a particular connection does not have, then we do not have to iterate through those 446 /// objects calling QueryConstruction() for each of them.<BR> 447 ///<BR> 448 /// The following code uses a sorted merge sort to quickly find new and deleted objects, given a list of objects we know should exist.<BR> 449 ///<BR> 450 /// DataStructures::Multilist<ML_STACK, Replica3*, Replica3*> objectsTheyShouldHave; // You have to fill in this list<BR> 451 /// DataStructures::Multilist<ML_STACK, Replica3*, Replica3*> objectsTheyCurrentlyHave,objectsTheyStillHave,existingReplicasToDestro,newReplicasToCreatey;<BR> 452 /// GetConstructedReplicas(objectsTheyCurrentlyHave);<BR> 453 /// DataStructures::Multilist::FindIntersection(objectsTheyCurrentlyHave, objectsTheyShouldHave, objectsTheyStillHave, existingReplicasToDestroy, newReplicasToCreate);<BR> 454 ///<BR> 455 /// See GridSectorizer in the Source directory as a method to find all objects within a certain radius in a fast way.<BR> 456 ///<BR> 457 /// \param[out] newReplicasToCreate Anything in this list will be created on the remote system 458 /// \param[out] existingReplicasToDestroy Anything in this list will be destroyed on the remote system QueryReplicaList(DataStructures::Multilist<ML_STACK,Replica3 *,Replica3 * > newReplicasToCreate,DataStructures::Multilist<ML_STACK,Replica3 *,Replica3 * > existingReplicasToDestroy)459 virtual void QueryReplicaList( 460 DataStructures::Multilist<ML_STACK, Replica3*, Replica3*> newReplicasToCreate, 461 DataStructures::Multilist<ML_STACK, Replica3*, Replica3*> existingReplicasToDestroy) {} 462 463 /// \internal This is used internally - however, you can also call it manually to send a data update for a remote replica.<BR> 464 /// \brief Sends over a serialization update for \a replica.<BR> 465 /// NetworkID::GetNetworkID() is written automatically, serializationData is the object data.<BR> 466 /// \param[in] replica Which replica to serialize 467 /// \param[in] serializationData Serialized object data 468 /// \param[in] timestamp 0 means no timestamp. Otherwise message is prepended with ID_TIMESTAMP 469 /// \param[in] sendParameters Parameters on how to send 470 /// \param[in] rakPeer Instance of RakPeerInterface to send on 471 /// \param[in] worldId Which world, see ReplicaManager3::SetWorldID() 472 virtual SendSerializeIfChangedResult SendSerialize(RakNet::Replica3 *replica, bool indicesToSend[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS], RakNet::BitStream serializationData[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS], RakNetTime timestamp, PRO sendParameters[RM3_NUM_OUTPUT_BITSTREAM_CHANNELS], RakPeerInterface *rakPeer, unsigned char worldId); 473 474 /// \internal 475 /// \details Calls Connection_RM3::SendSerialize() if Replica3::Serialize() returns a different result than what is contained in \a lastSerializationResult.<BR> 476 /// Used by autoserialization in Connection_RM3::OnAutoserializeInterval() 477 /// \param[in] queryToSerializeIndex Index into queryToSerializeReplicaList for whichever replica this is 478 /// \param[in] sp Controlling parameters over the serialization 479 /// \param[in] rakPeer Instance of RakPeerInterface to send on 480 /// \param[in] worldId Which world, see ReplicaManager3::SetWorldID() 481 virtual SendSerializeIfChangedResult SendSerializeIfChanged(DataStructures::DefaultIndexType queryToSerializeIndex, SerializeParameters *sp, RakPeerInterface *rakPeer, unsigned char worldId, ReplicaManager3 *replicaManager); 482 483 /// \internal 484 /// \brief Given a list of objects that were created and destroyed, serialize and send them to another system. 485 /// \param[in] newObjects Objects to serialize construction 486 /// \param[in] deletedObjects Objects to serialize destruction 487 /// \param[in] sendParameters Controlling parameters over the serialization 488 /// \param[in] rakPeer Instance of RakPeerInterface to send on 489 /// \param[in] worldId Which world, see ReplicaManager3::SetWorldID() 490 virtual void SendConstruction(DataStructures::Multilist<ML_STACK, Replica3*, Replica3*> &newObjects, DataStructures::Multilist<ML_STACK, Replica3*, Replica3*> &deletedObjects, PRO sendParameters, RakPeerInterface *rakPeer, unsigned char worldId); 491 492 /// \internal 493 /// Remove from \a newObjectsIn objects that already exist and save to \a newObjectsOut 494 /// Remove from \a deletedObjectsIn objects that do not exist, and save to \a deletedObjectsOut 495 void CullUniqueNewAndDeletedObjects(DataStructures::Multilist<ML_STACK, Replica3*> &newObjectsIn, 496 DataStructures::Multilist<ML_STACK, Replica3*> &deletedObjectsIn, 497 DataStructures::Multilist<ML_STACK, Replica3*> &newObjectsOut, 498 DataStructures::Multilist<ML_STACK, Replica3*> &deletedObjectsOut); 499 500 /// \internal 501 void SendValidation(RakPeerInterface *rakPeer, unsigned char worldId); 502 503 /// \internal 504 void AutoConstructByQuery(ReplicaManager3 *replicaManager3); 505 506 507 // Internal - does the other system have this connection too? Validated means we can now use it 508 bool isValidated; 509 // Internal - Used to see if we should send download started 510 bool isFirstConstruction; 511 512 protected: 513 514 SystemAddress systemAddress; 515 RakNetGUID guid; 516 517 /* 518 Operations: 519 520 Locally reference a new replica: 521 Add to queryToConstructReplicaList for all objects 522 523 Add all objects to queryToConstructReplicaList 524 525 Download: 526 Add to constructedReplicaList for connection that send the object to us 527 Add to queryToSerializeReplicaList for connection that send the object to us 528 Add to queryToConstructReplicaList for all other connections 529 530 Never construct for this connection: 531 Remove from queryToConstructReplicaList 532 533 Construct to this connection 534 Remove from queryToConstructReplicaList 535 Add to constructedReplicaList for this connection 536 Add to queryToSerializeReplicaList for this connection 537 538 Serialize: 539 Iterate through queryToSerializeReplicaList 540 541 Never serialize for this connection 542 Remove from queryToSerializeReplicaList 543 544 Reference (this system has this object already) 545 Remove from queryToConstructReplicaList 546 Add to constructedReplicaList for this connection 547 Add to queryToSerializeReplicaList for this connection 548 549 Downloaded an existing object 550 if replica is in queryToConstructReplicaList, OnConstructToThisConnection() 551 else ignore 552 553 Send destruction from query 554 Remove from queryToDestructReplicaList 555 Remove from queryToSerializeReplicaList 556 Remove from constructedReplicaList 557 Add to queryToConstructReplicaList 558 559 Do not query destruction again 560 Remove from queryToDestructReplicaList 561 */ 562 void OnLocalReference(Replica3* replica3, ReplicaManager3 *replicaManager); 563 void OnDereference(Replica3* replica3, ReplicaManager3 *replicaManager); 564 void OnDownloadFromThisSystem(Replica3* replica3, ReplicaManager3 *replicaManager); 565 void OnDownloadFromOtherSystem(Replica3* replica3, ReplicaManager3 *replicaManager); 566 void OnNeverConstruct(DataStructures::DefaultIndexType queryToConstructIdx, ReplicaManager3 *replicaManager); 567 void OnConstructToThisConnection(DataStructures::DefaultIndexType queryToConstructIdx, ReplicaManager3 *replicaManager); 568 void OnConstructToThisConnection(Replica3 *replica, ReplicaManager3 *replicaManager); 569 void OnNeverSerialize(DataStructures::DefaultIndexType queryToSerializeIndex, ReplicaManager3 *replicaManager); 570 void OnReplicaAlreadyExists(DataStructures::DefaultIndexType queryToConstructIdx, ReplicaManager3 *replicaManager); 571 void OnDownloadExisting(Replica3* replica3, ReplicaManager3 *replicaManager); 572 void OnSendDestructionFromQuery(DataStructures::DefaultIndexType queryToDestructIdx, ReplicaManager3 *replicaManager); 573 void OnDoNotQueryDestruction(DataStructures::DefaultIndexType queryToDestructIdx, ReplicaManager3 *replicaManager); 574 void ValidateLists(ReplicaManager3 *replicaManager) const; 575 void SendSerializeHeader(RakNet::Replica3 *replica, RakNetTime timestamp, RakNet::BitStream *bs, unsigned char worldId); 576 577 // The list of objects that our local system and this remote system both have 578 // Either we sent this object to them, or they sent this object to us 579 // A given Replica can be either in queryToConstructReplicaList or constructedReplicaList but not both at the same time 580 DataStructures::Multilist<ML_ORDERED_LIST, LastSerializationResult*, Replica3*> constructedReplicaList; 581 582 // Objects that we have, but this system does not, and we will query each tick to see if it should be sent to them 583 // If we do send it to them, the replica is moved to constructedReplicaList 584 // A given Replica can be either in queryToConstructReplicaList or constructedReplicaList but not both at the same time 585 DataStructures::Multilist<ML_STACK, LastSerializationResult*, Replica3*> queryToConstructReplicaList; 586 587 // Objects that this system has constructed are added at the same time to queryToSerializeReplicaList 588 // This list is used to serialize all objects that this system has to this connection 589 DataStructures::Multilist<ML_STACK, LastSerializationResult*, Replica3*> queryToSerializeReplicaList; 590 591 // Objects that are constructed on this system are also queried if they should be destroyed to this system 592 DataStructures::Multilist<ML_STACK, LastSerializationResult*, Replica3*> queryToDestructReplicaList; 593 594 // Working lists 595 DataStructures::Multilist<ML_STACK, Replica3*, Replica3*> constructedReplicasCulled, destroyedReplicasCulled; 596 597 // This is used if QueryGroupDownloadMessages() returns true when ID_REPLICA_MANAGER_DOWNLOAD_STARTED arrives 598 // Packets will be gathered and not returned until ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE arrives 599 bool groupConstructionAndSerialize; 600 DataStructures::Multilist<ML_QUEUE, Packet*, Packet*> downloadGroup; 601 void ClearDownloadGroup(RakPeerInterface *rakPeerInterface); 602 603 friend class ReplicaManager3; 604 private: Connection_RM3()605 Connection_RM3() {}; 606 607 ConstructionMode constructionMode; 608 }; 609 610 /// \brief Return codes for Connection_RM3::GetConstructionState() and Replica3::QueryConstruction() 611 /// \details Indicates what state the object should be in for the remote system 612 /// \ingroup REPLICA_MANAGER_GROUP3 613 enum RM3ConstructionState 614 { 615 /// This object should exist on the remote system. Send a construction message if necessary 616 /// If the NetworkID is already in use, it will not do anything 617 /// If it is not in use, it will create the object, and then call DeserializeConstruction 618 RM3CS_SEND_CONSTRUCTION, 619 620 /// This object should exist on the remote system. 621 /// The other system already has the object, and the object will never be deleted. 622 /// This is true of objects that are loaded with the level, for example. 623 /// Treat it as if it existed, without sending a construction message. 624 /// Will call SerializeConstructionExisting() to the object on the remote system 625 RM3CS_ALREADY_EXISTS_REMOTELY, 626 627 /// This object will never be sent to this system 628 RM3CS_NEVER_CONSTRUCT, 629 630 /// Don't do anything this tick. Will query again next tick 631 RM3CS_NO_ACTION, 632 }; 633 634 /// If this object already exists for this system, should it be removed? 635 /// \ingroup REPLICA_MANAGER_GROUP3 636 enum RM3DestructionState 637 { 638 /// This object should not exist on the remote system. Send a destruction message if necessary. 639 RM3DS_SEND_DESTRUCTION, 640 641 /// This object will never be destroyed by a per-tick query. Don't call again 642 RM3DS_DO_NOT_QUERY_DESTRUCTION, 643 644 /// Don't do anything this tick. Will query again next tick 645 RM3DS_NO_ACTION, 646 }; 647 648 /// Return codes when constructing an object 649 /// \ingroup REPLICA_MANAGER_GROUP3 650 enum RM3SerializationResult 651 { 652 /// This object serializes identically no matter who we send to 653 /// We also send it to every connection (broadcast). 654 /// Efficient for memory, speed, and bandwidth but only if the object is always broadcast identically. 655 RM3SR_BROADCAST_IDENTICALLY, 656 657 /// Same as RM3SR_BROADCAST_IDENTICALLY, but assume the object needs to be serialized, do not check with a memcmp 658 /// Assume the object changed, and serialize it 659 /// Use this if you know exactly when your object needs to change. Can be faster than RM3SR_BROADCAST_IDENTICALLY. 660 /// An example of this is if every member variable has an accessor, changing a member sets a flag, and you check that flag in Replica3::QuerySerialization() 661 /// The opposite of this is RM3SR_DO_NOT_SERIALIZE, in case the object did not change 662 RM3SR_BROADCAST_IDENTICALLY_FORCE_SERIALIZATION, 663 664 /// Either this object serializes differently depending on who we send to or we send it to some systems and not others. 665 /// Inefficient for memory and speed, but efficient for bandwidth 666 /// However, if you don't know what to return, return this 667 RM3SR_SERIALIZED_UNIQUELY, 668 669 /// Do not compare against last sent value. Just send even if the data is the same as the last tick 670 /// If the data is always changing anyway, or you want to send unreliably, this is a good method of serialization 671 /// Can send unique data per connection if desired. If same data is sent to all connections, use RM3SR_SERIALIZED_ALWAYS_IDENTICALLY for even better performance 672 /// Efficient for memory and speed, but not necessarily bandwidth 673 RM3SR_SERIALIZED_ALWAYS, 674 675 /// Even faster than RM3SR_SERIALIZED_ALWAYS 676 /// Serialize() will only be called for the first system. The remaining systems will get the same data as the first system. 677 RM3SR_SERIALIZED_ALWAYS_IDENTICALLY, 678 679 /// Do not serialize this object this tick, for this connection. Will query again next autoserialize timer 680 RM3SR_DO_NOT_SERIALIZE, 681 682 /// Never serialize this object for this connection 683 /// Useful for objects that are downloaded, and never change again 684 /// Efficient 685 RM3SR_NEVER_SERIALIZE_FOR_THIS_CONNECTION, 686 }; 687 688 /// First pass at topology to see if an object should be serialized 689 /// \ingroup REPLICA_MANAGER_GROUP3 690 enum RM3QuerySerializationResult 691 { 692 /// Call Serialize() to see if this object should be serializable for this connection 693 RM3QSR_CALL_SERIALIZE, 694 /// Do not call Serialize() this tick to see if this object should be serializable for this connection 695 RM3QSR_DO_NOT_CALL_SERIALIZE, 696 /// Never call Serialize() for this object and connection. This system will not serialize this object for this topology 697 RM3QSR_NEVER_CALL_SERIALIZE, 698 }; 699 700 /// \ingroup REPLICA_MANAGER_GROUP3 701 enum RM3ActionOnPopConnection 702 { 703 RM3AOPC_DO_NOTHING, 704 RM3AOPC_DELETE_REPLICA, 705 RM3AOPC_DELETE_REPLICA_AND_BROADCAST_DESTRUCTION, 706 }; 707 708 709 /// \brief Base class for your replicated objects for the ReplicaManager3 system. 710 /// \details To use, derive your class, or a member of your class, from Replica3.<BR> 711 /// \ingroup REPLICA_MANAGER_GROUP3 712 class RAK_DLL_EXPORT Replica3 : public NetworkIDObject 713 { 714 public: 715 Replica3(); 716 717 /// Before deleting a local instance of Replica3, call Replica3::BroadcastDestruction() for the deletion notification to go out on the network. 718 /// It is not necessary to call ReplicaManager3::Dereference(), as this happens automatically in the destructor 719 virtual ~Replica3(); 720 721 /// \brief Write a unique identifer that can be read on a remote system to create an object of this same class. 722 /// \details The value written to \a allocationIdBitstream will be passed to Connection_RM3::AllocReplica().<BR> 723 /// Sample implementation:<BR> 724 /// {allocationIdBitstream->Write(RakNet::RakString("Soldier");}<BR> 725 /// \param[out] allocationIdBitstream Bitstream for the user to write to, to identify this class 726 virtual void WriteAllocationID(RakNet::BitStream *allocationIdBitstream) const=0; 727 728 /// \brief Ask if this object, which does not exist on \a destinationConnection should (now) be sent to that system. 729 /// \details If ReplicaManager3::QueryConstructionMode() returns QUERY_CONNECTION_FOR_REPLICA_LIST or QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION (default), 730 /// then QueyrConstruction() is called once per tick from ReplicaManager3::Update() to determine if an object should exist on a given system.<BR> 731 /// Based on the return value, a network message may be sent to the other system to create the object.<BR> 732 /// If QueryConstructionMode() is overriden to return QUERY_CONNECTION_FOR_REPLICA_LIST, this function is unused.<BR> 733 /// \note Defaults are provided: QueryConstruction_PeerToPeer(), QueryConstruction_ServerConstruction(), QueryConstruction_ClientConstruction(). Return one of these functions for a working default for the relevant topology. 734 /// \param[in] destinationConnection Which system we will send to 735 /// \param[in] replicaManager3 Plugin instance for this Replica3 736 /// \return What action to take 737 virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3)=0; 738 739 /// \brief Ask if this object, which does exist on \a destinationConnection should be removed from the remote system 740 /// \details If ReplicaManager3::QueryConstructionMode() returns QUERY_REPLICA_FOR_CONSTRUCTION_AND_DESTRUCTION (default), 741 /// then QueryDestruction() is called once per tick from ReplicaManager3::Update() to determine if an object that exists on a remote system should be destroyed for a given system.<BR> 742 /// Based on the return value, a network message may be sent to the other system to destroy the object.<BR> 743 /// Note that you can also destroy objects with BroadcastDestruction(), so this function is not useful unless you plan to delete objects for only a particular connection.<BR> 744 /// If QueryConstructionMode() is overriden to return QUERY_CONNECTION_FOR_REPLICA_LIST, this function is unused.<BR> 745 /// \param[in] destinationConnection Which system we will send to 746 /// \param[in] replicaManager3 Plugin instance for this Replica3 747 /// \return What action to take. Only RM3CS_SEND_DESTRUCTION does anything at this time. QueryDestruction(RakNet::Connection_RM3 * destinationConnection,ReplicaManager3 * replicaManager3)748 virtual RM3DestructionState QueryDestruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3) {(void) destinationConnection; (void) replicaManager3; return RM3DS_DO_NOT_QUERY_DESTRUCTION;} 749 750 /// \brief We're about to call DeserializeConstruction() on this Replica3. If QueryRemoteConstruction() returns false, this object is deleted instead. 751 /// \details By default, QueryRemoteConstruction_ServerConstruction() does not allow clients to create objects. The client will get Replica3::DeserializeConstructionRequestRejected().<BR> 752 /// If you want the client to be able to potentially create objects for client/server, override accordingly.<BR> 753 /// Other variants of QueryRemoteConstruction_* just return true. 754 /// \note Defaults are provided: QueryRemoteConstruction_PeerToPeer(), QueryRemoteConstruction_ServerConstruction(), QueryRemoteConstruction_ClientConstruction(). Return one of these functions for a working default for the relevant topology. 755 /// \param[in] sourceConnection Which system sent us the object creation request message. 756 /// \return True to allow the object to pass onto DeserializeConstruction() (where it may also be rejected), false to immediately reject the remote construction request 757 virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection)=0; 758 759 /// \brief Write data to be sent only when the object is constructed on a remote system. 760 /// \details SerializeConstruction is used to write out data that you need to create this object in the context of your game, such as health, score, name. Use it for data you only need to send when the object is created.<BR> 761 /// After SerializeConstruction() is called, Serialize() will be called immediately thereafter. However, they are sent in different messages, so Serialize() may arrive a later frame than SerializeConstruction() 762 /// For that reason, the object should be valid after a call to DeserializeConstruction() for at least a short time.<BR> 763 /// \note The object's NetworkID and allocation id are handled by the system automatically, you do not need to write these values to \a constructionBitstream 764 /// \param[out] constructionBitstream Destination bitstream to write your data to 765 /// \param[in] destinationConnection System that will receive this network message. 766 virtual void SerializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *destinationConnection)=0; 767 768 /// \brief Read data written by Replica3::SerializeConstruction() 769 /// \details Reads whatever data was written to \a constructionBitstream in Replica3::SerializeConstruction() 770 /// \param[out] constructionBitstream Bitstream written to in Replica3::SerializeConstruction() 771 /// \param[in] sourceConnection System that sent us this network message. 772 /// \return true to accept construction of the object. false to reject, in which case the object will be deleted via Replica3::DeallocReplica() 773 virtual bool DeserializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *sourceConnection)=0; 774 775 /// Same as SerializeConstruction(), but for an object that already exists on the remote system. 776 /// Used if you return RM3CS_ALREADY_EXISTS_REMOTELY from QueryConstruction SerializeConstructionExisting(RakNet::BitStream * constructionBitstream,RakNet::Connection_RM3 * destinationConnection)777 virtual void SerializeConstructionExisting(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *destinationConnection) {(void) constructionBitstream; (void) destinationConnection;}; 778 779 /// Same as DeserializeConstruction(), but for an object that already exists on the remote system. 780 /// Used if you return RM3CS_ALREADY_EXISTS_REMOTELY from QueryConstruction DeserializeConstructionExisting(RakNet::BitStream * constructionBitstream,RakNet::Connection_RM3 * sourceConnection)781 virtual void DeserializeConstructionExisting(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *sourceConnection) {(void) constructionBitstream; (void) sourceConnection;}; 782 783 /// \brief Write extra data to send with the object deletion event, if desired 784 /// \details Replica3::SerializeDestruction() will be called to write any object destruction specific data you want to send with this event. 785 /// \a destructionBitstream can be read in DeserializeDestruction() 786 /// \param[out] destructionBitstream Bitstream for you to write to 787 /// \param[in] destinationConnection System that will receive this network message. 788 virtual void SerializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *destinationConnection)=0; 789 790 /// \brief Read data written by Replica3::SerializeDestruction() 791 /// \details Return true to delete the object. BroadcastDestruction() will be called automatically, followed by ReplicaManager3::Dereference.<BR> 792 /// Return false to not delete it. If you delete it at a later point, you are responsible for calling BroadcastDestruction() yourself. 793 virtual bool DeserializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *sourceConnection)=0; 794 795 /// \brief The system is asking what to do with this replica when the connection is dropped 796 /// \details Return QueryActionOnPopConnection_Client, QueryActionOnPopConnection_Server, or QueryActionOnPopConnection_PeerToPeer 797 virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const=0; 798 799 /// Notification called for each of our replicas when a connection is popped OnPoppedConnection(RakNet::Connection_RM3 * droppedConnection)800 void OnPoppedConnection(RakNet::Connection_RM3 *droppedConnection) {(void) droppedConnection;} 801 802 /// \brief Override with {delete this;} 803 /// \details 804 /// <OL> 805 /// <LI>Got a remote message to delete this object which passed DeserializeDestruction(), OR 806 /// <LI>ReplicaManager3::SetAutoManageConnections() was called autoDestroy true (which is the default setting), and a remote system that owns this object disconnected) OR 807 /// <\OL> 808 /// <BR> 809 /// Override with {delete this;} to actually delete the object (and any other processing you wish).<BR> 810 /// If you don't want to delete the object, just do nothing, however, the system will not know this so you are responsible for deleting it yoruself later.<BR> 811 /// destructionBitstream may be 0 if the object was deleted locally 812 virtual void DeallocReplica(RakNet::Connection_RM3 *sourceConnection)=0; 813 814 /// \brief Implement with QuerySerialization_ClientSerializable(), QuerySerialization_ServerSerializable(), or QuerySerialization_PeerToPeer() 815 /// \details QuerySerialization() is a first pass query to check if a given object should serializable to a given system. The intent is that the user implements with one of the defaults for client, server, or peer to peer.<BR> 816 /// Without this function, a careless implementation would serialize an object anytime it changed to all systems. This would give you feedback loops as the sender gets the same message back from the recipient it just sent to.<BR> 817 /// If more than one system can serialize the same object then you will need to override to return true, and control the serialization result from Replica3::Serialize(). Be careful not to send back the same data to the system that just sent to you! 818 /// \return True to allow calling Replica3::Serialize() for this connection, false to not call. 819 virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection)=0; 820 821 /// \brief Called for each replica owned by the user, once per Serialization tick, before Serialize() is called. 822 /// If you want to do some kind of operation on the Replica objects that you own, just before Serialization(), then overload this function OnUserReplicaPreSerializeTick(void)823 virtual void OnUserReplicaPreSerializeTick(void) {} 824 825 /// \brief Serialize our class to a bitstream 826 /// \details User should implement this function to write the contents of this class to SerializationParamters::serializationBitstream.<BR> 827 /// If data only needs to be written once, you can write it to SerializeConstruction() instead for efficiency.<BR> 828 /// Transmitted over the network if it changed from the last time we called Serialize().<BR> 829 /// Called every time the time interval to ReplicaManager3::SetAutoSerializeInterval() elapses and ReplicaManager3::Update is subsequently called. 830 /// \param[in/out] serializeParameters Parameters controlling the serialization, including destination bitstream to write to 831 /// \return Whether to serialize, and if so, how to optimize the results 832 virtual RM3SerializationResult Serialize(RakNet::SerializeParameters *serializeParameters)=0; 833 834 /// \brief Called when the class is actually transmitted via Serialize() 835 /// \details Use to track how much bandwidth this class it taking OnSerializeTransmission(RakNet::BitStream * bitStream,SystemAddress systemAddress)836 virtual void OnSerializeTransmission(RakNet::BitStream *bitStream, SystemAddress systemAddress) {(void) bitStream; (void) systemAddress; } 837 838 /// \brief Read what was written in Serialize() 839 /// \details Reads the contents of the class from SerializationParamters::serializationBitstream.<BR> 840 /// Called whenever Serialize() is called with different data from the last send. 841 /// \param[in] serializationBitstream Bitstream passed to Serialize() 842 /// \param[in] timeStamp 0 if unused, else contains the time the message originated on the remote system 843 /// \param[in] sourceConnection Which system sent to us 844 virtual void Deserialize(RakNet::DeserializeParameters *deserializeParameters)=0; 845 846 /// \brief Write data for when an object creation request is accepted 847 /// \details If a system creates an object and NetworkIDManager::IsNetworkIDAuthority() returns false, then the object cannot locally assign NetworkID, which means that the object cannot be used over the network.<BR> 848 /// The object will call SerializeConstruction() and sent over the network with a temporary id.<BR> 849 /// When the object is created by a system where NetworkIDManager::IsNetworkIDAuthority() returns true, SerializeConstructionRequestAccepted() will be called with the opportunity to write additional data if desired.<BR> 850 /// The sender will then receive serializationBitstream in DeserializeConstructionRequestAccepted(), after the NetworkID has been assigned.<BR> 851 /// This is not pure virtual, because it is not often used and is not necessary for the system to work. 852 /// \param[out] serializationBitstream Destination bitstream to write to 853 /// \param[in] requestingConnection Which system sent to us SerializeConstructionRequestAccepted(RakNet::BitStream * serializationBitstream,RakNet::Connection_RM3 * requestingConnection)854 virtual void SerializeConstructionRequestAccepted(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *requestingConnection) {(void) serializationBitstream; (void) requestingConnection;} 855 856 /// Receive the result of SerializeConstructionRequestAccepted 857 /// \param[in] serializationBitstream Source bitstream to read from 858 /// \param[in] acceptingConnection Which system sent to us DeserializeConstructionRequestAccepted(RakNet::BitStream * serializationBitstream,RakNet::Connection_RM3 * acceptingConnection)859 virtual void DeserializeConstructionRequestAccepted(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *acceptingConnection) {(void) serializationBitstream; (void) acceptingConnection;} 860 861 /// Same as SerializeConstructionRequestAccepted(), but the client construction request was rejected 862 /// \param[out] serializationBitstream Destination bitstream to write to 863 /// \param[in] requestingConnection Which system sent to us SerializeConstructionRequestRejected(RakNet::BitStream * serializationBitstream,RakNet::Connection_RM3 * requestingConnection)864 virtual void SerializeConstructionRequestRejected(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *requestingConnection) {(void) serializationBitstream; (void) requestingConnection;} 865 866 /// Receive the result of DeserializeConstructionRequestRejected 867 /// \param[in] serializationBitstream Source bitstream to read from 868 /// \param[in] requestingConnection Which system sent to us DeserializeConstructionRequestRejected(RakNet::BitStream * serializationBitstream,RakNet::Connection_RM3 * rejectingConnection)869 virtual void DeserializeConstructionRequestRejected(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *rejectingConnection) {(void) serializationBitstream; (void) rejectingConnection;} 870 871 /// Called after DeserializeConstruction completes for the object successfully.<BR> 872 /// Override to trigger some sort of event when you know the object has completed deserialization. 873 /// \param[in] sourceConnection System that sent us this network message. PostDeserializeConstruction(RakNet::Connection_RM3 * sourceConnection)874 virtual void PostDeserializeConstruction(RakNet::Connection_RM3 *sourceConnection) {(void) sourceConnection;} 875 876 /// Called after DeserializeDestruction completes for the object successfully, but obviously before the object is deleted.<BR> 877 /// Override to trigger some sort of event when you know the object has completed destruction. 878 /// \param[in] sourceConnection System that sent us this network message. PreDestruction(RakNet::Connection_RM3 * sourceConnection)879 virtual void PreDestruction(RakNet::Connection_RM3 *sourceConnection) {(void) sourceConnection;} 880 881 /// creatingSystemGUID is set the first time Reference() is called, or if we get the object from another system 882 /// \return System that originally created this object 883 RakNetGUID GetCreatingSystemGUID(void) const; 884 885 /// Call to send a network message to delete this object on other systems.<BR> 886 /// Call it before deleting the object 887 virtual void BroadcastDestruction(void); 888 889 /// Default call for QueryConstruction(). Allow clients to create this object 890 virtual RM3ConstructionState QueryConstruction_ClientConstruction(RakNet::Connection_RM3 *destinationConnection); 891 /// Default call for QueryConstruction(). Allow clients to create this object 892 virtual bool QueryRemoteConstruction_ClientConstruction(RakNet::Connection_RM3 *sourceConnection); 893 894 /// Default call for QueryConstruction(). Allow the server to create this object, but not the client. 895 virtual RM3ConstructionState QueryConstruction_ServerConstruction(RakNet::Connection_RM3 *destinationConnection); 896 /// Default call for QueryConstruction(). Allow the server to create this object, but not the client. 897 virtual bool QueryRemoteConstruction_ServerConstruction(RakNet::Connection_RM3 *sourceConnection); 898 899 /// Default call for QueryConstruction(). Peer to peer - creating system sends the object to all other systems. No relaying. 900 virtual RM3ConstructionState QueryConstruction_PeerToPeer(RakNet::Connection_RM3 *destinationConnection); 901 /// Default call for QueryConstruction(). Peer to peer - creating system sends the object to all other systems. No relaying. 902 virtual bool QueryRemoteConstruction_PeerToPeer(RakNet::Connection_RM3 *sourceConnection); 903 904 /// Default call for QuerySerialization(). Use if the values you are serializing are generated by the client that owns the object. The serialization will be relayed through the server to the other clients. 905 virtual RakNet::RM3QuerySerializationResult QuerySerialization_ClientSerializable(RakNet::Connection_RM3 *destinationConnection); 906 /// Default call for QuerySerialization(). Use if the values you are serializing are generated only by the server. The serialization will be sent to all clients, but the clients will not send back to the server. 907 virtual RakNet::RM3QuerySerializationResult QuerySerialization_ServerSerializable(RakNet::Connection_RM3 *destinationConnection); 908 /// Default call for QuerySerialization(). Use if the values you are serializing are on a peer to peer network. The peer that owns the object will send to all. Remote peers will not send. 909 virtual RakNet::RM3QuerySerializationResult QuerySerialization_PeerToPeer(RakNet::Connection_RM3 *destinationConnection); 910 911 /// Default: If we are a client, and the connection is lost, delete the server's objects 912 virtual RM3ActionOnPopConnection QueryActionOnPopConnection_Client(RakNet::Connection_RM3 *droppedConnection) const; 913 /// Default: If we are a client, and the connection is lost, delete the client's objects and broadcast the destruction 914 virtual RM3ActionOnPopConnection QueryActionOnPopConnection_Server(RakNet::Connection_RM3 *droppedConnection) const; 915 /// Default: If we are a peer, and the connection is lost, delete the peer's objects 916 virtual RM3ActionOnPopConnection QueryActionOnPopConnection_PeerToPeer(RakNet::Connection_RM3 *droppedConnection) const; 917 918 /// GUID of the system that first called Reference() on this object. 919 /// Transmitted automatically when the object is constructed 920 RakNetGUID creatingSystemGUID; 921 /// GUID of the system that caused the item to send a deletion command over the network 922 RakNetGUID deletingSystemGUID; 923 924 /// \internal 925 /// ReplicaManager3 plugin associated with this object 926 ReplicaManager3 *replicaManager; 927 928 LastSerializationResultBS lastSentSerialization; 929 RakNetTime whenLastSerialized; 930 bool forceSendUntilNextUpdate; 931 }; 932 933 } // namespace RakNet 934 935 936 #endif 937 938 #endif // _RAKNET_SUPPORT_* 939