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_
|