1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 #include "client.h"
22 
23 
24 /*
25 ===================
26 CL_CheckPredictionError
27 ===================
28 */
CL_CheckPredictionError(void)29 void CL_CheckPredictionError (void)
30 {
31 	int		frame;
32 	int		delta[3];
33 	int		i;
34 	int		len;
35 
36 	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
37 		return;
38 
39 	// calculate the last usercmd_t we sent that the server has processed
40 	frame = cls.netchan.incoming_acknowledged;
41 	frame &= (CMD_BACKUP-1);
42 
43 	// compare what the server returned with what we had predicted it to be
44 	VectorSubtract (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame], delta);
45 
46 	// save the prediction error for interpolation
47 	len = abs(delta[0]) + abs(delta[1]) + abs(delta[2]);
48 	if (len > 640)	// 80 world units
49 	{	// a teleport or something
50 		VectorClear (cl.prediction_error);
51 	}
52 	else
53 	{
54 		if (cl_showmiss->value && (delta[0] || delta[1] || delta[2]) )
55 			Com_Printf ("prediction miss on %i: %i\n", cl.frame.serverframe,
56 			delta[0] + delta[1] + delta[2]);
57 
58 		VectorCopy (cl.frame.playerstate.pmove.origin, cl.predicted_origins[frame]);
59 
60 		// save for error itnerpolation
61 		for (i=0 ; i<3 ; i++)
62 			cl.prediction_error[i] = delta[i]*0.125;
63 	}
64 }
65 
66 
67 /*
68 ====================
69 CL_ClipMoveToEntities
70 
71 ====================
72 */
CL_ClipMoveToEntities(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,trace_t * tr)73 void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr )
74 {
75 	int			i, x, zd, zu;
76 	trace_t		trace;
77 	int			headnode;
78 	float		*angles;
79 	entity_state_t	*ent;
80 	int			num;
81 	cmodel_t		*cmodel;
82 	vec3_t		bmins, bmaxs;
83 
84 	for (i=0 ; i<cl.frame.num_entities ; i++)
85 	{
86 		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
87 		ent = &cl_parse_entities[num];
88 
89 		if (!ent->solid)
90 			continue;
91 
92 		if (ent->number == cl.playernum+1)
93 			continue;
94 
95 		if (ent->solid == 31)
96 		{	// special value for bmodel
97 			cmodel = cl.model_clip[ent->modelindex];
98 			if (!cmodel)
99 				continue;
100 			headnode = cmodel->headnode;
101 			angles = ent->angles;
102 		}
103 		else
104 		{	// encoded bbox
105 			x = 8*(ent->solid & 31);
106 			zd = 8*((ent->solid>>5) & 31);
107 			zu = 8*((ent->solid>>10) & 63) - 32;
108 
109 			bmins[0] = bmins[1] = -x;
110 			bmaxs[0] = bmaxs[1] = x;
111 			bmins[2] = -zd;
112 			bmaxs[2] = zu;
113 
114 			headnode = CM_HeadnodeForBox (bmins, bmaxs);
115 			angles = vec3_origin;	// boxes don't rotate
116 		}
117 
118 		if (tr->allsolid)
119 			return;
120 
121 		trace = CM_TransformedBoxTrace (start, end,
122 			mins, maxs, headnode,  MASK_PLAYERSOLID,
123 			ent->origin, angles);
124 
125 		if (trace.allsolid || trace.startsolid ||
126 		trace.fraction < tr->fraction)
127 		{
128 			trace.ent = (struct edict_s *)ent;
129 		 	if (tr->startsolid)
130 			{
131 				*tr = trace;
132 				tr->startsolid = true;
133 			}
134 			else
135 				*tr = trace;
136 		}
137 		else if (trace.startsolid)
138 			tr->startsolid = true;
139 	}
140 }
141 
142 
143 /*
144 ================
145 CL_PMTrace
146 ================
147 */
CL_PMTrace(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end)148 trace_t		CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
149 {
150 	trace_t	t;
151 
152 	// check against world
153 	t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID);
154 	if (t.fraction < 1.0)
155 		t.ent = (struct edict_s *)1;
156 
157 	// check all other solid models
158 	CL_ClipMoveToEntities (start, mins, maxs, end, &t);
159 
160 	return t;
161 }
162 
CL_PMpointcontents(vec3_t point)163 int		CL_PMpointcontents (vec3_t point)
164 {
165 	int			i;
166 	entity_state_t	*ent;
167 	int			num;
168 	cmodel_t		*cmodel;
169 	int			contents;
170 
171 	contents = CM_PointContents (point, 0);
172 
173 	for (i=0 ; i<cl.frame.num_entities ; i++)
174 	{
175 		num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
176 		ent = &cl_parse_entities[num];
177 
178 		if (ent->solid != 31) // special value for bmodel
179 			continue;
180 
181 		cmodel = cl.model_clip[ent->modelindex];
182 		if (!cmodel)
183 			continue;
184 
185 		contents |= CM_TransformedPointContents (point, cmodel->headnode, ent->origin, ent->angles);
186 	}
187 
188 	return contents;
189 }
190 
191 
192 /*
193 =================
194 CL_PredictMovement
195 
196 Sets cl.predicted_origin and cl.predicted_angles
197 =================
198 */
CL_PredictMovement(void)199 void CL_PredictMovement (void)
200 {
201 	int			ack, current;
202 	int			frame;
203 	int			oldframe;
204 	usercmd_t	*cmd;
205 	pmove_t		pm;
206 	int			i;
207 	int			step;
208 	int			oldz;
209 
210 	if (cls.state != ca_active)
211 		return;
212 
213 	if (cl_paused->value)
214 		return;
215 
216 	if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
217 	{	// just set angles
218 		for (i=0 ; i<3 ; i++)
219 		{
220 			cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
221 		}
222 		return;
223 	}
224 
225 	ack = cls.netchan.incoming_acknowledged;
226 	current = cls.netchan.outgoing_sequence;
227 
228 	// if we are too far out of date, just freeze
229 	if (current - ack >= CMD_BACKUP)
230 	{
231 		if (cl_showmiss->value)
232 			Com_Printf ("exceeded CMD_BACKUP\n");
233 		return;
234 	}
235 
236 	// copy current state to pmove
237 	memset (&pm, 0, sizeof(pm));
238 	pm.trace = CL_PMTrace;
239 	pm.pointcontents = CL_PMpointcontents;
240 
241 	pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
242 
243 	pm.s = cl.frame.playerstate.pmove;
244 
245 //	SCR_DebugGraph (current - ack - 1, 0);
246 
247 	frame = 0;
248 
249 	// run frames
250 	while (++ack < current)
251 	{
252 		frame = ack & (CMD_BACKUP-1);
253 		cmd = &cl.cmds[frame];
254 
255 		pm.cmd = *cmd;
256 		Pmove (&pm);
257 
258 		// save for debug checking
259 		VectorCopy (pm.s.origin, cl.predicted_origins[frame]);
260 	}
261 
262 	oldframe = (ack-2) & (CMD_BACKUP-1);
263 	oldz = cl.predicted_origins[oldframe][2];
264 	step = pm.s.origin[2] - oldz;
265 	if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) )
266 	{
267 		cl.predicted_step = step * 0.125;
268 		cl.predicted_step_time = cls.realtime - cls.frametime * 500;
269 	}
270 
271 
272 	// copy results out for rendering
273 	cl.predicted_origin[0] = pm.s.origin[0]*0.125;
274 	cl.predicted_origin[1] = pm.s.origin[1]*0.125;
275 	cl.predicted_origin[2] = pm.s.origin[2]*0.125;
276 
277 	VectorCopy (pm.viewangles, cl.predicted_angles);
278 }
279