3 * Daniel Nelson - 8/24/0
5 * Copyright (C) 2000 Daniel Nelson
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
26 #ifndef COMMUNICATOR_H
27 #define COMMUNICATOR_H
31 #include <sys/types.h>
35 # include <sys/socket.h>
36 # include <netinet/in.h>
38 # include <winsock2.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)
53 #define CO_TEST_INT (47)
55 // protocol version number
56 #define CO_VERSION "1.1.8"
65 BufferElement (): time_stamp(0), height(0), width(0), flavor(0) { };
68 class CommunicationBuffer
{
70 BufferElement garbage
[GC_GARBAGE_QUEUE_SIZE
];
74 uint32 loss_time_stamp
;
78 /* static */ class Communicator
{
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
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
;
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
;
116 send_buffer
.game_state
&= ~GS_PAUSED
;
119 static inline void timeStepPlay ( )
122 if (time_step
& (CO_COMMUNICATION_PERIOD
- 1)) return;
123 if (!no_communication
)
124 timeStepPlay_inline_split_();
127 static inline void timeStepMeta ( )
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
;
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
];
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
)
178 if ((n
= send(comm_link
, (char *) message
, size
, 0)) != -1) {
179 message
= (char *) message
+ n
;
182 cerr
<< "Connection lost." << endl
;
188 static inline void commRecv ( void *buffer
, int size
)
192 if ((n
= recv(comm_link
, (char *) buffer
, size
, 0)) != -1) {
193 buffer
= (char *) buffer
+ n
;
196 cerr
<< "Connection lost." << endl
;
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
;