diff options
Diffstat (limited to 'src/uqm/supermelee/netplay/checkbuf.c')
-rw-r--r-- | src/uqm/supermelee/netplay/checkbuf.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/uqm/supermelee/netplay/checkbuf.c b/src/uqm/supermelee/netplay/checkbuf.c new file mode 100644 index 0000000..e9c5a32 --- /dev/null +++ b/src/uqm/supermelee/netplay/checkbuf.c @@ -0,0 +1,145 @@ +/* + * Copyright 2006 Serge van den Boom <svdb@stack.nl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define PORT_WANT_ERRNO +#include "port.h" + +#include "netplay.h" +#include "checkbuf.h" +#include "libs/log.h" + +#include "../../battle.h" + // for battleFrameCount + + +#include <errno.h> +#include <stdlib.h> + + + +static inline BattleFrameCounter +ChecksumBuffer_getCurrentFrameNr(void) { + return battleFrameCount; +} + +void +ChecksumBuffer_init(ChecksumBuffer *cb, size_t delay, size_t interval) { + // The input buffer lags BattleInput_inputDelay frames behind, + // but only every interval frames will there be a checksum to be + // checked. + + // Checksums will be checked when 'frameNr % interval == 0'. + // (and frameNr is zero-based). + // The checksum of frame n will be processed in frame 'n + delay'. + + // In the worst case, side 1 processes frames 'n' through 'n + delay - 1', + // then blocks in frame 'n + delay' (after sending a checksum, if that's + // pertinent for that frame). + // Then side 2 receives all this input and these checksums, and + // progresses to 'delay' frames after the last frame the received input + // originated from, and blocks in the frame after it (after sending a + // checksum, if that's pertinent for the frame). + // So it sent input and checksums for frames 'n' through + // 'n + delay + delay + 1'. + // The input and checksums for these '2*delay + 2' frames are still + // unhandled by side 1, so it needs buffer space for this. + // With checksums only sent every interval frames, the buffer space + // needed will be 'roundUp(2*delay + 2)' spaces. + + size_t bufSize = ((2 * delay + 2) + (interval - 1)) / interval; + + { +#ifdef NETPLAY_DEBUG + size_t i; +#endif + + cb->checksums = malloc(bufSize * sizeof (ChecksumEntry)); + cb->maxSize = bufSize; + cb->interval = interval; + +#ifdef NETPLAY_DEBUG + for (i = 0; i < bufSize; i++) { + cb->checksums[i].checksum = 0; + cb->checksums[i].frameNr = (BattleFrameCounter) -1; + } +#endif + } +} + +void +ChecksumBuffer_uninit(ChecksumBuffer *cb) { + if (cb->checksums != NULL) { + free(cb->checksums); + cb->checksums = NULL; + } +} + +// Returns the entry that would be used for the checksum for the specified +// frame. Whether the entry is actually valid is not checked. +static ChecksumEntry * +ChecksumBuffer_getChecksumEntry(ChecksumBuffer *cb, + BattleFrameCounter frameNr) { + size_t index; + ChecksumEntry *entry; + + assert(frameNr % cb->interval == 0); + // We only record checksums exactly every 'interval' frames. + + index = (frameNr / cb->interval) % cb->maxSize; + entry = &cb->checksums[index]; + + return entry; +} + +bool +ChecksumBuffer_addChecksum(ChecksumBuffer *cb, BattleFrameCounter frameNr, + Checksum checksum) { + ChecksumEntry *entry; + + assert(frameNr % cb->interval == 0); + + entry = ChecksumBuffer_getChecksumEntry(cb, frameNr); + +#ifdef NETPLAY_DEBUG + entry->frameNr = frameNr; +#endif + entry->checksum = checksum; + return true; +} + +// Pre: frameNr is within the range of the checksums stored in cb. +bool +ChecksumBuffer_getChecksum(ChecksumBuffer *cb, BattleFrameCounter frameNr, + Checksum *result) { + ChecksumEntry *entry; + + entry = ChecksumBuffer_getChecksumEntry(cb, frameNr); + +#ifdef NETPLAY_DEBUG + if (frameNr != entry->frameNr) { + log_add(log_Error, "Checksum buffer entry for requested frame %u " + "(still?) contains a checksum for frame %u.\n", + frameNr, entry->frameNr); + return false; + } +#endif + + *result = entry->checksum; + return true; +} + |