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