]> git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_ents_qw.c
Merge PR 'Make particles solid squares when cl_particles_quake is set to 2'
[xonotic/darkplaces.git] / cl_ents_qw.c
1 #include "quakedef.h"
2 #include "protocol.h"
3
4 static void QW_TranslateEffects(entity_state_t *s, int qweffects)
5 {
6         s->effects = 0;
7         s->internaleffects = 0;
8         if (qweffects & QW_EF_BRIGHTFIELD)
9                 s->effects |= EF_BRIGHTFIELD;
10         if (qweffects & QW_EF_MUZZLEFLASH)
11                 s->effects |= EF_MUZZLEFLASH;
12         if (qweffects & QW_EF_FLAG1)
13         {
14                 // mimic FTEQW's interpretation of EF_FLAG1 as EF_NODRAW on non-player entities
15                 if (s->number > cl.maxclients)
16                         s->effects |= EF_NODRAW;
17                 else
18                         s->internaleffects |= INTEF_FLAG1QW;
19         }
20         if (qweffects & QW_EF_FLAG2)
21         {
22                 // mimic FTEQW's interpretation of EF_FLAG2 as EF_ADDITIVE on non-player entities
23                 if (s->number > cl.maxclients)
24                         s->effects |= EF_ADDITIVE;
25                 else
26                         s->internaleffects |= INTEF_FLAG2QW;
27         }
28         if (qweffects & QW_EF_RED)
29         {
30                 if (qweffects & QW_EF_BLUE)
31                         s->effects |= EF_RED | EF_BLUE;
32                 else
33                         s->effects |= EF_RED;
34         }
35         else if (qweffects & QW_EF_BLUE)
36                 s->effects |= EF_BLUE;
37         else if (qweffects & QW_EF_BRIGHTLIGHT)
38                 s->effects |= EF_BRIGHTLIGHT;
39         else if (qweffects & QW_EF_DIMLIGHT)
40                 s->effects |= EF_DIMLIGHT;
41 }
42
43 extern cvar_t cl_rollangle;
44 extern cvar_t cl_rollspeed;
45
46 void EntityStateQW_ReadPlayerUpdate(void)
47 {
48         int slot = MSG_ReadByte(&cl_message);
49         int enumber = slot + 1;
50         int weaponframe;
51         int msec;
52         int playerflags;
53         int bits;
54         entity_state_t *s;
55         // look up the entity
56         entity_t *ent = cl.entities + enumber;
57         vec3_t viewangles;
58         vec3_t velocity;
59
60         // slide the current state into the previous
61         ent->state_previous = ent->state_current;
62
63         // read the update
64         s = &ent->state_current;
65         *s = defaultstate;
66         s->active = ACTIVE_NETWORK;
67         s->number = enumber;
68         s->colormap = enumber;
69         playerflags = MSG_ReadShort(&cl_message);
70         MSG_ReadVector(&cl_message, s->origin, cls.protocol);
71         s->frame = MSG_ReadByte(&cl_message);
72
73         VectorClear(viewangles);
74         VectorClear(velocity);
75
76         if (playerflags & QW_PF_MSEC)
77         {
78                 // time difference between last update this player sent to the server,
79                 // and last input we sent to the server (this packet is in response to
80                 // our input, so msec is how long ago the last update of this player
81                 // entity occurred, compared to our input being received)
82                 msec = MSG_ReadByte(&cl_message);
83         }
84         else
85                 msec = 0;
86         if (playerflags & QW_PF_COMMAND)
87         {
88                 bits = MSG_ReadByte(&cl_message);
89                 if (bits & QW_CM_ANGLE1)
90                         viewangles[0] = MSG_ReadAngle16i(&cl_message); // cmd->angles[0]
91                 if (bits & QW_CM_ANGLE2)
92                         viewangles[1] = MSG_ReadAngle16i(&cl_message); // cmd->angles[1]
93                 if (bits & QW_CM_ANGLE3)
94                         viewangles[2] = MSG_ReadAngle16i(&cl_message); // cmd->angles[2]
95                 if (bits & QW_CM_FORWARD)
96                         MSG_ReadShort(&cl_message); // cmd->forwardmove
97                 if (bits & QW_CM_SIDE)
98                         MSG_ReadShort(&cl_message); // cmd->sidemove
99                 if (bits & QW_CM_UP)
100                         MSG_ReadShort(&cl_message); // cmd->upmove
101                 if (bits & QW_CM_BUTTONS)
102                         (void) MSG_ReadByte(&cl_message); // cmd->buttons
103                 if (bits & QW_CM_IMPULSE)
104                         (void) MSG_ReadByte(&cl_message); // cmd->impulse
105                 (void) MSG_ReadByte(&cl_message); // cmd->msec
106         }
107         if (playerflags & QW_PF_VELOCITY1)
108                 velocity[0] = MSG_ReadShort(&cl_message);
109         if (playerflags & QW_PF_VELOCITY2)
110                 velocity[1] = MSG_ReadShort(&cl_message);
111         if (playerflags & QW_PF_VELOCITY3)
112                 velocity[2] = MSG_ReadShort(&cl_message);
113         if (playerflags & QW_PF_MODEL)
114                 s->modelindex = MSG_ReadByte(&cl_message);
115         else
116                 s->modelindex = cl.qw_modelindex_player;
117         if (playerflags & QW_PF_SKINNUM)
118                 s->skin = MSG_ReadByte(&cl_message);
119         if (playerflags & QW_PF_EFFECTS)
120                 QW_TranslateEffects(s, MSG_ReadByte(&cl_message));
121         if (playerflags & QW_PF_WEAPONFRAME)
122                 weaponframe = MSG_ReadByte(&cl_message);
123         else
124                 weaponframe = 0;
125
126         if (enumber == cl.playerentity)
127         {
128                 // if this is an update on our player, update the angles
129                 VectorCopy(cl.viewangles, viewangles);
130         }
131
132         // calculate the entity angles from the viewangles
133         s->angles[0] = viewangles[0] * -0.0333;
134         s->angles[1] = viewangles[1];
135         s->angles[2] = 0;
136         s->angles[2] = Com_CalcRoll(s->angles, velocity, cl_rollangle.value, cl_rollspeed.value)*4;
137
138         // if this is an update on our player, update interpolation state
139         if (enumber == cl.playerentity)
140         {
141                 VectorCopy (cl.mpunchangle[0], cl.mpunchangle[1]);
142                 VectorCopy (cl.mpunchvector[0], cl.mpunchvector[1]);
143                 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
144                 cl.mviewzoom[1] = cl.mviewzoom[0];
145
146                 cl.idealpitch = 0;
147                 cl.mpunchangle[0][0] = 0;
148                 cl.mpunchangle[0][1] = 0;
149                 cl.mpunchangle[0][2] = 0;
150                 cl.mpunchvector[0][0] = 0;
151                 cl.mpunchvector[0][1] = 0;
152                 cl.mpunchvector[0][2] = 0;
153                 cl.mvelocity[0][0] = 0;
154                 cl.mvelocity[0][1] = 0;
155                 cl.mvelocity[0][2] = 0;
156                 cl.mviewzoom[0] = 1;
157
158                 VectorCopy(velocity, cl.mvelocity[0]);
159                 cl.stats[STAT_WEAPONFRAME] = weaponframe;
160                 if (playerflags & QW_PF_GIB)
161                         cl.stats[STAT_VIEWHEIGHT] = 8;
162                 else if (playerflags & QW_PF_DEAD)
163                         cl.stats[STAT_VIEWHEIGHT] = -16;
164                 else
165                         cl.stats[STAT_VIEWHEIGHT] = 22;
166         }
167
168         // set the cl.entities_active flag
169         cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK);
170         // set the update time
171         s->time = cl.mtime[0] - msec * 0.001; // qw has no clock
172         // check if we need to update the lerp stuff
173         if (s->active == ACTIVE_NETWORK)
174                 CL_MoveLerpEntityStates(&cl.entities[enumber]);
175 }
176
177 static void EntityStateQW_ReadEntityUpdate(entity_state_t *s, int bits)
178 {
179         int qweffects = 0;
180         s->active = ACTIVE_NETWORK;
181         s->number = bits & 511;
182         bits &= ~511;
183         if (bits & QW_U_MOREBITS)
184                 bits |= MSG_ReadByte(&cl_message);
185
186         // store the QW_U_SOLID bit here?
187
188         if (bits & QW_U_MODEL)
189                 s->modelindex = MSG_ReadByte(&cl_message);
190         if (bits & QW_U_FRAME)
191                 s->frame = MSG_ReadByte(&cl_message);
192         if (bits & QW_U_COLORMAP)
193                 s->colormap = MSG_ReadByte(&cl_message);
194         if (bits & QW_U_SKIN)
195                 s->skin = MSG_ReadByte(&cl_message);
196         if (bits & QW_U_EFFECTS)
197                 QW_TranslateEffects(s, qweffects = MSG_ReadByte(&cl_message));
198         if (bits & QW_U_ORIGIN1)
199                 s->origin[0] = MSG_ReadCoord13i(&cl_message);
200         if (bits & QW_U_ANGLE1)
201                 s->angles[0] = MSG_ReadAngle8i(&cl_message);
202         if (bits & QW_U_ORIGIN2)
203                 s->origin[1] = MSG_ReadCoord13i(&cl_message);
204         if (bits & QW_U_ANGLE2)
205                 s->angles[1] = MSG_ReadAngle8i(&cl_message);
206         if (bits & QW_U_ORIGIN3)
207                 s->origin[2] = MSG_ReadCoord13i(&cl_message);
208         if (bits & QW_U_ANGLE3)
209                 s->angles[2] = MSG_ReadAngle8i(&cl_message);
210
211         if (developer_networkentities.integer >= 2)
212         {
213                 Con_Printf("ReadFields e%i", s->number);
214                 if (bits & QW_U_MODEL)
215                         Con_Printf(" U_MODEL %i", s->modelindex);
216                 if (bits & QW_U_FRAME)
217                         Con_Printf(" U_FRAME %i", s->frame);
218                 if (bits & QW_U_COLORMAP)
219                         Con_Printf(" U_COLORMAP %i", s->colormap);
220                 if (bits & QW_U_SKIN)
221                         Con_Printf(" U_SKIN %i", s->skin);
222                 if (bits & QW_U_EFFECTS)
223                         Con_Printf(" U_EFFECTS %i", qweffects);
224                 if (bits & QW_U_ORIGIN1)
225                         Con_Printf(" U_ORIGIN1 %f", s->origin[0]);
226                 if (bits & QW_U_ANGLE1)
227                         Con_Printf(" U_ANGLE1 %f", s->angles[0]);
228                 if (bits & QW_U_ORIGIN2)
229                         Con_Printf(" U_ORIGIN2 %f", s->origin[1]);
230                 if (bits & QW_U_ANGLE2)
231                         Con_Printf(" U_ANGLE2 %f", s->angles[1]);
232                 if (bits & QW_U_ORIGIN3)
233                         Con_Printf(" U_ORIGIN3 %f", s->origin[2]);
234                 if (bits & QW_U_ANGLE3)
235                         Con_Printf(" U_ANGLE3 %f", s->angles[2]);
236                 if (bits & QW_U_SOLID)
237                         Con_Printf(" U_SOLID");
238                 Con_Print("\n");
239         }
240 }
241
242 entityframeqw_database_t *EntityFrameQW_AllocDatabase(mempool_t *pool)
243 {
244         entityframeqw_database_t *d;
245         d = (entityframeqw_database_t *)Mem_Alloc(pool, sizeof(*d));
246         return d;
247 }
248
249 void EntityFrameQW_FreeDatabase(entityframeqw_database_t *d)
250 {
251         Mem_Free(d);
252 }
253
254 void EntityFrameQW_CL_ReadFrame(qbool delta)
255 {
256         qbool invalid = false;
257         int number, oldsnapindex, newsnapindex, oldindex, newindex, oldnum, newnum;
258         entity_t *ent;
259         entityframeqw_database_t *d;
260         entityframeqw_snapshot_t *oldsnap, *newsnap;
261
262         if (!cl.entitydatabaseqw)
263                 cl.entitydatabaseqw = EntityFrameQW_AllocDatabase(cls.levelmempool);
264         d = cl.entitydatabaseqw;
265
266         // there is no cls.netcon in demos, so this reading code can't access
267         // cls.netcon-> at all...  so cls.qw_incoming_sequence and
268         // cls.qw_outgoing_sequence are updated every time the corresponding
269         // cls.netcon->qw. variables are updated
270         // read the number of this frame to echo back in next input packet
271         cl.qw_validsequence = cls.qw_incoming_sequence;
272         newsnapindex = cl.qw_validsequence & QW_UPDATE_MASK;
273         newsnap = d->snapshot + newsnapindex;
274         memset(newsnap, 0, sizeof(*newsnap));
275         oldsnap = NULL;
276         if (delta)
277         {
278                 number = MSG_ReadByte(&cl_message);
279                 oldsnapindex = cl.qw_deltasequence[newsnapindex];
280                 if ((number & QW_UPDATE_MASK) != (oldsnapindex & QW_UPDATE_MASK))
281                         Con_DPrintf("WARNING: from mismatch\n");
282                 if (oldsnapindex != -1)
283                 {
284                         if (cls.qw_outgoing_sequence - oldsnapindex >= QW_UPDATE_BACKUP-1)
285                         {
286                                 Con_DPrintf("delta update too old\n");
287                                 newsnap->invalid = invalid = true; // too old
288                                 delta = false;
289                         }
290                         oldsnap = d->snapshot + (oldsnapindex & QW_UPDATE_MASK);
291                 }
292                 else
293                         delta = false;
294         }
295
296         // if we can't decode this frame properly, report that to the server
297         if (invalid)
298                 cl.qw_validsequence = 0;
299
300         // read entity numbers until we find a 0x0000
301         // (which would be an empty update on world entity, but is actually a terminator)
302         newsnap->num_entities = 0;
303         oldindex = 0;
304         for (;;)
305         {
306                 int word = (unsigned short)MSG_ReadShort(&cl_message);
307                 if (cl_message.badread)
308                         return; // just return, the main parser will print an error
309                 newnum = word == 0 ? 512 : (word & 511);
310                 oldnum = delta ? (oldindex >= oldsnap->num_entities ? 9999 : oldsnap->entities[oldindex].number) : 9999;
311
312                 // copy unmodified oldsnap entities
313                 while (newnum > oldnum) // delta only
314                 {
315                         if (developer_networkentities.integer >= 2)
316                                 Con_Printf("copy %i\n", oldnum);
317                         // copy one of the old entities
318                         if (newsnap->num_entities >= QW_MAX_PACKET_ENTITIES)
319                                 Host_Error("EntityFrameQW_CL_ReadFrame: newsnap->num_entities == MAX_PACKETENTITIES");
320                         newsnap->entities[newsnap->num_entities] = oldsnap->entities[oldindex++];
321                         newsnap->num_entities++;
322                         oldnum = oldindex >= oldsnap->num_entities ? 9999 : oldsnap->entities[oldindex].number;
323                 }
324
325                 if (word == 0)
326                         break;
327
328                 if (developer_networkentities.integer >= 2)
329                 {
330                         if (word & QW_U_REMOVE)
331                                 Con_Printf("remove %i\n", newnum);
332                         else if (newnum == oldnum)
333                                 Con_Printf("delta %i\n", newnum);
334                         else
335                                 Con_Printf("baseline %i\n", newnum);
336                 }
337
338                 if (word & QW_U_REMOVE)
339                 {
340                         if (newnum != oldnum && !delta && !invalid)
341                         {
342                                 cl.qw_validsequence = 0;
343                                 Con_Printf(CON_WARN "WARNING: U_REMOVE %i on full update\n", newnum);
344                         }
345                 }
346                 else
347                 {
348                         if (newsnap->num_entities >= QW_MAX_PACKET_ENTITIES)
349                                 Host_Error("EntityFrameQW_CL_ReadFrame: newsnap->num_entities == MAX_PACKETENTITIES");
350                         newsnap->entities[newsnap->num_entities] = (newnum == oldnum) ? oldsnap->entities[oldindex] : cl.entities[newnum].state_baseline;
351                         EntityStateQW_ReadEntityUpdate(newsnap->entities + newsnap->num_entities, word);
352                         newsnap->num_entities++;
353                 }
354
355                 if (newnum == oldnum)
356                         oldindex++;
357         }
358
359         // expand cl.num_entities to include every entity we've seen this game
360         newnum = newsnap->num_entities ? newsnap->entities[newsnap->num_entities - 1].number : 1;
361         if (cl.num_entities <= newnum)
362         {
363                 cl.num_entities = newnum + 1;
364                 if (cl.max_entities < newnum + 1)
365                         CL_ExpandEntities(newnum);
366         }
367
368         // now update the non-player entities from the snapshot states
369         number = cl.maxclients + 1;
370         for (newindex = 0;;newindex++)
371         {
372                 newnum = newindex >= newsnap->num_entities ? cl.num_entities : newsnap->entities[newindex].number;
373                 // kill any missing entities
374                 for (;number < newnum;number++)
375                 {
376                         if (cl.entities_active[number])
377                         {
378                                 cl.entities_active[number] = false;
379                                 cl.entities[number].state_current.active = ACTIVE_NOT;
380                         }
381                 }
382                 if (number >= cl.num_entities)
383                         break;
384                 // update the entity
385                 ent = &cl.entities[number];
386                 ent->state_previous = ent->state_current;
387                 ent->state_current = newsnap->entities[newindex];
388                 ent->state_current.time = cl.mtime[0];
389                 CL_MoveLerpEntityStates(ent);
390                 // the entity lives again...
391                 cl.entities_active[number] = true;
392                 number++;
393         }
394 }