Fixes for datatype size on amd64.
[crack-attack.git] / src / Communicator.h
blob417f5bae469e57d3616cdfe89ce8e20b853b8309
1 /* vim: set et ts=2 sw=2:
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 //#include <sys/types.h>
31 #include "Game.h"
32 #include "enet/enet.h"
34 // default communication port
35 #define CO_DEFAULT_PORT (8080)
37 // seconds before server time out due to no connection
38 #define CO_SERVER_TIME_OUT (30)
40 // time steps between communication exchange; must be power of 2
41 #define CO_COMMUNICATION_PERIOD (32)
43 // test integer
44 #define CO_TEST_INT (47)
46 // protocol version number
47 #define CO_VERSION "1.1.15"
48 #define CO_VERSION_MAX_LENGTH (10)
50 // channel numbers
51 enum { CO_CHANNEL_REL = 0, CO_CHANNEL_GARBAGE, CO_CHANNEL_STATUS,
52 CO_CHANNEL_BOARD, NUM_CHANNELS };
54 class BufferElement {
55 public:
56 uint32 time_stamp;
57 uint32 height;
58 uint32 width;
59 uint32 flavor;
61 BufferElement (): time_stamp(0), height(0), width(0), flavor(0) { };
64 class GarbageBuffer {
65 public:
66 BufferElement garbage[GC_GARBAGE_QUEUE_SIZE];
67 uint32 count;
70 class CommunicationBuffer {
71 public:
72 uint32 level_lights;
73 uint32 game_state;
74 uint32 loss_time_stamp;
75 uint32 sync;
77 inline void print() const {
79 std::cout << "lights: " << level_lights << " state: "
80 << game_state << " stamp: " << loss_time_stamp
81 << " sync: " << sync << std::endl;
86 /* static */ class Communicator {
87 public:
88 static void initialize ( int mode, int port, char host_name[256],
89 char player_name[GC_PLAYER_NAME_LENGTH] );
90 static void gameStart ( );
91 static void gameFinish ( );
92 static void cleanUp ( );
93 static void barrier ( );
95 static inline void unpauseSyncCheck ( )
97 // latency for opponent's unpause depends on whether our next communication
98 // action is to send or recv; note that this method if far from perfect and
99 // often causes sporatic waits after an unpause; everything is perfectly
100 // resynced by the resync system, but it would be nice to eliminate those
101 // waits
102 int latency = 0;
103 if (time_step & CO_COMMUNICATION_PERIOD)
104 latency += CO_COMMUNICATION_PERIOD;
105 latency += time_step & (CO_COMMUNICATION_PERIOD - 1);
107 if (last_recv_sync > last_own_sync + latency)
108 Game::syncPause(last_recv_sync - last_own_sync - latency);
111 static inline void signalPaused ( )
113 if (!(send_buffer.game_state & GS_UNPAUSED))
114 send_buffer.game_state |= GS_PAUSED;
115 else
116 send_buffer.game_state &= ~GS_UNPAUSED;
119 static inline void signalUnpaused ( )
121 if (!(send_buffer.game_state & GS_PAUSED))
122 send_buffer.game_state |= GS_UNPAUSED;
123 else
124 send_buffer.game_state &= ~GS_PAUSED;
127 static inline void timeStepPlay ( )
129 time_step++;
130 //if (time_step & (CO_COMMUNICATION_PERIOD - 1)) return;
131 if (!no_communication)
132 timeStepPlay_inline_split_();
135 static inline void timeStepMeta ( )
137 time_step++;
138 //if (time_step & (CO_COMMUNICATION_PERIOD - 1)) return;
139 timeStepMeta_inline_split_();
142 static inline bool isSendStep ( )
144 return time_step & CO_COMMUNICATION_PERIOD;
147 static inline void sendGarbage ( int height, int width, int flavor )
149 if (send_garb_buffer.count == GC_GARBAGE_QUEUE_SIZE) return;
151 send_garb_buffer.garbage[send_garb_buffer.count].time_stamp = Game::time_step;
152 send_garb_buffer.garbage[send_garb_buffer.count].height = height;
153 send_garb_buffer.garbage[send_garb_buffer.count].width = width;
154 send_garb_buffer.garbage[send_garb_buffer.count].flavor = flavor;
155 send_garb_buffer.count++;
158 static inline void setLevelLightSendBit ( int mask )
160 send_buffer.level_lights |= mask;
163 static inline bool checkLevelLightRecvBit ( int mask )
165 return recv_buffer.level_lights & mask;
168 static inline void setLossTimeStep ( )
170 send_buffer.loss_time_stamp = (uint32) Game::time_step;
173 static int time_step;
174 static char opponent_name[GC_PLAYER_NAME_LENGTH];
176 private:
177 static void timeStepPlay_inline_split_ ( );
178 static void timeStepMeta_inline_split_ ( );
180 static void handlePlayRecv ( );
181 static void handlePlayRecvGarbage ( ENetEvent event );
182 static void handlePlayRecvStatus ( ENetEvent event );
183 static void handlePlayRecvBoard ( ENetEvent event );
185 static void handlePlaySend ( );
187 static void exchangeRandomSeed ( );
189 static inline void commSend (
190 const void *message,
191 size_t size,
192 enet_uint8 channelId,
193 bool reliable)
195 ENetPacket *packet = enet_packet_create(
196 message, size, (reliable ? ENET_PACKET_FLAG_RELIABLE : 0));
197 DOT((int)channelId + 10);
198 if(enet_peer_send(peer, channelId, packet)!=0) {
199 std::cerr << "Connection lost on send" << std::endl;
200 exit(1);
204 static inline void commSendRel ( const void *buffer, size_t size )
206 commSend(buffer, size, CO_CHANNEL_REL, true);
209 static inline void commSendRel ( uint32 value )
211 commSendRel(&value, sizeof(value));
214 static inline void commGetRel ( void *buffer, size_t size )
216 ENetEvent event;
217 MESSAGE("Potentially waiting forever");
218 while (enet_host_service(host, &event, CO_SERVER_TIME_OUT * 1000) > 0) {
219 DOT(4);
220 if (event.type == ENET_EVENT_TYPE_DISCONNECT) {
221 std::cerr << "Disconnected from host." << std::endl;
222 exit(1);
224 else if (event.type == ENET_EVENT_TYPE_RECEIVE) {
225 if(event.channelID!=CO_CHANNEL_REL) {
226 MESSAGE("Received out-of-order non-reliable packet on channnel " <<
227 event.channelID);
228 continue;
230 read(event.packet, buffer, size);
231 enet_packet_destroy(event.packet);
232 break;
237 static inline void commGetRel ( uint32 &value )
239 commGetRel(&value, sizeof(value));
242 static inline bool commGetRelNoBlock ( void *buffer, size_t size )
244 ENetEvent event;
245 if (enet_host_service(host, &event, 0) > 0) {
246 if (event.type == ENET_EVENT_TYPE_DISCONNECT) {
247 std::cerr << "Disconnected from host." << std::endl;
248 exit(1);
250 else if (event.type == ENET_EVENT_TYPE_RECEIVE) {
251 if (event.channelID != CO_CHANNEL_REL) {
252 MESSAGE("Received out-of-order non-reliable packet on channnel " <<
253 event.channelID);
254 return false;
255 } else {
256 read(event.packet, buffer, size);
257 enet_packet_destroy(event.packet);
258 return true;
262 return false;
265 static inline bool commGetRelNoBlock( uint32 &value)
267 return commGetRelNoBlock(&value, sizeof(value));
270 static inline void commSendGarbage ( )
272 commSendGarbage(send_garb_buffer);
275 static inline void commSendGarbage ( const GarbageBuffer &buffer )
277 for (uint32 count = 0; count < buffer.count; ++count) {
278 commSend(&(buffer.garbage[count]), sizeof(BufferElement), CO_CHANNEL_GARBAGE, true);
280 //commSend(&buffer, sizeof(buffer), CO_CHANNEL_GARBAGE, true);
283 static inline void commSendStatus ( )
285 commSendStatus(send_buffer);
288 static inline void commSendStatus ( const CommunicationBuffer &buffer )
290 MESSAGE("Sending status");
291 #ifdef DEVELOPMENT
292 buffer.print();
293 #endif
294 commSend(&buffer, sizeof(buffer), CO_CHANNEL_STATUS, false);
297 static inline void read ( ENetPacket *p, void *buffer, size_t size)
299 size_t plen = p->dataLength;
300 size_t ilen = std::min(plen, size);
301 enet_uint8 *buf = (enet_uint8 *)buffer;
302 for (size_t i=0; i < ilen; ++i) {
303 buf[i] = p->data[i];
307 static inline void fillCommunicationBuffer ( ENetPacket *packet)
309 read(packet, &work_buffer, sizeof(work_buffer));
311 recv_buffer.level_lights = (work_buffer.level_lights);
312 recv_buffer.game_state = (work_buffer.game_state);
313 recv_buffer.loss_time_stamp = (work_buffer.loss_time_stamp);
314 recv_buffer.sync = (work_buffer.sync);
317 static inline void fillGarbageBuffer ( ENetPacket *packet )
319 size_t len = packet->dataLength;
320 size_t num_garbage = len / sizeof(BufferElement);
321 recv_garb_buffer.count = num_garbage;
322 for (size_t i = 0; i < num_garbage; ++i) {
323 read(packet, &(recv_garb_buffer.garbage[i]), sizeof(BufferElement));
327 static void startupExchange ( char player_name[GC_PLAYER_NAME_LENGTH] );
329 static ENetHost * host;
330 static ENetPeer * peer;
331 static bool comm_link_active;
332 static bool no_communication;
333 static bool have_communicated;
334 static int last_recv_sync;
335 static int last_own_sync;
336 static CommunicationBuffer send_buffer;
337 static CommunicationBuffer recv_buffer;
338 static GarbageBuffer send_garb_buffer;
339 static GarbageBuffer recv_garb_buffer;
340 static CommunicationBuffer work_buffer;
342 static bool win_ties;
345 #endif