3 // this is 88 bytes (must match entity_state_t in protocol.h)
4 entity_state_t defaultstate =
6 // ! means this is not sent to client
7 0,//double time; // ! time this state was built (used on client for interpolation)
8 {0,0,0},//float netcenter[3]; // ! for network prioritization, this is the center of the bounding box (which may differ from the origin)
9 {0,0,0},//float origin[3];
10 {0,0,0},//float angles[3];
12 0,//unsigned int customizeentityforclient; // !
13 0,//unsigned short number; // entity number this state is for
14 0,//unsigned short modelindex;
15 0,//unsigned short frame;
16 0,//unsigned short tagentity;
17 0,//unsigned short specialvisibilityradius; // ! larger if it has effects/light
18 0,//unsigned short viewmodelforclient; // !
19 0,//unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
20 0,//unsigned short nodrawtoclient; // !
21 0,//unsigned short drawonlytoclient; // !
22 0,//unsigned short traileffectnum;
23 {0,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
24 ACTIVE_NOT,//unsigned char active; // true if a valid state
25 0,//unsigned char lightstyle;
26 0,//unsigned char lightpflags;
27 0,//unsigned char colormap;
28 0,//unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
29 255,//unsigned char alpha;
30 16,//unsigned char scale;
31 0,//unsigned char glowsize;
32 254,//unsigned char glowcolor;
33 0,//unsigned char flags;
34 0,//unsigned char internaleffects; // INTEF_FLAG1QW and so on
35 0,//unsigned char tagindex;
36 {32, 32, 32},//unsigned char colormod[3];
37 {32, 32, 32},//unsigned char glowmod[3];
40 // LadyHavoc: I own protocol ranges 96, 97, 3500-3599
42 struct protocolversioninfo_s
45 protocolversion_t version;
48 protocolversioninfo[] =
50 { 3504, PROTOCOL_DARKPLACES7 , "DP7"},
51 { 3503, PROTOCOL_DARKPLACES6 , "DP6"},
52 { 3502, PROTOCOL_DARKPLACES5 , "DP5"},
53 { 3501, PROTOCOL_DARKPLACES4 , "DP4"},
54 { 3500, PROTOCOL_DARKPLACES3 , "DP3"},
55 { 97, PROTOCOL_DARKPLACES2 , "DP2"},
56 { 96, PROTOCOL_DARKPLACES1 , "DP1"},
57 { 15, PROTOCOL_QUAKEDP , "QUAKEDP"},
58 { 15, PROTOCOL_QUAKE , "QUAKE"},
59 { 28, PROTOCOL_QUAKEWORLD , "QW"},
60 { 250, PROTOCOL_NEHAHRAMOVIE, "NEHAHRAMOVIE"},
61 {10000, PROTOCOL_NEHAHRABJP , "NEHAHRABJP"},
62 {10001, PROTOCOL_NEHAHRABJP2 , "NEHAHRABJP2"},
63 {10002, PROTOCOL_NEHAHRABJP3 , "NEHAHRABJP3"},
64 { 0, PROTOCOL_UNKNOWN , NULL}
67 protocolversion_t Protocol_EnumForName(const char *s)
70 for (i = 0;protocolversioninfo[i].name;i++)
71 if (!strcasecmp(s, protocolversioninfo[i].name))
72 return protocolversioninfo[i].version;
73 return PROTOCOL_UNKNOWN;
76 const char *Protocol_NameForEnum(protocolversion_t p)
79 for (i = 0;protocolversioninfo[i].name;i++)
80 if (protocolversioninfo[i].version == p)
81 return protocolversioninfo[i].name;
85 protocolversion_t Protocol_EnumForNumber(int n)
88 for (i = 0;protocolversioninfo[i].name;i++)
89 if (protocolversioninfo[i].number == n)
90 return protocolversioninfo[i].version;
91 return PROTOCOL_UNKNOWN;
94 int Protocol_NumberForEnum(protocolversion_t p)
97 for (i = 0;protocolversioninfo[i].name;i++)
98 if (protocolversioninfo[i].version == p)
99 return protocolversioninfo[i].number;
103 void Protocol_Names(char *buffer, size_t buffersize)
109 for (i = 0;protocolversioninfo[i].name;i++)
112 strlcat(buffer, " ", buffersize);
113 strlcat(buffer, protocolversioninfo[i].name, buffersize);
117 void Protocol_UpdateClientStats(const int *stats)
120 // update the stats array and set deltabits for any changed stats
121 for (i = 0;i < MAX_CL_STATS;i++)
123 if (host_client->stats[i] != stats[i])
125 host_client->statsdeltabits[i >> 3] |= 1 << (i & 7);
126 host_client->stats[i] = stats[i];
131 // only a few stats are within the 32 stat limit of Quake, and most of them
132 // are sent every frame in svc_clientdata messages, so we only send the
133 // remaining ones here
134 static const int sendquakestats[] =
136 // quake did not send these secrets/monsters stats in this way, but doing so
137 // allows a mod to increase STAT_TOTALMONSTERS during the game, and ensures
138 // that STAT_SECRETS and STAT_MONSTERS are always correct (even if a client
139 // didn't receive an svc_foundsecret or svc_killedmonster), which may be most
140 // valuable if randomly seeking around in a demo
141 STAT_TOTALSECRETS, // never changes during game
142 STAT_TOTALMONSTERS, // changes in some mods
143 STAT_SECRETS, // this makes svc_foundsecret unnecessary
144 STAT_MONSTERS, // this makes svc_killedmonster unnecessary
145 STAT_VIEWHEIGHT, // sent just for FTEQW clients
146 STAT_VIEWZOOM, // this rarely changes
150 void Protocol_WriteStatsReliable(void)
153 if (!host_client->netconnection)
155 // detect changes in stats and write reliable messages
156 // this only deals with 32 stats because the older protocols which use
157 // this function can only cope with 32 stats,
158 // they also do not support svc_updatestatubyte which was introduced in
159 // DP6 protocol (except for QW)
160 for (j = 0;sendquakestats[j] >= 0;j++)
162 i = sendquakestats[j];
163 // check if this bit is set
164 if (host_client->statsdeltabits[i >> 3] & (1 << (i & 7)))
166 host_client->statsdeltabits[i >> 3] -= (1 << (i & 7));
167 // send the stat as a byte if possible
168 if (sv.protocol == PROTOCOL_QUAKEWORLD)
170 if (host_client->stats[i] >= 0 && host_client->stats[i] < 256)
172 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestat);
173 MSG_WriteByte(&host_client->netconnection->message, i);
174 MSG_WriteByte(&host_client->netconnection->message, host_client->stats[i]);
178 MSG_WriteByte(&host_client->netconnection->message, qw_svc_updatestatlong);
179 MSG_WriteByte(&host_client->netconnection->message, i);
180 MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]);
185 // this could make use of svc_updatestatubyte in DP6 and later
186 // protocols but those protocols do not use this function
187 MSG_WriteByte(&host_client->netconnection->message, svc_updatestat);
188 MSG_WriteByte(&host_client->netconnection->message, i);
189 MSG_WriteLong(&host_client->netconnection->message, host_client->stats[i]);
195 entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number)
197 if (d->maxreferenceentities <= number)
199 int oldmax = d->maxreferenceentities;
200 entity_state_t *oldentity = d->referenceentity;
201 d->maxreferenceentities = (number + 15) & ~7;
202 d->referenceentity = (entity_state_t *)Mem_Alloc(d->mempool, d->maxreferenceentities * sizeof(*d->referenceentity));
205 memcpy(d->referenceentity, oldentity, oldmax * sizeof(*d->referenceentity));
208 // clear the newly created entities
209 for (;oldmax < d->maxreferenceentities;oldmax++)
211 d->referenceentity[oldmax] = defaultstate;
212 d->referenceentity[oldmax].number = oldmax;
215 return d->referenceentity + number;
218 void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s)
220 // resize commit's entity list if full
221 if (d->currentcommit->maxentities <= d->currentcommit->numentities)
223 entity_state_t *oldentity = d->currentcommit->entity;
224 d->currentcommit->maxentities += 8;
225 d->currentcommit->entity = (entity_state_t *)Mem_Alloc(d->mempool, d->currentcommit->maxentities * sizeof(*d->currentcommit->entity));
228 memcpy(d->currentcommit->entity, oldentity, d->currentcommit->numentities * sizeof(*d->currentcommit->entity));
232 d->currentcommit->entity[d->currentcommit->numentities++] = *s;
235 entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool)
237 entityframe4_database_t *d;
238 d = (entityframe4_database_t *)Mem_Alloc(pool, sizeof(*d));
240 EntityFrame4_ResetDatabase(d);
244 void EntityFrame4_FreeDatabase(entityframe4_database_t *d)
247 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
248 if (d->commit[i].entity)
249 Mem_Free(d->commit[i].entity);
250 if (d->referenceentity)
251 Mem_Free(d->referenceentity);
255 void EntityFrame4_ResetDatabase(entityframe4_database_t *d)
258 d->referenceframenum = -1;
259 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
260 d->commit[i].numentities = 0;
261 for (i = 0;i < d->maxreferenceentities;i++)
262 d->referenceentity[i] = defaultstate;
265 int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode)
268 entity_database4_commit_t *commit;
271 // reset reference, but leave commits alone
272 d->referenceframenum = -1;
273 for (i = 0;i < d->maxreferenceentities;i++)
275 d->referenceentity[i] = defaultstate;
276 // if this is the server, remove commits
277 for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
278 commit->numentities = 0;
282 else if (d->referenceframenum == framenum)
287 for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
289 if (commit->numentities && commit->framenum <= framenum)
291 if (commit->framenum == framenum)
294 d->referenceframenum = framenum;
295 if (developer_networkentities.integer >= 3)
297 for (j = 0;j < commit->numentities;j++)
299 entity_state_t *s = EntityFrame4_GetReferenceEntity(d, commit->entity[j].number);
300 if (commit->entity[j].active != s->active)
302 if (commit->entity[j].active == ACTIVE_NETWORK)
303 Con_Printf("commit entity %i has become active (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
305 Con_Printf("commit entity %i has become inactive (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
307 *s = commit->entity[j];
311 for (j = 0;j < commit->numentities;j++)
312 *EntityFrame4_GetReferenceEntity(d, commit->entity[j].number) = commit->entity[j];
314 commit->numentities = 0;
318 if (developer_networkentities.integer >= 1)
320 Con_Printf("ack ref:%i database updated to: ref:%i commits:", framenum, d->referenceframenum);
321 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
322 if (d->commit[i].numentities)
323 Con_Printf(" %i", d->commit[i].framenum);
329 void EntityFrame4_CL_ReadFrame(void)
331 int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false;
333 entityframe4_database_t *d;
334 if (!cl.entitydatabase4)
335 cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.levelmempool);
336 d = cl.entitydatabase4;
337 // read the number of the frame this refers to
338 referenceframenum = MSG_ReadLong(&cl_message);
339 // read the number of this frame
340 framenum = MSG_ReadLong(&cl_message);
341 CL_NewFrameReceived(framenum);
342 // read the start number
343 enumber = (unsigned short) MSG_ReadShort(&cl_message);
344 if (developer_networkentities.integer >= 10)
346 Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum);
347 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
348 if (d->commit[i].numentities)
349 Con_Printf(" %i", d->commit[i].framenum);
352 if (!EntityFrame4_AckFrame(d, referenceframenum, false))
354 Con_Print("EntityFrame4_CL_ReadFrame: reference frame invalid (VERY BAD ERROR), this update will be skipped\n");
357 d->currentcommit = NULL;
358 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
360 if (!d->commit[i].numentities)
362 d->currentcommit = d->commit + i;
363 d->currentcommit->framenum = framenum;
364 d->currentcommit->numentities = 0;
367 if (d->currentcommit == NULL)
369 Con_Printf("EntityFrame4_CL_ReadFrame: error while decoding frame %i: database full, reading but not storing this update\n", framenum);
373 while (!done && !cl_message.badread)
375 // read the number of the modified entity
376 // (gaps will be copied unmodified)
377 n = (unsigned short)MSG_ReadShort(&cl_message);
380 // no more entities in this update, but we still need to copy the
381 // rest of the reference entities (final gap)
383 // read end of range number, then process normally
384 n = (unsigned short)MSG_ReadShort(&cl_message);
386 // high bit means it's a remove message
387 cnumber = n & 0x7FFF;
388 // if this is a live entity we may need to expand the array
389 if (cl.num_entities <= cnumber && !(n & 0x8000))
391 cl.num_entities = cnumber + 1;
392 if (cnumber >= cl.max_entities)
393 CL_ExpandEntities(cnumber);
395 // add one (the changed one) if not done
396 stopnumber = cnumber + !done;
397 // process entities in range from the last one to the changed one
398 for (;enumber < stopnumber;enumber++)
400 if (skip || enumber >= cl.num_entities)
402 if (enumber == cnumber && (n & 0x8000) == 0)
404 entity_state_t tempstate;
405 EntityState_ReadFields(&tempstate, EntityState_ReadExtendBits());
409 // slide the current into the previous slot
410 cl.entities[enumber].state_previous = cl.entities[enumber].state_current;
411 // copy a new current from reference database
412 cl.entities[enumber].state_current = *EntityFrame4_GetReferenceEntity(d, enumber);
413 s = &cl.entities[enumber].state_current;
414 // if this is the one to modify, read more data...
415 if (enumber == cnumber)
420 if (developer_networkentities.integer >= 2)
421 Con_Printf("entity %i: remove\n", enumber);
427 if (developer_networkentities.integer >= 2)
428 Con_Printf("entity %i: update\n", enumber);
429 s->active = ACTIVE_NETWORK;
430 EntityState_ReadFields(s, EntityState_ReadExtendBits());
433 else if (developer_networkentities.integer >= 4)
434 Con_Printf("entity %i: copy\n", enumber);
435 // set the cl.entities_active flag
436 cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK);
437 // set the update time
438 s->time = cl.mtime[0];
439 // fix the number (it gets wiped occasionally by copying from defaultstate)
441 // check if we need to update the lerp stuff
442 if (s->active == ACTIVE_NETWORK)
443 CL_MoveLerpEntityStates(&cl.entities[enumber]);
444 // add this to the commit entry whether it is modified or not
445 if (d->currentcommit)
446 EntityFrame4_AddCommitEntity(d, &cl.entities[enumber].state_current);
447 // print extra messages if desired
448 if (developer_networkentities.integer >= 2 && cl.entities[enumber].state_current.active != cl.entities[enumber].state_previous.active)
450 if (cl.entities[enumber].state_current.active == ACTIVE_NETWORK)
451 Con_Printf("entity #%i has become active\n", enumber);
452 else if (cl.entities[enumber].state_previous.active)
453 Con_Printf("entity #%i has become inactive\n", enumber);
457 d->currentcommit = NULL;
459 EntityFrame4_ResetDatabase(d);
462 qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t **states)
464 prvm_prog_t *prog = SVVM_prog;
465 const entity_state_t *e, *s;
466 entity_state_t inactiveentitystate;
467 int i, n, startnumber;
469 unsigned char data[128];
471 // if there isn't enough space to accomplish anything, skip it
472 if (msg->cursize + 24 > maxsize)
475 // prepare the buffer
476 memset(&buf, 0, sizeof(buf));
478 buf.maxsize = sizeof(data);
480 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
481 if (!d->commit[i].numentities)
483 // if commit buffer full, just don't bother writing an update this frame
484 if (i == MAX_ENTITY_HISTORY)
486 d->currentcommit = d->commit + i;
488 // this state's number gets played around with later
489 inactiveentitystate = defaultstate;
491 d->currentcommit->numentities = 0;
492 d->currentcommit->framenum = ++d->latestframenumber;
493 MSG_WriteByte(msg, svc_entities);
494 MSG_WriteLong(msg, d->referenceframenum);
495 MSG_WriteLong(msg, d->currentcommit->framenum);
496 if (developer_networkentities.integer >= 10)
498 Con_Printf("send svc_entities num:%i ref:%i (database: ref:%i commits:", d->currentcommit->framenum, d->referenceframenum, d->referenceframenum);
499 for (i = 0;i < MAX_ENTITY_HISTORY;i++)
500 if (d->commit[i].numentities)
501 Con_Printf(" %i", d->commit[i].framenum);
504 if (d->currententitynumber >= prog->max_edicts)
507 startnumber = bound(1, d->currententitynumber, prog->max_edicts - 1);
508 MSG_WriteShort(msg, startnumber);
509 // reset currententitynumber so if the loop does not break it we will
510 // start at beginning next frame (if it does break, it will set it)
511 d->currententitynumber = 1;
512 for (i = 0, n = startnumber;n < prog->max_edicts;n++)
514 if (PRVM_serveredictfunction((&prog->edicts[n]), SendEntity))
516 // find the old state to delta from
517 e = EntityFrame4_GetReferenceEntity(d, n);
518 // prepare the buffer
520 // entity exists, build an update (if empty there is no change)
521 // find the state in the list
522 for (;i < numstates && states[i]->number < n;i++);
528 EntityState_WriteUpdate(s, &buf, e);
532 inactiveentitystate.number = n;
533 s = &inactiveentitystate;
534 if (e->active == ACTIVE_NETWORK)
536 // entity used to exist but doesn't anymore, send remove
537 MSG_WriteShort(&buf, n | 0x8000);
540 // if the commit is full, we're done this frame
541 if (msg->cursize + buf.cursize > maxsize - 4)
543 // next frame we will continue where we left off
546 // add the entity to the commit
547 EntityFrame4_AddCommitEntity(d, s);
548 // if the message is empty, skip out now
551 // write the message to the packet
552 SZ_Write(msg, buf.data, buf.cursize);
555 d->currententitynumber = n;
557 // remove world message (invalid, and thus a good terminator)
558 MSG_WriteShort(msg, 0x8000);
559 // write the number of the end entity
560 MSG_WriteShort(msg, d->currententitynumber);
562 d->currentcommit = NULL;