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