]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/csqcmodel/cl_player.qc
support custom properties
[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 void CSQCPlayer_SetCamera()
104 {
105         if(csqcplayer)
106         {
107                 vector org, ang;
108                 entity oldself;
109                 oldself = self;
110                 self = csqcplayer;
111
112                 if(servercommandframe == 0)
113                 {
114                         InterpolateOrigin_Do();
115                 }
116                 else
117                 {
118                         if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
119                         {
120                                 vector o, v;
121                                 o = self.origin;
122                                 v = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
123                                 csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
124                                 CSQCPlayer_PredictTo(servercommandframe + 1);
125                                 CSQCPlayer_SetPredictionError(o - self.origin);
126                                 self.origin = o;
127                                 self.velocity = v;
128                                 CSQCPlayer_SavePrediction();
129                         }
130                         CSQCPlayer_PredictTo(clientcommandframe);
131                 }
132
133                 self = oldself;
134
135                 org = csqcplayer.origin + csqcplayer.view_ofs + CSQCPlayer_GetPredictionError();
136                 ang = R_SetView3fv(VF_ANGLES);
137
138                 // simulate missing engine features
139                 if(autocvar_chase_active)
140                 {
141                         float dist;
142                         vector chase_dest;
143                         dist = -autocvar_chase_back - 8;
144                         makevectors(ang);
145                         chase_dest = org + v_forward * dist;
146                         traceline(org, chase_dest, MOVE_NOMONSTERS, csqcplayer);
147                         org = trace_endpos + 8 * v_forward + 4 * trace_plane_normal;
148                 }
149
150                 R_SetView3fv(VF_ORIGIN, org);
151                 R_SetView3fv(VF_ANGLES, ang);
152         }
153 }
154
155 float CSQCPlayer_PreUpdate()
156 {
157         if(self.entnum != player_localentnum)
158                 return 0;
159         cvar_clientsettemp("cl_movement_replay", "0");
160         if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
161                 CSQCPlayer_Unpredict();
162         return 1;
163 }
164
165 float CSQCPlayer_PostUpdate()
166 {
167         if(self.entnum <= maxclients)
168                 self.renderflags |= RF_EXTERNALMODEL;
169         else
170                 self.renderflags &~= RF_EXTERNALMODEL;
171         if(self.entnum != player_localentnum)
172                 return 0;
173         csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
174         csqcplayer = self;
175         return 1;
176 }