1 /*
2 * Copyright 2006 Serge van den Boom <svdb@stack.nl>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #ifdef NETPLAY
20
21 #include "checksum.h"
22 #include "netoptions.h"
23
24 #ifdef NETPLAY_CHECKSUM
25
26 #include "checkbuf.h"
27 #include "crc.h"
28 // for DUMP_CRC_OPS
29 #include "netconnection.h"
30 #include "netmelee.h"
31 #include "libs/log.h"
32 #include "libs/mathlib.h"
33
34 ChecksumBuffer localChecksumBuffer;
35
36 void
crc_processEXTENT(crc_State * state,const EXTENT * val)37 crc_processEXTENT(crc_State *state, const EXTENT *val) {
38 #ifdef DUMP_CRC_OPS
39 crc_log("START crc_processEXTENT().");
40 #endif
41 crc_processCOORD(state, val->width);
42 crc_processCOORD(state, val->height);
43 #ifdef DUMP_CRC_OPS
44 crc_log("END crc_processEXTENT().");
45 #endif
46 }
47
48 void
crc_processVELOCITY_DESC(crc_State * state,const VELOCITY_DESC * val)49 crc_processVELOCITY_DESC(crc_State *state, const VELOCITY_DESC *val) {
50 #ifdef DUMP_CRC_OPS
51 crc_log("START crc_processVELOCITY_DESC().");
52 #endif
53 crc_processCOUNT(state, val->TravelAngle);
54 crc_processEXTENT(state, &val->vector);
55 crc_processEXTENT(state, &val->fract);
56 crc_processEXTENT(state, &val->error);
57 crc_processEXTENT(state, &val->incr);
58 #ifdef DUMP_CRC_OPS
59 crc_log("END crc_processVELOCITY_DESC().");
60 #endif
61 }
62
63 void
crc_processPOINT(crc_State * state,const POINT * val)64 crc_processPOINT(crc_State *state, const POINT *val) {
65 #ifdef DUMP_CRC_OPS
66 crc_log("START crc_processPOINT().");
67 #endif
68 crc_processCOORD(state, val->x);
69 crc_processCOORD(state, val->y);
70 #ifdef DUMP_CRC_OPS
71 crc_log("END crc_processPOINT().");
72 #endif
73 }
74
75 #if 0
76 void
77 crc_processSTAMP(crc_State *state, const STAMP *val) {
78 #ifdef DUMP_CRC_OPS
79 crc_log("START crc_processSTAMP().");
80 #endif
81 crc_processPOINT(state, val->origin);
82 crc_processFRAME(state, val->frame);
83 #ifdef DUMP_CRC_OPS
84 crc_log("END crc_processSTAMP().");
85 #endif
86 }
87
88 void
89 crc_processINTERSECT_CONTROL(crc_State *state, const INTERSECT_CONTROL *val) {
90 #ifdef DUMP_CRC_OPS
91 crc_log("START crc_processINTERSECT_CONTROL().");
92 #endif
93 crc_processTIME_VALUE(state, val->last_time_val);
94 crc_processPOINT(state, &val->EndPoint);
95 #ifdef DUMP_CRC_OPS
96 crc_log("END crc_processINTERSECT_CONTROL().");
97 #endif
98 }
99 #endif
100
101 void
crc_processSTATE(crc_State * state,const STATE * val)102 crc_processSTATE(crc_State *state, const STATE *val) {
103 crc_processPOINT(state, &val->location);
104 }
105
106 void
crc_processELEMENT(crc_State * state,const ELEMENT * val)107 crc_processELEMENT(crc_State *state, const ELEMENT *val) {
108 #ifdef DUMP_CRC_OPS
109 crc_log("START crc_processELEMENT().");
110 #endif
111 if (val->state_flags & BACKGROUND_OBJECT) {
112 // The element never influences the state of other elements,
113 // and is to be excluded from checksums.
114 #ifdef DUMP_CRC_OPS
115 crc_log(" BACKGROUND_OBJECT element omited");
116 #endif
117 } else {
118 crc_processELEMENT_FLAGS(state, val->state_flags);
119 crc_processCOUNT(state, val->life_span);
120 crc_processCOUNT(state, val->crew_level);
121 crc_processBYTE(state, val->mass_points);
122 crc_processBYTE(state, val->turn_wait);
123 crc_processBYTE(state, val->thrust_wait);
124 crc_processVELOCITY_DESC(state, &val->velocity);
125 crc_processSTATE(state, &val->current);
126 crc_processSTATE(state, &val->next);
127 }
128 #ifdef DUMP_CRC_OPS
129 crc_log("END crc_processELEMENT().");
130 #endif
131 }
132
133 void
crc_processDispQueue(crc_State * state)134 crc_processDispQueue(crc_State *state) {
135 HELEMENT element;
136 HELEMENT nextElement;
137
138 #ifdef DUMP_CRC_OPS
139 size_t i = 0;
140 crc_log("START crc_processDispQueue().");
141 #endif
142 for (element = GetHeadElement(); element != 0; element = nextElement) {
143 ELEMENT *elementPtr;
144
145 #ifdef DUMP_CRC_OPS
146 crc_log("===== disp_q[%d]:", i);
147 #endif
148 LockElement(element, &elementPtr);
149
150 crc_processELEMENT(state, elementPtr);
151
152 nextElement = GetSuccElement(elementPtr);
153 UnlockElement(element);
154 #ifdef DUMP_CRC_OPS
155 i++;
156 #endif
157 }
158 #ifdef DUMP_CRC_OPS
159 crc_log("END crc_processDispQueue().");
160 #endif
161 }
162
163 void
crc_processRNG(crc_State * state)164 crc_processRNG(crc_State *state) {
165 DWORD seed;
166
167 #ifdef DUMP_CRC_OPS
168 crc_log("START crc_processRNG().");
169 #endif
170
171 seed = TFB_SeedRandom(0);
172 // This modifies the seed too.
173 crc_processDWORD(state, seed);
174 TFB_SeedRandom(seed);
175 // Restore the old seed.
176
177 #ifdef DUMP_CRC_OPS
178 crc_log("END crc_processRNG().");
179 #endif
180 }
181
182 void
crc_processState(crc_State * state)183 crc_processState(crc_State *state) {
184 #ifdef DUMP_CRC_OPS
185 crc_log("--------------------\n"
186 "START crc_processState() (frame %u).", battleFrameCount);
187 #endif
188
189 crc_processRNG(state);
190 crc_processDispQueue(state);
191
192 #ifdef DUMP_CRC_OPS
193 crc_log("END crc_processState() (frame %u).",
194 battleFrameCount);
195 #endif
196 }
197
198 void
initChecksumBuffers(void)199 initChecksumBuffers(void) {
200 size_t player;
201
202 for (player = 0; player < NETPLAY_NUM_PLAYERS; player++)
203 {
204 NetConnection *conn;
205 ChecksumBuffer *cb;
206
207 conn = netConnections[player];
208 if (conn == NULL)
209 continue;
210
211 cb = NetConnection_getChecksumBuffer(conn);
212 ChecksumBuffer_init(cb, getBattleInputDelay(),
213 NETPLAY_CHECKSUM_INTERVAL);
214 }
215
216 ChecksumBuffer_init(&localChecksumBuffer, getBattleInputDelay(),
217 NETPLAY_CHECKSUM_INTERVAL);
218 }
219
220 void
uninitChecksumBuffers(void)221 uninitChecksumBuffers(void)
222 {
223 size_t player;
224
225 for (player = 0; player < NETPLAY_NUM_PLAYERS; player++)
226 {
227 NetConnection *conn;
228 ChecksumBuffer *cb;
229
230 conn = netConnections[player];
231 if (conn == NULL)
232 continue;
233
234 cb = NetConnection_getChecksumBuffer(conn);
235
236 ChecksumBuffer_uninit(cb);
237 }
238
239 ChecksumBuffer_uninit(&localChecksumBuffer);
240 }
241
242 void
addLocalChecksum(BattleFrameCounter frameNr,Checksum checksum)243 addLocalChecksum(BattleFrameCounter frameNr, Checksum checksum) {
244 assert(frameNr == battleFrameCount);
245
246 ChecksumBuffer_addChecksum(&localChecksumBuffer, frameNr, checksum);
247 }
248
249 void
addRemoteChecksum(NetConnection * conn,BattleFrameCounter frameNr,Checksum checksum)250 addRemoteChecksum(NetConnection *conn, BattleFrameCounter frameNr,
251 Checksum checksum) {
252 ChecksumBuffer *cb;
253
254 assert(frameNr <= battleFrameCount + getBattleInputDelay() + 1);
255 assert(frameNr + getBattleInputDelay() >= battleFrameCount);
256
257 cb = NetConnection_getChecksumBuffer(conn);
258 ChecksumBuffer_addChecksum(cb, frameNr, checksum);
259 }
260
261 bool
verifyChecksums(BattleFrameCounter frameNr)262 verifyChecksums(BattleFrameCounter frameNr) {
263 Checksum localChecksum;
264 size_t player;
265
266 if (!ChecksumBuffer_getChecksum(&localChecksumBuffer, frameNr,
267 &localChecksum)) {
268 // Right now, we require that a checksum is present.
269 // If/when we move to UDP, and packets may get lost, we may prefer
270 // not to do any checks in this case.
271 return false;
272 }
273
274 for (player = 0; player < NETPLAY_NUM_PLAYERS; player++)
275 {
276 NetConnection *conn;
277 ChecksumBuffer *cb;
278 Checksum remoteChecksum;
279
280 conn = netConnections[player];
281 if (conn == NULL)
282 continue;
283
284 cb = NetConnection_getChecksumBuffer(conn);
285
286 if (!ChecksumBuffer_getChecksum(cb, frameNr, &remoteChecksum))
287 return false;
288
289 if (localChecksum != remoteChecksum) {
290 log_add(log_Error, "Network connections have gone out of "
291 "sync.\n");
292 return false;
293 }
294 }
295 return true;
296 }
297
298
299 #endif /* NETPLAY_CHECKSUM */
300
301 #endif /* NETPLAY */
302
303