]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/csqcplayer.qc
split csqcmodel generic and csqcplayer specific
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / csqcplayer.qc
1 float autocvar_cl_predictionerrorcompensation = 0;
2 float autocvar_chase_active;
3 float autocvar_chase_back;
4
5 .float pmove_flags;
6
7 entity csqcplayer;
8 vector csqcplayer_origin, csqcplayer_velocity;
9 float csqcplayer_sequence, player_pmflags;
10 float csqcplayer_moveframe;
11 vector csqcplayer_predictionerror;
12 float csqcplayer_predictionerrortime;
13
14 vector CSQCPlayer_GetPredictionError()
15 {
16         if(!autocvar_cl_predictionerrorcompensation)
17                 return '0 0 0';
18         if(time < csqcplayer_predictionerrortime)
19                 return csqcplayer_predictionerror * (csqcplayer_predictionerrortime - time) * autocvar_cl_predictionerrorcompensation;
20         return '0 0 0';
21 }
22
23 void CSQCPlayer_SetPredictionError(vector v)
24 {
25         if(!autocvar_cl_predictionerrorcompensation)
26                 return;
27         csqcplayer_predictionerror = (csqcplayer_predictionerrortime - time) * autocvar_cl_predictionerrorcompensation * csqcplayer_predictionerror + v;
28         csqcplayer_predictionerrortime = time + 1.0 / autocvar_cl_predictionerrorcompensation;
29 }
30
31 void CSQCPlayer_Unpredict()
32 {
33         if(csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED)
34                 return;
35         if(csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED)
36                 error("Cannot unpredict in current status");
37         self.origin = csqcplayer_origin;
38         self.velocity = csqcplayer_velocity;
39         csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
40         self.pmove_flags = player_pmflags;
41 }
42
43 void CSQCPlayer_SavePrediction()
44 {
45         player_pmflags = self.pmove_flags;
46         csqcplayer_origin = self.origin;
47         csqcplayer_velocity = self.velocity;
48         csqcplayer_sequence = servercommandframe;
49         csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
50 }
51
52 void CSQCPlayer_PredictTo(float endframe)
53 {
54         CSQCPlayer_Unpredict();
55
56         csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
57
58         if (getstatf(STAT_HEALTH) <= 0)
59         {
60                 csqcplayer_moveframe = clientcommandframe;
61                 getinputstate(csqcplayer_moveframe-1);
62                 return;
63         }
64
65         while(csqcplayer_moveframe < endframe)
66         {
67                 if (!getinputstate(csqcplayer_moveframe))
68                 {
69                         break;
70                 }
71                 runstandardplayerphysics(self);
72
73                 csqcplayer_moveframe++;
74         }
75
76         //add in anything that was applied after (for low packet rate protocols)
77         input_angles = view_angles;
78 }
79
80 void CSQCPlayer_SetCamera()
81 {
82         if(csqcplayer)
83         {
84                 vector org, ang;
85                 entity oldself;
86                 oldself = self;
87                 self = csqcplayer;
88
89                 if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
90                 {
91                         vector o, v;
92                         o = self.origin;
93                         v = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
94                         csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
95                         CSQCPlayer_PredictTo(servercommandframe + 1);
96                         CSQCPlayer_SetPredictionError(o - self.origin);
97                         self.origin = o;
98                         self.velocity = v;
99                         CSQCPlayer_SavePrediction();
100                         CSQCPlayer_Unpredict();
101                 }
102
103                 CSQCPlayer_PredictTo(clientcommandframe);
104                 self = oldself;
105
106                 org = csqcplayer.origin + csqcplayer.view_ofs + CSQCPlayer_GetPredictionError();
107                 ang = R_SetView3fv(VF_ANGLES);
108
109                 // simulate missing engine features
110                 if(autocvar_chase_active)
111                 {
112                         float dist;
113                         vector chase_dest;
114                         dist = -autocvar_chase_back - 8;
115                         makevectors(ang);
116                         chase_dest = org + v_forward * dist;
117                         traceline(org, chase_dest, MOVE_NOMONSTERS, csqcplayer);
118                         org = trace_endpos + 8 * v_forward + 4 * trace_plane_normal;
119                 }
120
121                 R_SetView3fv(VF_ORIGIN, org);
122                 R_SetView3fv(VF_ANGLES, ang);
123         }
124 }
125
126 float CSQCPlayer_PreUpdate()
127 {
128         if(self.entnum != player_localentnum)
129                 return 0;
130         if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
131                 CSQCPlayer_Unpredict();
132         return 1;
133 }
134
135 float CSQCPlayer_PostUpdate()
136 {
137         if(self.entnum <= maxclients)
138                 self.renderflags |= RF_EXTERNALMODEL;
139         else
140                 self.renderflags &~= RF_EXTERNALMODEL;
141         if(self.entnum != player_localentnum)
142                 return 0;
143         csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
144         csqcplayer = self;
145         return 1;
146 }