aboutsummaryrefslogtreecommitdiff
path: root/src/parsec_server/include/e_simnetoutput.h
blob: db2441b07bf0f2d6df4eed7854d2a0e4ba362797 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
#ifndef E_SIMNETOUTPUT_H_
#define E_SIMNETOUTPUT_H_


// update todos ---------------------------------------------------------------
//
#define UPDATE_TODO_NOTHING					0x0000
#define UPDATE_TODO_SEND					0x0001
#define UPDATE_TODO_MASK					0x0001

// update mode  ---------------------------------------------------------------
//
#define UPDATEMODE_SENDMODE_UNRELIABLE		0x0000
#define UPDATEMODE_SENDMODE_RELIABLE		0x0010
#define UPDATEMODE_SENDMODE_MASK			0x0010

#define UPDATEMODE_SENDWHAT_STATE			0x0000
#define UPDATEMODE_SENDWHAT_REMOVE			0x0020
#define UPDATEMODE_SENDWHAT_MASK			0x0020

#define UPDATEMODE_FLAGS_SEND_TO_OWNER		0x0100
#define UPDATEMODE_FLAGS_MASK				0xFF00


enum {
    
	RMEVSTATE_NEBULAID,
	RMEVSTATE_PROBEXTRA,
	RMEVSTATE_PROBHELIX,
	RMEVSTATE_PROBLIGHTNING,
	RMEVSTATE_PROBPHOTON,
	RMEVSTATE_PROBMINE,
	RMEVSTATE_PROBREPAIR,
	RMEVSTATE_PROBAFTERBURNER,
	RMEVSTATE_PROBHOLODECOY,
	RMEVSTATE_PROBINVISIBILITY,
	RMEVSTATE_PROBINVULNERABILITY,
	RMEVSTATE_PROBENERGYFIELD,
	RMEVSTATE_PROBLASERUPGRADE,
	RMEVSTATE_PROBLASERUPGRADE1,
	RMEVSTATE_PROBLASERUPGRADE2,
	RMEVSTATE_PROBMISSPACK,
	RMEVSTATE_PROBDUMBPACK,
	RMEVSTATE_PROBGUIDEPACK,
	RMEVSTATE_PROBSWARMPACK,
	RMEVSTATE_PROBEMPUPGRADE1,
	RMEVSTATE_PROBEMPUPGRADE2,
	RMEVSTATE_AMAZING,
	RMEVSTATE_BRILLIANT,
	RMEVSTATE_KILLLIMIT,
    RMEVSTATE_ENERGYBOOST,
    RMEVSTATE_REPAIRBOOST,
    RMEVSTATE_DUMBPACK,
    RMEVSTATE_HOMPACK,
    RMEVSTATE_SWARMPACK,
    RMEVSTATE_PROXPACK,
    
	RMEVSTATE_NUMSTATES
};

// info about a E_Distributable -------------------------------------------------
//
class E_Distributable
{
protected:
	dword				m_objectid;
	int					m_listno;
	int					m_update_mode;
	byte*				m_update_to_client;
public:
	E_Distributable( dword objectid, int listno, int reliable, int send_to_owner ) : 
		m_objectid( objectid ),
		m_listno( listno ),
		m_update_mode( UPDATE_TODO_NOTHING ),
		m_update_to_client( NULL )
	{
		// translate to internal format
		if ( reliable ) {
			m_update_mode |= UPDATEMODE_SENDMODE_RELIABLE;
		}
		if ( send_to_owner ) {
			m_update_mode |= UPDATEMODE_FLAGS_SEND_TO_OWNER;
		}

		ResetUpdateInfo();
	}

	~E_Distributable()
	{
		delete []m_update_to_client;
	}

	// reset the update info
	void ResetUpdateInfo();

	// get the object id
	dword GetObjectID() { return m_objectid; }

	// return the list # the object belongs to
	int GetListNo() { return m_listno; }

	// set updatemode for all clients to STATE
	void UpdateMode_STATE();

	// set updatemode for all clients to REMOVE
	void UpdateMode_REMOVE();

	// check whether this E_Distributable is marked as REMOVE
	int IsInRemoving()
	{
		return ( ( m_update_mode & UPDATEMODE_SENDWHAT_MASK ) == UPDATEMODE_SENDWHAT_REMOVE );
	}

	// return whether the E_Distributable will be sent to the owner
	int WillBeSentToOwner()
	{
		return ( ( m_update_mode & UPDATEMODE_FLAGS_SEND_TO_OWNER ) != 0 );
	}

	// check whether the E_Distributable is a ZOMBIE ( client has received the REMOVE update )
	int IsZombie( int nClientID );

	// check whethe the E_Distributable has an update for a specific client
	int HasUpdate( int nClientID );

	// mark, that we sent an update to a client
	void MarkUpdateSent( int nClientID );

	// mark, that we need to send an update to a client
	void MarkForUpdate( int nClientID );

	// check whether the E_Distributable should be sent reliable
	int NeedsReliable()
	{
		return ( ( m_update_mode & UPDATEMODE_SENDMODE_MASK ) == UPDATEMODE_SENDMODE_RELIABLE );
	}

	// write a corresponding RE to the REList
	void DistributeToREList( E_REList* relist );

	// determine the size this E_Distributable is
	size_t DetermineSizeInPacket();
};





// send modi for client updates -----------------------------------------------
//
#define SEND_MODE_NONE			0
#define SEND_MODE_UNRELIABLE	1
#define SEND_MODE_RELIABLE		2

#define MAX_NUM_DISTRIBUTABLES_TO_SEND_PER_PACKET		256

