g_spawn_command_line_sync used for spawning the game now.
[crack-attack.git] / src / Communicator.h
blob00c6a2a103052471c7ce8f48964791eac43af7a2
1 /*
2 * Communicator.h
3 * Daniel Nelson - 8/24/0
5 * Copyright (C) 2000 Daniel Nelson
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Daniel Nelson - aluminumangel.org
22 * 174 W. 18th Ave.
23 * Columbus, OH 43210
26 #ifndef COMMUNICATOR_H
27 #define COMMUNICATOR_H
29 using namespace std;
31 #include <sys/types.h>
33 #ifndef _WIN32
34 # include <unistd.h>
35 # include <sys/socket.h>
36 # include <netinet/in.h>
37 #else
38 # include <winsock2.h>
39 #endif
41 #include "Game.h"
43 // default communication port
44 #define CO_DEFAULT_PORT (8080)
46 // seconds before server time out due to no connection
47 #define CO_SERVER_TIME_OUT (30)
49 // time steps between communication exchange; must be power of 2
50 #define CO_COMMUNICATION_PERIOD (32)
52 // test integer
53 #define CO_TEST_INT (47)
55 // protocol version number
56 #define CO_VERSION "1.1.8"
58 class BufferElement {
59 public:
60 uint32 time_stamp;
61 uint32 height;
62 uint32 width;
63 uint32 flavor;
65 BufferElement (): time_stamp(0), height(0), width(0), flavor(0) { };
68 class CommunicationBuffer {
69 public:
70 BufferElement garbage[GC_GARBAGE_QUEUE_SIZE];
71 uint32 count;
72 uint32 level_lights;
73 uint32 game_state;
74 uint32 loss_time_stamp;
75 uint32 sync;
78 /* static */ class Communicator {
79 public:
80 static void initialize ( int mode, int port, char host_name[256],
81 char player_name[GC_PLAYER_NAME_LENGTH] );
82 static void gameStart ( );
83 static void gameFinish ( );
84 static void cleanUp ( );
85 static void barrier ( );
87 static inline void unpauseSyncCheck ( )
89 // latency for opponent's unpause depends on whether our next communication
90 // action is to send or recv; note that this method if far from perfect and
91 // often causes sporatic waits after an unpause; everything is perfectly
92 // resynced by the resync system, but it would be nice to eliminate those
93 // waits
94 int latency = 0;
95 if (time_step & CO_COMMUNICATION_PERIOD)
96 latency += CO_COMMUNICATION_PERIOD;
97 latency += time_step & (CO_COMMUNICATION_PERIOD - 1);
99 if (last_recv_sync > last_own_sync + latency)
100 Game::syncPause(last_recv_sync - last_own_sync - latency);
103 static inline void signalPaused ( )
105 if (!(send_buffer.game_state & GS_UNPAUSED))
106 send_buffer.game_state |= GS_PAUSED;
107 else
108 send_buffer.game_state &= ~GS_UNPAUSED;
111 static inline void signalUnpaused ( )
113 if (!(send_buffer.game_state & GS_PAUSED))
114 send_buffer.game_state |= GS_UNPAUSED;
115 else
116 send_buffer.game_state &= ~GS_PAUSED;
119 static inline void timeStepPlay ( )
121 time_step++;
122 if (time_step & (CO_COMMUNICATION_PERIOD - 1)) return;
123 if (!no_communication)
124 timeStepPlay_inline_split_();
127 static inline void timeStepMeta ( )
129 time_step++;
130 if (time_step & (CO_COMMUNICATION_PERIOD - 1)) return;
131 timeStepMeta_inline_split_();
134 static inline bool isSendStep ( )
136 return time_step & CO_COMMUNICATION_PERIOD;
139 static inline void sendGarbage ( int height, int width, int flavor )
141 if (send_buffer.count == GC_GARBAGE_QUEUE_SIZE) return;
143 send_buffer.garbage[send_buffer.count].time_stamp = Game::time_step;
144 send_buffer.garbage[send_buffer.count].height = height;
145 send_buffer.garbage[send_buffer.count].width = width;
146 send_buffer.garbage[send_buffer.count].flavor = flavor;
147 send_buffer.count++;
150 static inline void setLevelLightSendBit ( int mask )
152 send_buffer.level_lights |= mask;
155 static inline bool checkLevelLightRecvBit ( int mask )
157 return recv_buffer.level_lights & mask;
160 static inline void setLossTimeStep ( )
162 send_buffer.loss_time_stamp = (uint32) Game::time_step;
165 static int time_step;
166 static char opponent_name[GC_PLAYER_NAME_LENGTH];
168 private:
169 static void timeStepPlay_inline_split_ ( );
170 static void timeStepMeta_inline_split_ ( );
172 static void exchangeRandomSeed ( );
174 static inline void commSend ( const void *message, int size )
176 int n;
178 if ((n = send(comm_link, (char *) message, size, 0)) != -1) {
179 message = (char *) message + n;
180 size -= n;
181 } else {
182 cerr << "Connection lost." << endl;
183 exit(1);
185 while (size > 0);
188 static inline void commRecv ( void *buffer, int size )
190 int n;
192 if ((n = recv(comm_link, (char *) buffer, size, 0)) != -1) {
193 buffer = (char *) buffer + n;
194 size -= n;
195 } else {
196 cerr << "Connection lost." << endl;
197 exit(1);
199 while (size > 0);
202 static inline void commSend ( uint32 value )
204 value = htonl(value);
205 commSend(&value, sizeof(value));
208 static inline void commRecv ( uint32 &value )
210 commRecv(&value, sizeof(value));
211 value = ntohl(value);
214 static inline void commSend ( const CommunicationBuffer &buffer )
216 work_buffer.count = htonl(buffer.count);
217 for (int i = buffer.count; i--; ) {
218 work_buffer.garbage[i].time_stamp = htonl(buffer.garbage[i].time_stamp);
219 work_buffer.garbage[i].height = htonl(buffer.garbage[i].height);
220 work_buffer.garbage[i].width = htonl(buffer.garbage[i].width);
221 work_buffer.garbage[i].flavor = htonl(buffer.garbage[i].flavor);
223 work_buffer.level_lights = htonl(buffer.level_lights);
224 work_buffer.game_state = htonl(buffer.game_state);
225 work_buffer.loss_time_stamp = htonl(buffer.loss_time_stamp);
226 work_buffer.sync = htonl(buffer.sync);
228 commSend(&work_buffer, sizeof(work_buffer));
231 static inline void commRecv ( CommunicationBuffer &buffer )
233 commRecv(&work_buffer, sizeof(work_buffer));
235 buffer.count = ntohl(work_buffer.count);
236 for (int i = buffer.count; i--; ) {
237 buffer.garbage[i].time_stamp = ntohl(work_buffer.garbage[i].time_stamp);
238 buffer.garbage[i].height = ntohl(work_buffer.garbage[i].height);
239 buffer.garbage[i].width = ntohl(work_buffer.garbage[i].width);
240 buffer.garbage[i].flavor = ntohl(work_buffer.garbage[i].flavor);
242 buffer.level_lights = ntohl(work_buffer.level_lights);
243 buffer.game_state = ntohl(work_buffer.game_state);
244 buffer.loss_time_stamp = ntohl(work_buffer.loss_time_stamp);
245 buffer.sync = ntohl(work_buffer.sync);
248 static void startupExchange ( char player_name[GC_PLAYER_NAME_LENGTH] );
250 static int comm_link;
251 static bool comm_link_active;
252 static bool no_communication;
253 static bool have_communicated;
254 static int last_recv_sync;
255 static int last_own_sync;
256 static CommunicationBuffer send_buffer;
257 static CommunicationBuffer recv_buffer;
258 static CommunicationBuffer work_buffer;
260 static bool win_ties;
263 #endif