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