• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright (C) 1996-1997 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 #include "quakedef.h"
21 #include "winquake.h"
22 
23 cvar_t	cl_nopred = CVAR2("cl_nopred","0");
24 cvar_t	cl_pushlatency = CVAR2("pushlatency","-999");
25 
26 extern	frame_t		*view_frame;
27 
28 /*
29 =================
30 CL_NudgePosition
31 
32 If pmove.origin is in a solid position,
33 try nudging slightly on all axis to
34 allow for the cut precision of the net coordinates
35 =================
36 */
CL_NudgePosition(void)37 void CL_NudgePosition (void)
38 {
39 	vec3_t	base;
40 	int		x, y;
41 
42 	if (PM_HullPointContents (&cl.model_precache[1]->hulls[1], 0, pmove.origin) == CONTENTS_EMPTY)
43 		return;
44 
45 	VectorCopy (pmove.origin, base);
46 	for (x=-1 ; x<=1 ; x++)
47 	{
48 		for (y=-1 ; y<=1 ; y++)
49 		{
50 			pmove.origin[0] = base[0] + x * 1.0/8;
51 			pmove.origin[1] = base[1] + y * 1.0/8;
52 			if (PM_HullPointContents (&cl.model_precache[1]->hulls[1], 0, pmove.origin) == CONTENTS_EMPTY)
53 				return;
54 		}
55 	}
56 	Con_DPrintf ("CL_NudgePosition: stuck\n");
57 }
58 
59 /*
60 ==============
61 CL_PredictUsercmd
62 ==============
63 */
CL_PredictUsercmd(player_state_t * from,player_state_t * to,usercmd_t * u,qboolean spectator)64 void CL_PredictUsercmd (player_state_t *from, player_state_t *to, usercmd_t *u, qboolean spectator)
65 {
66 	// split up very long moves
67 	if (u->msec > 50)
68 	{
69 		player_state_t	temp;
70 		usercmd_t	split;
71 
72 		split = *u;
73 		split.msec /= 2;
74 
75 		CL_PredictUsercmd (from, &temp, &split, spectator);
76 		CL_PredictUsercmd (&temp, to, &split, spectator);
77 		return;
78 	}
79 
80 	VectorCopy (from->origin, pmove.origin);
81 //	VectorCopy (from->viewangles, pmove.angles);
82 	VectorCopy (u->angles, pmove.angles);
83 	VectorCopy (from->velocity, pmove.velocity);
84 
85 	pmove.oldbuttons = from->oldbuttons;
86 	pmove.waterjumptime = from->waterjumptime;
87 	pmove.dead = cl.stats[STAT_HEALTH] <= 0;
88 	pmove.spectator = spectator;
89 
90 	pmove.cmd = *u;
91 
92 	PlayerMove ();
93 //for (i=0 ; i<3 ; i++)
94 //pmove.origin[i] = ((int)(pmove.origin[i]*8))*0.125;
95 	to->waterjumptime = pmove.waterjumptime;
96 	to->oldbuttons = pmove.cmd.buttons;
97 	VectorCopy (pmove.origin, to->origin);
98 	VectorCopy (pmove.angles, to->viewangles);
99 	VectorCopy (pmove.velocity, to->velocity);
100 	to->onground = onground;
101 
102 	to->weaponframe = from->weaponframe;
103 }
104 
105 
106 
107 /*
108 ==============
109 CL_PredictMove
110 ==============
111 */
CL_PredictMove(void)112 void CL_PredictMove (void)
113 {
114 	int			i;
115 	float		f;
116 	frame_t		*from, *to = NULL;
117 	int			oldphysent;
118 
119 	if (cl_pushlatency.value > 0)
120 		Cvar_Set ("pushlatency", "0");
121 
122 	if (cl.paused)
123 		return;
124 
125 	cl.time = realtime - cls.latency - cl_pushlatency.value*0.001;
126 	if (cl.time > realtime)
127 		cl.time = realtime;
128 
129 	if (cl.intermission)
130 		return;
131 
132 	if (!cl.validsequence)
133 		return;
134 
135 	if (cls.netchan.outgoing_sequence - cls.netchan.incoming_sequence >= UPDATE_BACKUP-1)
136 		return;
137 
138 	VectorCopy (cl.viewangles, cl.simangles);
139 
140 	// this is the last frame received from the server
141 	from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
142 
143 	// we can now render a frame
144 	if (cls.state == ca_onserver)
145 	{	// first update is the final signon stage
146 		char		text[1024];
147 
148 		cls.state = ca_active;
149 		sprintf (text, "QuakeWorld: %s", cls.servername);
150 #ifdef _WIN32
151 		SetWindowText (mainwindow, text);
152 #endif
153 	}
154 
155 	if (cl_nopred.value)
156 	{
157 		VectorCopy (from->playerstate[cl.playernum].velocity, cl.simvel);
158 		VectorCopy (from->playerstate[cl.playernum].origin, cl.simorg);
159 		return;
160 	}
161 
162 	// predict forward until cl.time <= to->senttime
163 	oldphysent = pmove.numphysent;
164 	CL_SetSolidPlayers (cl.playernum);
165 
166 //	to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
167 
168 	for (i=1 ; i<UPDATE_BACKUP-1 && cls.netchan.incoming_sequence+i <
169 			cls.netchan.outgoing_sequence; i++)
170 	{
171 		to = &cl.frames[(cls.netchan.incoming_sequence+i) & UPDATE_MASK];
172 		CL_PredictUsercmd (&from->playerstate[cl.playernum]
173 			, &to->playerstate[cl.playernum], &to->cmd, cl.spectator);
174 		if (to->senttime >= cl.time)
175 			break;
176 		from = to;
177 	}
178 
179 	pmove.numphysent = oldphysent;
180 
181 	if (i == UPDATE_BACKUP-1 || !to)
182 		return;		// net hasn't deliver packets in a long time...
183 
184 	// now interpolate some fraction of the final frame
185 	if (to->senttime == from->senttime)
186 		f = 0;
187 	else
188 	{
189 		f = (cl.time - from->senttime) / (to->senttime - from->senttime);
190 
191 		if (f < 0)
192 			f = 0;
193 		if (f > 1)
194 			f = 1;
195 	}
196 
197 	for (i=0 ; i<3 ; i++)
198 		if ( fabs(from->playerstate[cl.playernum].origin[i] - to->playerstate[cl.playernum].origin[i]) > 128)
199 		{	// teleported, so don't lerp
200 			VectorCopy (to->playerstate[cl.playernum].velocity, cl.simvel);
201 			VectorCopy (to->playerstate[cl.playernum].origin, cl.simorg);
202 			return;
203 		}
204 
205 	for (i=0 ; i<3 ; i++)
206 	{
207 		cl.simorg[i] = from->playerstate[cl.playernum].origin[i]
208 			+ f*(to->playerstate[cl.playernum].origin[i] - from->playerstate[cl.playernum].origin[i]);
209 		cl.simvel[i] = from->playerstate[cl.playernum].velocity[i]
210 			+ f*(to->playerstate[cl.playernum].velocity[i] - from->playerstate[cl.playernum].velocity[i]);
211 	}
212 }
213 
214 
215 /*
216 ==============
217 CL_InitPrediction
218 ==============
219 */
CL_InitPrediction(void)220 void CL_InitPrediction (void)
221 {
222 	Cvar_RegisterVariable (&cl_pushlatency);
223 	Cvar_RegisterVariable (&cl_nopred);
224 }
225 
226