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 #define PORT_WANT_ERRNO
20 #include "port.h"
21
22 #include "netplay.h"
23 #include "netinput.h"
24
25 #include "../../intel.h"
26 // for NETWORK_CONTROL
27 #include "../../setup.h"
28 // For PlayerControl
29 #include "libs/log.h"
30
31 #include <errno.h>
32 #include <stdlib.h>
33
34
35 static BattleInputBuffer battleInputBuffers[NUM_PLAYERS];
36 static size_t BattleInput_inputDelay;
37
38 // Call before initBattleInputBuffers()
39 void
setBattleInputDelay(size_t delay)40 setBattleInputDelay(size_t delay) {
41 BattleInput_inputDelay = delay;
42 }
43
44 size_t
getBattleInputDelay(void)45 getBattleInputDelay(void) {
46 return BattleInput_inputDelay;
47 }
48
49 static void
BattleInputBuffer_init(BattleInputBuffer * bib,size_t bufSize)50 BattleInputBuffer_init(BattleInputBuffer *bib, size_t bufSize) {
51 bib->buf = malloc(bufSize * sizeof (BATTLE_INPUT_STATE));
52 bib->maxSize = bufSize;
53 bib->first = 0;
54 bib->size = 0;
55 }
56
57 static void
BattleInputBuffer_uninit(BattleInputBuffer * bib)58 BattleInputBuffer_uninit(BattleInputBuffer *bib) {
59 if (bib->buf != NULL) {
60 free(bib->buf);
61 bib->buf = NULL;
62 }
63 bib->maxSize = 0;
64 bib->first = 0;
65 bib->size = 0;
66 }
67
68 void
initBattleInputBuffers(void)69 initBattleInputBuffers(void) {
70 size_t player;
71 int bufSize = BattleInput_inputDelay * 2 + 2;
72
73 // The input of frame n will be processed in frame 'n + delay'.
74 //
75 // In the worst case, side 1 processes frames 'n' through 'n + delay - 1',
76 // then blocks in frame 'n + delay'.
77 // Then side 2 receives all this input, and progresses to 'delay' frames
78 // after the last frame the received input originated from, and blocks
79 // in the frame after it.
80 // So it sent input for frames 'n' through 'n + delay + delay + 1'.
81 // The input for these '2*delay + 2' frames are still
82 // unhandled by side 1, so it needs buffer space for this.
83 //
84 // Initially the buffer is filled with inputDelay zeroes,
85 // so that a party can process at least that much frames.
86
87 for (player = 0; player < NUM_PLAYERS; player++)
88 {
89 BattleInputBuffer *bib = &battleInputBuffers[player];
90 BattleInputBuffer_init(bib, bufSize);
91
92 {
93 // Initially a party must be able to process at least inputDelay
94 // frames, so we fill the buffer with inputDelay zeros.
95 size_t i;
96 for (i = 0; i < BattleInput_inputDelay; i++)
97 BattleInputBuffer_push(bib, (BATTLE_INPUT_STATE) 0);
98 }
99 }
100 }
101
102 void
uninitBattleInputBuffers(void)103 uninitBattleInputBuffers(void)
104 {
105 size_t player;
106
107 for (player = 0; player < NUM_PLAYERS; player++)
108 {
109 BattleInputBuffer *bib;
110
111 bib = &battleInputBuffers[player];
112 BattleInputBuffer_uninit(bib);
113 }
114 }
115
116 // On error, returns false and sets errno.
117 bool
BattleInputBuffer_push(BattleInputBuffer * bib,BATTLE_INPUT_STATE input)118 BattleInputBuffer_push(BattleInputBuffer *bib, BATTLE_INPUT_STATE input)
119 {
120 size_t next;
121
122 if (bib->size == bib->maxSize) {
123 // No more space.
124 log_add(log_Error, "NETPLAY: battleInputBuffer full.\n");
125 errno = ENOBUFS;
126 return false;
127 }
128
129 next = (bib->first + bib->size) % bib->maxSize;
130 bib->buf[next] = input;
131 bib->size++;
132 return true;
133 }
134
135 // On error, returns false and sets errno, and *input remains unchanged.
136 bool
BattleInputBuffer_pop(BattleInputBuffer * bib,BATTLE_INPUT_STATE * input)137 BattleInputBuffer_pop(BattleInputBuffer *bib, BATTLE_INPUT_STATE *input)
138 {
139 if (bib->size == 0)
140 {
141 // Buffer is empty.
142 errno = EAGAIN;
143 return false;
144 }
145
146 *input = bib->buf[bib->first];
147 bib->first = (bib->first + 1) % bib->maxSize;
148 bib->size--;
149 return true;
150 }
151
152 BattleInputBuffer *
getBattleInputBuffer(size_t player)153 getBattleInputBuffer(size_t player) {
154 return &battleInputBuffers[player];
155 }
156
157
158