// information about packets sent out ( time and size ) -----------------------
//
struct sent_packet_info_s {

	sent_packet_info_s()
	{
		Reset();
	}

	void Reset()
	{
		m_size = 0;
		m_sendtime = 0;
	}

	size_t		m_size;
	refframe_t	m_sendtime;
};


// class handling the network output for a client -----------------------------
// class with all necessary information on what to send to the destination client
class E_SimClientNetOutput
{
protected:

	int							m_nDestClientID;

	E_REList*					m_pReliableBuffer;
	E_REList*					m_pUnreliableBuffer;

	sent_packet_info_s*			m_SentPacketInfo;
	unsigned int				m_nPacket;

	refframe_t					m_LastSendFrame;
	refframe_t					m_Send_FrameTime;
	
	refframe_t					m_Heartbeat_Timeout_Frame;

	int							m_nNumPacketSlots;
	int							m_nAveragePacketSize;

	// list of all distributables for the client
	UTL_List<E_Distributable*>*	m_AllDistributables;

protected:

	// list of client ids the client is to be updated in the next packet
	int*			m_ClientIDList;		
	bool_t*			m_SendReliable;
	int				m_nNumClients;

	// inidicate that we should send a the state of the client itself to the destination client ( energy, damage, shields )
	bool_t			m_bIncludeDestClientState;

	// indicate whether to send the gamestate to the client
	bool_t			m_bIncludeGameState;

	// indicate whether to send the killstats to the client
	bool_t			m_bIncludeKillStats;

    //Indicate whether to send state variables to client
    bool_t          m_bIncludeStateSync;
    
	// array of distributables for next packet
	E_Distributable*	m_DistsForNextPacket[ MAX_NUM_DISTRIBUTABLES_TO_SEND_PER_PACKET ];
	int				m_nNumDistsForNextPacket;

	// # of byte available for the update
	int				m_nSizeAvail;

public:

	// default ctor/dtor
	E_SimClientNetOutput();
	~E_SimClientNetOutput();

	// connect a client
	void Connect( int nClientID );

	// disconnect a client
	void Disconnect();

	// sent udpate information to a client if bandwidth available
	int SendUpdateToClient();

	// the NET.SERVERRATE for this client has changed - recalc frame-time
	void RateChanged();

	// (re)calculate the average packet size
	void CalculateAveragePacketSize();

	// schedule a E_Distributable to be sent to the client
	void ScheduleDistributable( E_Distributable* pDist, int check_unique = FALSE );

	// buffer an RE for output
	void BufferRE( RE_Header* re, int reliable );

protected:

	// reset all data members
	void _Reset();

	// clear the list of things to update 
	void _ClearUpdates();

	// check whether there are any updates to send to the client
	int _HasUpdates();

	// add a E_Distributable to be sent out with the next packet
	void _AddDistForOutput( E_Distributable* pDist );

	// include the information about a client in the next update ( reliable or unreliable )
	void _FlagIncludeClient( int nClientID, bool_t bReliable );

	// check whether we can reserve size for output, and do so if space avail.
	bool_t _ReserveForOutput( int size );

	// fill the RE lists to be sent to the client
	int _FillPacketForClient( E_REList* pReliable, E_REList* pUnreliable );

	// getters/setters
	size_t _GetSizeAvail()	{ return m_nSizeAvail; }

	// check whether we should send a packet to this client
	int _CanSendPacket();

	// create buffer E_RELists for pass-through multicasts
	void _CreateBuffers();

	// terminate the multicast data in the E_REList buffers
	void _TerminateBufferMulticast();

	// determine which states must be updated for this client
	int _PrepareClientUpdateInfo();

	// check whether to send a heartbeat to the client
	int _ShouldSendHeartbeat();

	// set the new heartbeat timeout value
	void _DoHeartbeat();
};



// class for handling the network output from the simulation ------------------
//
class E_SimNetOutput {
protected:
	E_SimClientNetOutput*		m_SimClientNetOutput;
	UTL_List<E_Distributable*>*	m_Distributables;

protected:
	E_SimNetOutput();
	~E_SimNetOutput();

public:
	// SINGLETON access
	static E_SimNetOutput* GetSimNetOutput()
	{
		static E_SimNetOutput _TheSimNetOutput;
		return &_TheSimNetOutput;
	}

	// reset all data
	void Reset();

	// connect the player in a specific slot 
	int ConnectPlayer( int nClientID );

	// disconnect the player in a specific slot
	int DisconnectPlayer( int nClientID );

	// update all clients
	void DoClientUpdates();

	// buffer a RE for sending to all clients minus sender
	void BufferForMulticastRE( RE_Header* relist, int nSenderClientID, int reliable );
    
    // buffer a RE for sending to a specific client
    void BufferForDirectRE( RE_Header* relist, int nClientID, int reliable );
    
	// update NET.SERVERRATE dependent stuff of E_SimClientNetOutput
	void RateChangedForClient( int nClientID );

	// recalculate the average packet sizes for all connected clients
	void RecalcAveragePacketSizes();

	// create a new E_Distributable for all connected clients
	E_Distributable* CreateDistributable( GenObject* object, int reliable = FALSE, int send_to_owner = FALSE );

	// release a E_Distributable
	void ReleaseDistributable( E_Distributable* pDist );

	// cleanup all distributables, that are complete zombies
	void CleanupZombieDistributables();
   
protected:
	// destroy m_Distributables
	void _DestroyDistributables();

};


#endif // !E_SIMNETOUTPUT_H_