]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/csqcmodel/cl_player.qc
remove TEMPHACK_origin
[xonotic/xonotic-data.pk3dir.git] / qcsrc / csqcmodel / cl_player.qc
1 /*
2  * Copyright (c) 2011 Rudolf Polzer
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22
23 var float autocvar_cl_predictionerrorcompensation = 0;
24 var float autocvar_cl_movement_replay;
25 var float autocvar_chase_active;
26 var float autocvar_chase_back;
27
28 .float pmove_flags;
29
30 entity csqcplayer;
31 vector csqcplayer_origin, csqcplayer_velocity;
32 float csqcplayer_sequence, player_pmflags;
33 float csqcplayer_moveframe;
34 vector csqcplayer_predictionerror;
35 float csqcplayer_predictionerrortime;
36
37 vector CSQCPlayer_GetPredictionError()
38 {
39         if(!autocvar_cl_predictionerrorcompensation)
40                 return '0 0 0';
41         if(time < csqcplayer_predictionerrortime)
42                 return csqcplayer_predictionerror * (csqcplayer_predictionerrortime - time) * autocvar_cl_predictionerrorcompensation;
43         return '0 0 0';
44 }
45
46 void CSQCPlayer_SetPredictionError(vector v)
47 {
48         if(!autocvar_cl_predictionerrorcompensation)
49                 return;
50         csqcplayer_predictionerror = (csqcplayer_predictionerrortime - time) * autocvar_cl_predictionerrorcompensation * csqcplayer_predictionerror + v;
51         csqcplayer_predictionerrortime = time + 1.0 / autocvar_cl_predictionerrorcompensation;
52 }
53
54 void CSQCPlayer_Unpredict()
55 {
56         if(csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED)
57                 return;
58         if(csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED)
59                 error("Cannot unpredict in current status");
60         self.origin = csqcplayer_origin;
61         self.velocity = csqcplayer_velocity;
62         csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
63         self.pmove_flags = player_pmflags;
64 }
65
66 void CSQCPlayer_SavePrediction()
67 {
68         player_pmflags = self.pmove_flags;
69         csqcplayer_origin = self.origin;
70         csqcplayer_velocity = self.velocity;
71         csqcplayer_sequence = servercommandframe;
72         csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
73 }
74
75 void CSQCPlayer_PredictTo(float endframe)
76 {
77         CSQCPlayer_Unpredict();
78
79         csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
80
81         if (getstatf(STAT_HEALTH) <= 0)
82         {
83                 csqcplayer_moveframe = clientcommandframe;
84                 getinputstate(csqcplayer_moveframe-1);
85                 return;
86         }
87
88         while(csqcplayer_moveframe < endframe)
89         {
90                 if (!getinputstate(csqcplayer_moveframe))
91                 {
92                         break;
93                 }
94                 runstandardplayerphysics(self);
95
96                 csqcplayer_moveframe++;
97         }
98
99         //add in anything that was applied after (for low packet rate protocols)
100         input_angles = view_angles;
101 }
102
103 float CSQCPlayer_IsLocalPlayer()
104 {
105         return (self == csqcplayer);
106 }
107
108 void CSQCPlayer_SetCamera()
109 {
110         if(csqcplayer)
111         {
112                 vector org, ang;
113                 entity oldself;
114                 oldself = self;
115                 self = csqcplayer;
116
117                 if(servercommandframe == 0)
118                 {
119                         InterpolateOrigin_Do();
120                 }
121                 else
122                 {
123                         if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
124                         {
125                                 vector o, v;
126                                 o = self.origin;
127                                 v = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
128                                 csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
129                                 CSQCPlayer_PredictTo(servercommandframe + 1);
130                                 CSQCPlayer_SetPredictionError(o - self.origin);
131                                 self.origin = o;
132                                 self.velocity = v;
133                                 CSQCPlayer_SavePrediction();
134                         }
135                         CSQCPlayer_PredictTo(clientcommandframe);
136                 }
137
138                 self = oldself;
139
140                 org = csqcplayer.origin + '0 0 1' * getstatf(STAT_VIEWHEIGHT) + CSQCPlayer_GetPredictionError();
141                 ang = R_SetView3fv(VF_ANGLES);
142
143                 // simulate missing engine features
144                 if(autocvar_chase_active)
145                 {
146                         float dist;
147                         vector chase_dest;
148                         dist = -autocvar_chase_back - 8;
149                         makevectors(ang);
150                         chase_dest = org + v_forward * dist;
151                         traceline(org, chase_dest, MOVE_NOMONSTERS, csqcplayer);
152                         org = trace_endpos + 8 * v_forward + 4 * trace_plane_normal;
153                 }
154
155                 R_SetView3fv(VF_ORIGIN, org);
156                 R_SetView3fv(VF_ANGLES, ang);
157         }
158 }
159
160 float CSQCPlayer_PreUpdate()
161 {
162         if(self.entnum != player_localentnum)
163                 return 0;
164         cvar_clientsettemp("cl_movement_replay", "0");
165         if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
166                 CSQCPlayer_Unpredict();
167         return 1;
168 }
169
170 float CSQCPlayer_PostUpdate()
171 {
172         if(self.entnum <= maxclients)
173                 self.renderflags |= RF_EXTERNALMODEL;
174         else
175                 self.renderflags &~= RF_EXTERNALMODEL;
176         if(self.entnum != player_localentnum)
177                 return 0;
178         csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
179         csqcplayer = self;
180         return 1;
181 }
182
183 entity CSQCPlayer_GetPlayer(float pl)
184 {
185         return findfloat(world, entnum, pl); // FIXME optimize this using an array
186 }