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