1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4
5 This file is part of Shadow Warrior version 1.2
6
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26
27 //#define MAIN
28 #define QUIET
29 #include "build.h"
30
31 #include "keys.h"
32 #include "names2.h"
33 #include "panel.h"
34 #include "game.h"
35 //#include "quake.h"
36 //#include "jsector.h"
37
38 //#include "mytypes.h"
39 //#include "control.h"
40 //#include "function.h"
41 #include "net.h"
42 //#include "symutil.h"
43
44 BOOL PredictionOn = TRUE;
45 BOOL Prediction = FALSE;
46 PLAYER PredictPlayer;
47 USER PredictUser;
48 PLAYERp ppp = &PredictPlayer;
49
50 typedef struct
51 {
52 int x,y,z,horiz;
53 short ang,filler;
54 }PREDICT, *PREDICTp;
55
56 PREDICT Predict[MOVEFIFOSIZ];
57 int predictmovefifoplc;
58
59 VOID DoPlayerSectorUpdatePreMove(PLAYERp);
60 VOID DoPlayerSectorUpdatePostMove(PLAYERp);
61
62 extern BOOL GamePaused;
63
64 #define PREDICT_DEBUG 0
65
66 #if PREDICT_DEBUG
67 VOID (*pred_last_func)(PLAYERp) = NULL;
68 #endif
69
70 void
InitPrediction(PLAYERp pp)71 InitPrediction(PLAYERp pp)
72 {
73 if (!PredictionOn)
74 return;
75
76 #if PREDICT_DEBUG
77 pred_last_func = pp->DoPlayerAction;
78 #endif
79
80 // make a copy of player struct and sprite
81 *ppp = *pp;
82 PredictUser = *User[pp->PlayerSprite];
83 }
84
85 #if PREDICT_DEBUG
PredictDebug(PLAYERp ppp)86 PredictDebug(PLAYERp ppp)
87 {
88 static FILE *fout = NULL;
89 static char pred_sym_name[80];
90
91 if (SymCountCode == 0)
92 LoadSymTable("swcode.sym", &SymTableCode, &SymCountCode);
93
94 if (SymCountCode <= 0)
95 return;
96
97 if (!fout)
98 {
99 if ((fout = fopen("dbgpred.txt", "wb")) == NULL)
100 return;
101 }
102
103 if (ppp->DoPlayerAction != pred_last_func)
104 {
105 extern ULONG MoveThingsCount;
106 SYM_TABLEp st_ptr;
107 ULONG unrelocated_offset;
108 ULONG offset_from_symbol;
109
110 unrelocated_offset = SymCodePtrToOffset((void*)ppp->DoPlayerAction);
111 st_ptr = SearchSymTableByOffset(SymTableCode, SymCountCode, unrelocated_offset, &offset_from_symbol);
112 ASSERT(st_ptr);
113 strcpy(pred_sym_name, st_ptr->Name);
114
115 fprintf(fout, "%s, %d\n", pred_sym_name, MoveThingsCount);
116 }
117 }
118 #endif
119
120
121 void
DoPrediction(PLAYERp ppp)122 DoPrediction(PLAYERp ppp)
123 {
124 USERp u;
125 SPRITE spr;
126 int bakrandomseed;
127 short angvel;
128
129 // routine called from MoveLoop
130
131 if (!PredictionOn)
132 return;
133
134 ppp->input = Player[myconnectindex].inputfifo[predictmovefifoplc & (MOVEFIFOSIZ-1)];
135
136 // get rid of input bits so it doesn't go into other code branches that would
137 // get it out of sync
138 RESET(ppp->input.bits,
139 BIT(SK_SHOOT)|BIT(SK_OPERATE)|BIT(SK_INV_LEFT)|BIT(SK_INV_RIGHT)|
140 BIT(SK_INV_USE)|BIT(SK_HIDE_WEAPON)|
141 BIT(SK_AUTO_AIM)|
142 BIT(SK_CENTER_VIEW)|
143 SK_WEAPON_MASK|
144 SK_INV_HOTKEY_MASK
145 );
146
147 SET(ppp->KeyPressFlags,
148 BIT(SK_SHOOT)|BIT(SK_OPERATE)|BIT(SK_INV_LEFT)|BIT(SK_INV_RIGHT)|
149 BIT(SK_INV_USE)|BIT(SK_HIDE_WEAPON)|
150 BIT(SK_AUTO_AIM)|
151 BIT(SK_CENTER_VIEW)|
152 SK_WEAPON_MASK|
153 SK_INV_HOTKEY_MASK
154 );
155
156 // back up things so they won't get stepped on
157 bakrandomseed = randomseed;
158 spr = sprite[Player[myconnectindex].PlayerSprite];
159 sprite[Player[myconnectindex].PlayerSprite].cstat = 0;
160
161 u = User[ppp->PlayerSprite];
162 User[ppp->PlayerSprite] = &PredictUser;
163
164 ppp->oang = ppp->pang;
165 ppp->oposx = ppp->posx;
166 ppp->oposy = ppp->posy;
167 ppp->oposz = ppp->posz;
168 ppp->ohoriz = ppp->horiz;
169
170 #if PREDICT_DEBUG
171 PredictDebug(ppp);
172 #endif
173
174 // go through the player MOVEMENT code only
175 Prediction = TRUE;
176 DoPlayerSectorUpdatePreMove(ppp);
177 (*ppp->DoPlayerAction) (ppp);
178 DoPlayerSectorUpdatePostMove(ppp);
179 Prediction = FALSE;
180
181 // restore things
182 User[ppp->PlayerSprite] = u;
183 sprite[Player[myconnectindex].PlayerSprite] = spr;
184 randomseed = bakrandomseed;
185
186 Predict[predictmovefifoplc & (MOVEFIFOSIZ-1)].ang = ppp->pang;
187 Predict[predictmovefifoplc & (MOVEFIFOSIZ-1)].x = ppp->posx;
188 Predict[predictmovefifoplc & (MOVEFIFOSIZ-1)].y = ppp->posy;
189 Predict[predictmovefifoplc & (MOVEFIFOSIZ-1)].z = ppp->posz;
190 Predict[predictmovefifoplc & (MOVEFIFOSIZ-1)].horiz = ppp->horiz;
191 predictmovefifoplc++;
192 }
193
194 void
CorrectPrediction(int actualfifoplc)195 CorrectPrediction(int actualfifoplc)
196 {
197 PREDICTp predict = &Predict[actualfifoplc & (MOVEFIFOSIZ-1)];
198
199 if (!PredictionOn)
200 return;
201
202 if (!CommEnabled)
203 return;
204
205 // see if player position is predicted position
206 if (predict->ang == Player[myconnectindex].pang &&
207 predict->x == Player[myconnectindex].posx &&
208 predict->y == Player[myconnectindex].posy &&
209 predict->z == Player[myconnectindex].posz &&
210 predict->horiz == Player[myconnectindex].horiz
211 )
212 {
213 return;
214 }
215
216 // //DSPRINTF(ds,"PREDICT ERROR: %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld", predict->ang, Player[myconnectindex].pang, predict->x, Player[myconnectindex].posx, predict->y, Player[myconnectindex].posy, predict->z, Player[myconnectindex].posz, predict->horiz,Player[myconnectindex].horiz);
217 // MONO_PRINT(ds);
218
219 InitPrediction(&Player[myconnectindex]);
220 // puts the predicted pos back to actual pos
221 predictmovefifoplc = movefifoplc;
222
223 while (predictmovefifoplc < Player[myconnectindex].movefifoend)
224 {
225 DoPrediction(ppp);
226 }
227 }
228
229