]> git.xonotic.org Git - xonotic/darkplaces.git/blob - protocol.c
(Round 2) Break up protocol.c
[xonotic/darkplaces.git] / protocol.c
1 #include "quakedef.h"
2
3 // this is 88 bytes (must match entity_state_t in protocol.h)
4 entity_state_t defaultstate =
5 {
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];
11         0,//int effects;
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];
38 };
39
40 // LadyHavoc: I own protocol ranges 96, 97, 3500-3599
41
42 struct protocolversioninfo_s
43 {
44         int number;
45         protocolversion_t version;
46         const char *name;
47 }
48 protocolversioninfo[] =
49 {
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}
65 };
66
67 protocolversion_t Protocol_EnumForName(const char *s)
68 {
69         int i;
70         for (i = 0;protocolversioninfo[i].name;i++)
71                 if (!strcasecmp(s, protocolversioninfo[i].name))
72                         return protocolversioninfo[i].version;
73         return PROTOCOL_UNKNOWN;
74 }
75
76 const char *Protocol_NameForEnum(protocolversion_t p)
77 {
78         int i;
79         for (i = 0;protocolversioninfo[i].name;i++)
80                 if (protocolversioninfo[i].version == p)
81                         return protocolversioninfo[i].name;
82         return "UNKNOWN";
83 }
84
85 protocolversion_t Protocol_EnumForNumber(int n)
86 {
87         int i;
88         for (i = 0;protocolversioninfo[i].name;i++)
89                 if (protocolversioninfo[i].number == n)
90                         return protocolversioninfo[i].version;
91         return PROTOCOL_UNKNOWN;
92 }
93
94 int Protocol_NumberForEnum(protocolversion_t p)
95 {
96         int i;
97         for (i = 0;protocolversioninfo[i].name;i++)
98                 if (protocolversioninfo[i].version == p)
99                         return protocolversioninfo[i].number;
100         return 0;
101 }
102
103 void Protocol_Names(char *buffer, size_t buffersize)
104 {
105         int i;
106         if (buffersize < 1)
107                 return;
108         buffer[0] = 0;
109         for (i = 0;protocolversioninfo[i].name;i++)
110         {
111                 if (i > 1)
112                         strlcat(buffer, " ", buffersize);
113                 strlcat(buffer, protocolversioninfo[i].name, buffersize);
114         }
115 }
116
117 void Protocol_UpdateClientStats(const int *stats)
118 {
119         int i;
120         // update the stats array and set deltabits for any changed stats
121         for (i = 0;i < MAX_CL_STATS;i++)
122         {
123                 if (host_client->stats[i] != stats[i])
124                 {
125                         host_client->statsdeltabits[i >> 3] |= 1 << (i & 7);
126                         host_client->stats[i] = stats[i];
127                 }
128         }
129 }
130
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[] =
135 {
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
147 -1,
148 };
149
150 void Protocol_WriteStatsReliable(void)
151 {
152         int i, j;
153         if (!host_client->netconnection)
154                 return;
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++)
161         {
162                 i = sendquakestats[j];
163                 // check if this bit is set
164                 if (host_client->statsdeltabits[i >> 3] & (1 << (i & 7)))
165                 {
166                         host_client->statsdeltabits[i >> 3] -= (1 << (i & 7));
167                         // send the stat as a byte if possible
168                         if (sv.protocol == PROTOCOL_QUAKEWORLD)
169                         {
170                                 if (host_client->stats[i] >= 0 && host_client->stats[i] < 256)
171                                 {
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]);
175                                 }
176                                 else
177                                 {
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]);
181                                 }
182                         }
183                         else
184                         {
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]);
190                         }
191                 }
192         }
193 }
194
195 entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number)
196 {
197         if (d->maxreferenceentities <= number)
198         {
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));
203                 if (oldentity)
204                 {
205                         memcpy(d->referenceentity, oldentity, oldmax * sizeof(*d->referenceentity));
206                         Mem_Free(oldentity);
207                 }
208                 // clear the newly created entities
209                 for (;oldmax < d->maxreferenceentities;oldmax++)
210                 {
211                         d->referenceentity[oldmax] = defaultstate;
212                         d->referenceentity[oldmax].number = oldmax;
213                 }
214         }
215         return d->referenceentity + number;
216 }
217
218 void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s)
219 {
220         // resize commit's entity list if full
221         if (d->currentcommit->maxentities <= d->currentcommit->numentities)
222         {
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));
226                 if (oldentity)
227                 {
228                         memcpy(d->currentcommit->entity, oldentity, d->currentcommit->numentities * sizeof(*d->currentcommit->entity));
229                         Mem_Free(oldentity);
230                 }
231         }
232         d->currentcommit->entity[d->currentcommit->numentities++] = *s;
233 }
234
235 entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool)
236 {
237         entityframe4_database_t *d;
238         d = (entityframe4_database_t *)Mem_Alloc(pool, sizeof(*d));
239         d->mempool = pool;
240         EntityFrame4_ResetDatabase(d);
241         return d;
242 }
243
244 void EntityFrame4_FreeDatabase(entityframe4_database_t *d)
245 {
246         int i;
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);
252         Mem_Free(d);
253 }
254
255 void EntityFrame4_ResetDatabase(entityframe4_database_t *d)
256 {
257         int i;
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;
263 }
264
265 int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode)
266 {
267         int i, j, found;
268         entity_database4_commit_t *commit;
269         if (framenum == -1)
270         {
271                 // reset reference, but leave commits alone
272                 d->referenceframenum = -1;
273                 for (i = 0;i < d->maxreferenceentities;i++)
274                 {
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;
279                 }
280                 found = true;
281         }
282         else if (d->referenceframenum == framenum)
283                 found = true;
284         else
285         {
286                 found = false;
287                 for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
288                 {
289                         if (commit->numentities && commit->framenum <= framenum)
290                         {
291                                 if (commit->framenum == framenum)
292                                 {
293                                         found = true;
294                                         d->referenceframenum = framenum;
295                                         if (developer_networkentities.integer >= 3)
296                                         {
297                                                 for (j = 0;j < commit->numentities;j++)
298                                                 {
299                                                         entity_state_t *s = EntityFrame4_GetReferenceEntity(d, commit->entity[j].number);
300                                                         if (commit->entity[j].active != s->active)
301                                                         {
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);
304                                                                 else
305                                                                         Con_Printf("commit entity %i has become inactive (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
306                                                         }
307                                                         *s = commit->entity[j];
308                                                 }
309                                         }
310                                         else
311                                                 for (j = 0;j < commit->numentities;j++)
312                                                         *EntityFrame4_GetReferenceEntity(d, commit->entity[j].number) = commit->entity[j];
313                                 }
314                                 commit->numentities = 0;
315                         }
316                 }
317         }
318         if (developer_networkentities.integer >= 1)
319         {
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);
324                 Con_Print("\n");
325         }
326         return found;
327 }
328
329 void EntityFrame4_CL_ReadFrame(void)
330 {
331         int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false;
332         entity_state_t *s;
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)
345         {
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);
350                 Con_Print("\n");
351         }
352         if (!EntityFrame4_AckFrame(d, referenceframenum, false))
353         {
354                 Con_Print("EntityFrame4_CL_ReadFrame: reference frame invalid (VERY BAD ERROR), this update will be skipped\n");
355                 skip = true;
356         }
357         d->currentcommit = NULL;
358         for (i = 0;i < MAX_ENTITY_HISTORY;i++)
359         {
360                 if (!d->commit[i].numentities)
361                 {
362                         d->currentcommit = d->commit + i;
363                         d->currentcommit->framenum = framenum;
364                         d->currentcommit->numentities = 0;
365                 }
366         }
367         if (d->currentcommit == NULL)
368         {
369                 Con_Printf("EntityFrame4_CL_ReadFrame: error while decoding frame %i: database full, reading but not storing this update\n", framenum);
370                 skip = true;
371         }
372         done = false;
373         while (!done && !cl_message.badread)
374         {
375                 // read the number of the modified entity
376                 // (gaps will be copied unmodified)
377                 n = (unsigned short)MSG_ReadShort(&cl_message);
378                 if (n == 0x8000)
379                 {
380                         // no more entities in this update, but we still need to copy the
381                         // rest of the reference entities (final gap)
382                         done = true;
383                         // read end of range number, then process normally
384                         n = (unsigned short)MSG_ReadShort(&cl_message);
385                 }
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))
390                 {
391                         cl.num_entities = cnumber + 1;
392                         if (cnumber >= cl.max_entities)
393                                 CL_ExpandEntities(cnumber);
394                 }
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++)
399                 {
400                         if (skip || enumber >= cl.num_entities)
401                         {
402                                 if (enumber == cnumber && (n & 0x8000) == 0)
403                                 {
404                                         entity_state_t tempstate;
405                                         EntityState_ReadFields(&tempstate, EntityState_ReadExtendBits());
406                                 }
407                                 continue;
408                         }
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)
416                         {
417                                 if (n & 0x8000)
418                                 {
419                                         // simply removed
420                                         if (developer_networkentities.integer >= 2)
421                                                 Con_Printf("entity %i: remove\n", enumber);
422                                         *s = defaultstate;
423                                 }
424                                 else
425                                 {
426                                         // read the changes
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());
431                                 }
432                         }
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)
440                         s->number = enumber;
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)
449                         {
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);
454                         }
455                 }
456         }
457         d->currentcommit = NULL;
458         if (skip)
459                 EntityFrame4_ResetDatabase(d);
460 }
461
462 qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t **states)
463 {
464         prvm_prog_t *prog = SVVM_prog;
465         const entity_state_t *e, *s;
466         entity_state_t inactiveentitystate;
467         int i, n, startnumber;
468         sizebuf_t buf;
469         unsigned char data[128];
470
471         // if there isn't enough space to accomplish anything, skip it
472         if (msg->cursize + 24 > maxsize)
473                 return false;
474
475         // prepare the buffer
476         memset(&buf, 0, sizeof(buf));
477         buf.data = data;
478         buf.maxsize = sizeof(data);
479
480         for (i = 0;i < MAX_ENTITY_HISTORY;i++)
481                 if (!d->commit[i].numentities)
482                         break;
483         // if commit buffer full, just don't bother writing an update this frame
484         if (i == MAX_ENTITY_HISTORY)
485                 return false;
486         d->currentcommit = d->commit + i;
487
488         // this state's number gets played around with later
489         inactiveentitystate = defaultstate;
490
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)
497         {
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);
502                 Con_Print(")\n");
503         }
504         if (d->currententitynumber >= prog->max_edicts)
505                 startnumber = 1;
506         else
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++)
513         {
514                 if (PRVM_serveredictfunction((&prog->edicts[n]), SendEntity))
515                         continue;
516                 // find the old state to delta from
517                 e = EntityFrame4_GetReferenceEntity(d, n);
518                 // prepare the buffer
519                 SZ_Clear(&buf);
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++);
523                 // make the message
524                 s = states[i];
525                 if (s->number == n)
526                 {
527                         // build the update
528                         EntityState_WriteUpdate(s, &buf, e);
529                 }
530                 else
531                 {
532                         inactiveentitystate.number = n;
533                         s = &inactiveentitystate;
534                         if (e->active == ACTIVE_NETWORK)
535                         {
536                                 // entity used to exist but doesn't anymore, send remove
537                                 MSG_WriteShort(&buf, n | 0x8000);
538                         }
539                 }
540                 // if the commit is full, we're done this frame
541                 if (msg->cursize + buf.cursize > maxsize - 4)
542                 {
543                         // next frame we will continue where we left off
544                         break;
545                 }
546                 // add the entity to the commit
547                 EntityFrame4_AddCommitEntity(d, s);
548                 // if the message is empty, skip out now
549                 if (buf.cursize)
550                 {
551                         // write the message to the packet
552                         SZ_Write(msg, buf.data, buf.cursize);
553                 }
554         }
555         d->currententitynumber = n;
556
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);
561         // just to be sure
562         d->currentcommit = NULL;
563
564         return true;
565 }