summaryrefslogtreecommitdiff
path: root/src/uqm/supermelee/netplay/checkbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uqm/supermelee/netplay/checkbuf.c')
-rw-r--r--src/uqm/supermelee/netplay/checkbuf.c145
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;
+}
+