1 /* vim: set et ts=2 sw=2:
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
29 //#include <sys/types.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)
44 #define CO_TEST_INT (47)
46 // protocol version number
47 #define CO_VERSION "1.1.15"
48 #define CO_VERSION_MAX_LENGTH (10)
51 enum { CO_CHANNEL_REL
= 0, CO_CHANNEL_GARBAGE
, CO_CHANNEL_STATUS
,
52 CO_CHANNEL_BOARD
, NUM_CHANNELS
};
61 BufferElement (): time_stamp(0), height(0), width(0), flavor(0) { };
66 BufferElement garbage
[GC_GARBAGE_QUEUE_SIZE
];
70 class CommunicationBuffer
{
74 uint32 loss_time_stamp
;
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
{
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
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
;
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
;
124 send_buffer
.game_state
&= ~GS_PAUSED
;
127 static inline void timeStepPlay ( )
130 //if (time_step & (CO_COMMUNICATION_PERIOD - 1)) return;
131 if (!no_communication
)
132 timeStepPlay_inline_split_();
135 static inline void timeStepMeta ( )
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
];
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 (
192 enet_uint8 channelId
,
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
;
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
)
217 MESSAGE("Potentially waiting forever");
218 while (enet_host_service(host
, &event
, CO_SERVER_TIME_OUT
* 1000) > 0) {
220 if (event
.type
== ENET_EVENT_TYPE_DISCONNECT
) {
221 std::cerr
<< "Disconnected from host." << std::endl
;
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 " <<
230 read(event
.packet
, buffer
, size
);
231 enet_packet_destroy(event
.packet
);
237 static inline void commGetRel ( uint32
&value
)
239 commGetRel(&value
, sizeof(value
));
242 static inline bool commGetRelNoBlock ( void *buffer
, size_t size
)
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
;
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 " <<
256 read(event
.packet
, buffer
, size
);
257 enet_packet_destroy(event
.packet
);
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");
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
) {
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
;