1 /*
2 * file network.c - shared functions for server and clients
3 *
4 * $Id: network.c,v 1.42 2006/03/28 11:41:19 fzago Exp $
5 *
6 * Program XBLAST
7 * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2; or (at your option)
12 * any later version
13 *
14 * This program is distributed in the hope that it will be entertaining,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 * Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "xblast.h"
25
26 /*
27 * local types
28 */
29 typedef struct _network_event
30 {
31 struct _network_event *next;
32 XBNetworkEvent msg;
33 unsigned id;
34 } XBNetworkEventQueue;
35
36 typedef struct
37 {
38 unsigned char host;
39 unsigned char player;
40 } XBHostPlayerId;
41
42 /*
43 * local variables
44 */
45
46 /* events */
47 static XBNetworkEventQueue *queueFirst = NULL;
48 static XBNetworkEventQueue *queueLast = NULL;
49
50 /* network type */
51 static XBNetworkType nettype = XBNT_None;
52 static unsigned char localId = MAX_HOSTS;
53
54 /* player atoms and player count */
55 static unsigned players = 0;
56 static XBAtom hostPlayer[MAX_HOSTS][NUM_LOCAL_PLAYER];
57 static XBAtom hostPlayer2[MAX_HOSTS][NUM_LOCAL_PLAYER];
58
59 /* local player counts */
60 static unsigned localPlayers[MAX_HOSTS];
61
62 /* global config and conversion to local */
63 static XBBool global = XBFalse;
64 static CFGGame globalcfg;
65 static XBHostPlayerId s2l[MAX_PLAYER];
66 static unsigned char l2s[MAX_HOSTS][NUM_LOCAL_PLAYER];
67
68 /* ping times */
69 static unsigned hostPing[MAX_HOSTS];
70
71 /* host/team states per host */
72 static XBHostState hostState[MAX_HOSTS];
73 static XBTeamState teamState[MAX_HOSTS][NUM_LOCAL_PLAYER];
74
75 /* default team states */
76 static XBTeamState defTeam[MAX_HOSTS][NUM_LOCAL_PLAYER];
77
78 /* requested raw host/team states received for each host */
79 static XBHostState hostStateReq[MAX_HOSTS][MAX_HOSTS];
80 static XBTeamState teamStateReq[MAX_HOSTS][NUM_LOCAL_PLAYER][MAX_HOSTS];
81
82 /* constant team color assignment for team states */
83 const XBColor teamColors[NUM_XBTS] = {
84 COLOR_INVALID, COLOR_INVALID, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_INVALID,
85 };
86
87 /***************
88 * local stuff *
89 ***************/
90
91 /*
92 * reset host data
93 */
94 static void
ClearHostLocalData(unsigned id)95 ClearHostLocalData (unsigned id)
96 {
97 unsigned host;
98 unsigned pl;
99 /* update total player count first */
100 players -= localPlayers[id];
101 /* clear data for host id */
102 hostPing[id] = -1;
103 hostState[id] = XBHS_None;
104 localPlayers[id] = 0;
105 for (pl = 0; pl < NUM_LOCAL_PLAYER; pl++) {
106 hostPlayer[id][pl] = ATOM_INVALID;
107 hostPlayer2[id][pl] = ATOM_INVALID;
108 teamState[id][pl] = XBTS_Invalid;
109 }
110 for (host = 0; host < MAX_HOSTS; host++) {
111 hostStateReq[id][host] = XBHS_None;
112 hostStateReq[host][id] = XBHS_None;
113 for (pl = 0; pl < NUM_LOCAL_PLAYER; pl++) {
114 defTeam[id][pl] = XBTS_Red;
115 teamStateReq[id][pl][host] = XBTS_Invalid;
116 teamStateReq[host][pl][id] = XBTS_Invalid;
117 }
118 }
119 } /* ClearHostLocalData */
120
121 /******************
122 * initialization *
123 ******************/
124
125 /*
126 * clear all host data
127 */
128 void
Network_ClearHost(unsigned id)129 Network_ClearHost (unsigned id)
130 {
131 ClearHostLocalData (id);
132 Version_Remove (id);
133 DeleteGameConfig (CT_Remote, LOCALGAMECONFIG (id));
134 Dbg_Network ("cleared host data #%u\n", id);
135 } /* Network_ClearHost */
136
137 /*
138 * clear all host, event, chat and version data
139 */
140 void
Network_Clear(void)141 Network_Clear (void)
142 {
143 unsigned id, pl;
144 /* clear data */
145 localId = MAX_HOSTS;
146 players = 0;
147 memset (hostPlayer, 0, sizeof (hostPlayer));
148 memset (hostPlayer2, 0, sizeof (hostPlayer2));
149 memset (localPlayers, 0, sizeof (localPlayers));
150 memset (hostPing, -1, sizeof (hostPing));
151 memset (hostState, 0, sizeof (hostState));
152 memset (hostStateReq, 0, sizeof (hostStateReq));
153 memset (teamState, 0, sizeof (teamState));
154 memset (teamStateReq, 0, sizeof (teamStateReq));
155 /* clear remote game configs and versions in database */
156 for (id = 0; id < MAX_HOSTS; id++) {
157 DeleteGameConfig (CT_Remote, LOCALGAMECONFIG (id));
158 for (pl = 0; pl < NUM_LOCAL_PLAYER; pl++) {
159 defTeam[id][pl] = XBTS_Red;
160 }
161 }
162 /* clear global game config and links */
163 global = XBFalse;
164 DeleteGameConfig (CT_Remote, SERVERGAMECONFIG);
165 memset (s2l, 0xFF, sizeof (s2l));
166 memset (l2s, 0xFF, sizeof (l2s));
167 /* reset version management */
168 Version_Reset ();
169 Network_SetType (XBNT_None);
170 #ifdef DEBUG_NETWORK
171 Dbg_Network ("cleared all host data\n");
172 #endif
173 } /* Network_Clear */
174
175 /************************************
176 * network events for client/server *
177 ************************************/
178
179 #ifdef DEBUG_NETWORK
180 /*
181 * network event to string
182 */
183 static const char *
NWEventName(XBNetworkEvent msg)184 NWEventName (XBNetworkEvent msg)
185 {
186 switch (msg) {
187 case XBNW_None:
188 return "None";
189 case XBNW_Accepted:
190 return "Accepted";
191 case XBNW_GameConfig:
192 return "GameConfig";
193 case XBNW_RightPlayerConfig:
194 return "RightPlayerConfig";
195 case XBNW_LeftPlayerConfig:
196 return "LeftPlayerConfig";
197 case XBNW_Joy1PlayerConfig:
198 return "Joy1PlayerConfig";
199 case XBNW_Joy2PlayerConfig:
200 return "Joy2PlayerConfig";
201 case XBNW_Disconnected:
202 return "Disconnected";
203 case XBNW_StartGame:
204 return "StartGame";
205 case XBNW_EndOfInit:
206 return "EndOfInit";
207 case XBNW_LevelConfig:
208 return "LevelConfig";
209 case XBNW_SyncEndOfInit:
210 return "SyncEndOfInit";
211 case XBNW_SyncLevelIntro:
212 return "SyncLevelIntro";
213 case XBNW_SyncLevelResult:
214 return "SyncLevelResult";
215 case XBNW_SyncLevelEnd:
216 return "SyncLevelEnd";
217 case XBNW_SyncScoreboard:
218 return "SyncScoreboard";
219 case XBNW_HostIsIn:
220 return "HostIsIn";
221 case XBNW_HostIsOut:
222 return "HostIsOut";
223 case XBNW_Error:
224 return "Error";
225 case XBNW_PingReceived:
226 return "PingReceived";
227 case XBNW_NetworkGame:
228 return "NetworkGame";
229 case XBNW_TeamChange:
230 return "TeamChange";
231 case XBNW_TeamChangeData:
232 return "TeamChangeData";
233 case XBNW_HostChange:
234 return "HostChange";
235 default:
236 return "unknown";
237 }
238 } /* EventName */
239 #endif
240
241 /*
242 * clear event queue
243 */
244 void
Network_ClearEvents(void)245 Network_ClearEvents (void)
246 {
247 unsigned id;
248 while (NULL != queueFirst) {
249 (void)Network_GetEvent (&id);
250 }
251 #ifdef DEBUG_NETWORK
252 Dbg_Network ("clearing all network events\n");
253 #endif
254 } /* Network_ClearEvents */
255
256 /*
257 * add event to queue
258 */
259 void
Network_QueueEvent(XBNetworkEvent msg,unsigned id)260 Network_QueueEvent (XBNetworkEvent msg, unsigned id)
261 {
262 /* alloc data */
263 XBNetworkEventQueue *ptr = calloc (1, sizeof (XBNetworkEventQueue));
264 assert (ptr != NULL);
265 /* set values */
266 ptr->msg = msg;
267 ptr->id = id;
268 /* put in queue */
269 if (queueLast != NULL) {
270 queueLast->next = ptr;
271 }
272 else {
273 queueFirst = ptr;
274 }
275 queueLast = ptr;
276 #ifdef DEBUG_NETWORK
277 Dbg_Network ("queue network event %s %u\n", NWEventName (msg), id);
278 #endif
279 } /* QueueEvent */
280
281 /*
282 * check for event in queue
283 */
284 XBNetworkEvent
Network_GetEvent(unsigned * pId)285 Network_GetEvent (unsigned *pId)
286 {
287 XBNetworkEventQueue *ptr;
288 XBNetworkEvent msg;
289
290 assert (NULL != pId);
291 if (NULL == queueFirst) {
292 return XBNW_None;
293 }
294 /* take element from list */
295 ptr = queueFirst;
296 queueFirst = queueFirst->next;
297 if (NULL == queueFirst) {
298 queueLast = NULL;
299 }
300 /* set results */
301 msg = ptr->msg;
302 *pId = ptr->id;
303 #ifdef DEBUG_NETWORK
304 Dbg_Network ("get network event %s %u\n", NWEventName (msg), *pId);
305 #endif
306 /* free element */
307 free (ptr);
308 /* that's all */
309 return msg;
310 } /* Network_GetEvent */
311
312 /*******************
313 * type of network *
314 *******************/
315
316 /*
317 * get network type
318 */
319 XBNetworkType
Network_GetType(void)320 Network_GetType (void)
321 {
322 return nettype;
323 } /* Network_GetType */
324
325 /*
326 * set network type
327 */
328 void
Network_SetType(XBNetworkType type)329 Network_SetType (XBNetworkType type)
330 {
331 nettype = type;
332 #ifdef DEBUG_NETWORK
333 Dbg_Network ("setting type to %u\n", type);
334 #endif
335 } /* Network_SetType */
336
337 /************
338 * local id *
339 ************/
340
341 /*
342 * receive local host id
343 */
344 void
Network_ReceiveLocalHostId(unsigned id)345 Network_ReceiveLocalHostId (unsigned id)
346 {
347 Dbg_Network ("receiving local host id = %u\n", id);
348 localId = id & 0xFF;
349 } /* Network_ReceiveLocalHostId */
350
351 /*
352 * get local host id
353 */
354 unsigned char
Network_LocalHostId(void)355 Network_LocalHostId (void)
356 {
357 return localId;
358 } /* Network_LocalHostId */
359
360 /**************
361 * ping times *
362 **************/
363
364 /*
365 * get ping time of host
366 */
367 int
Network_GetPingTime(unsigned id)368 Network_GetPingTime (unsigned id)
369 {
370 assert (id < MAX_HOSTS);
371 return hostPing[id];
372 } /* Network_GetPingTime */
373
374 /*
375 * ping received
376 */
377 void
Network_ReceivePing(unsigned id,int ping)378 Network_ReceivePing (unsigned id, int ping)
379 {
380 assert (id < MAX_HOSTS);
381 if (hostPing[id] != ping) {
382 Network_QueueEvent (XBNW_PingReceived, id);
383 }
384 hostPing[id] = ping;
385 } /* Network_ReceivePing */
386
387 /****************
388 * player atoms *
389 ****************/
390
391 /*
392 * get player atom
393 */
394 XBAtom
Network_GetPlayer(unsigned id,int player)395 Network_GetPlayer (unsigned id, int player)
396 {
397 assert (id < MAX_HOSTS);
398 assert (player < MAX_PLAYER);
399 return hostPlayer[id][player];
400 } /* Network_GetPlayer */
401
402 /*
403 * get player atom
404 */
405 XBAtom
Network_GetPlayer2(unsigned id,int player)406 Network_GetPlayer2 (unsigned id, int player)
407 {
408 assert (id < MAX_HOSTS);
409 assert (player < MAX_PLAYER);
410 return hostPlayer2[id][player];
411 } /* Network_GetPlayer2 */
412
413 /*
414 * set player atom
415 */
416 void
Network_SetPlayer(unsigned id,int player,XBAtom atom)417 Network_SetPlayer (unsigned id, int player, XBAtom atom)
418 {
419 assert (id < MAX_HOSTS);
420 assert (player < MAX_PLAYER);
421 hostPlayer[id][player] = atom;
422 if (atom != ATOM_INVALID) {
423 players += 1;
424 localPlayers[id] += 1;
425 }
426 } /* Network_SetPlayer */
427
428 /*
429 * set player atom
430 */
431 void
Network_SetPlayer2(unsigned id,int player,XBAtom atom)432 Network_SetPlayer2 (unsigned id, int player, XBAtom atom)
433 {
434 assert (id < MAX_HOSTS);
435 assert (player < MAX_PLAYER);
436 hostPlayer2[id][player] = atom;
437 } /* Network_SetPlayer2 */
438
439 /*
440 * get first player different from given one
441 */
442 XBBool
Network_GetFirstOtherPlayer(unsigned char id,unsigned char pl,unsigned char * h,unsigned char * p)443 Network_GetFirstOtherPlayer (unsigned char id, unsigned char pl, unsigned char *h, unsigned char *p)
444 {
445 *h = 0;
446 *p = 0;
447 if (hostPlayer2[0][0] != ATOM_INVALID) {
448 if (id != 0 || pl < NUM_LOCAL_PLAYER) {
449 return XBTrue;
450 }
451 }
452 return Network_GetNextOtherPlayer (id, pl, h, p);
453 } /* Network_GetFirstOtherPlayer */
454
455 /*
456 * get next player different from given one
457 */
458 XBBool
Network_GetNextOtherPlayer(unsigned char id,unsigned char pl,unsigned char * h,unsigned char * p)459 Network_GetNextOtherPlayer (unsigned char id, unsigned char pl, unsigned char *h, unsigned char *p)
460 {
461 *p += 1;
462 while (*h < MAX_HOSTS) {
463 if (id != *h || pl < NUM_LOCAL_PLAYER) {
464 while (*p < NUM_LOCAL_PLAYER) {
465 if ((hostPlayer2[*h][*p] != ATOM_INVALID) && (*h != id || *p != pl)) {
466 Dbg_Chat ("next = %s (%u,%u)\n", GUI_AtomToString (hostPlayer2[*h][*p]), *h,
467 *p);
468 return XBTrue;
469 }
470 *p += 1;
471 }
472 }
473 *h += 1;
474 *p = 0;
475 }
476 return XBFalse;
477 } /* Network_GetNextOtherPlayer */
478
479 /*************
480 * host data *
481 *************/
482
483 /*
484 * return player max for host, for check against global game config
485 */
486 unsigned
Network_HostPlayerMax(unsigned id)487 Network_HostPlayerMax (unsigned id)
488 {
489 CFGGameConst con;
490 unsigned max = -1;
491 assert (id < MAX_HOSTS);
492 (void)RetrieveGameConst (CT_Remote, LOCALGAMECONFIG (id), &con);
493 max = 8 * con.maxbytes - 1;
494 max = (max < con.maxplayers) ? max : con.maxplayers;
495 return max;
496 } /* Network_HostPlayerMax */
497
498 /***************
499 * game config *
500 ***************/
501
502 /*
503 * create global game config from current setup
504 */
505 XBGameConfigResult
Network_CreateGlobalGameConfig(CFGGame * cfg)506 Network_CreateGlobalGameConfig (CFGGame * cfg)
507 {
508 CFGGamePlayers localcfg;
509 unsigned char t[NUM_XBTS];
510 unsigned char p, save;
511 XBTeamState team = XBTS_Invalid;
512 unsigned char id, pl, host;
513 assert (cfg != NULL);
514 Dbg_Network ("creating global game config\n");
515 memset (t, 0, sizeof (t));
516 p = 0;
517 for (id = 0, host = XBPH_Server; id < MAX_HOSTS; id++, host++) {
518 /* first check if host is allowed to take part */
519 if (!Network_HostIsIn (id)) {
520 Dbg_Network ("host #%u ignored, is out\n", id);
521 continue;
522 }
523 /* now get player data for host */
524 if (!RetrieveGamePlayers (CT_Remote, LOCALGAMECONFIG (id), &localcfg)) {
525 Dbg_Network ("failed to get players for host #%u, failure\n", id);
526 return XBGC_Error;
527 }
528 /* check number of players */
529 if (localcfg.num == 0) {
530 Dbg_Network ("no players for host #%u, failure\n", id);
531 return XBGC_Error;
532 }
533 /* add each player */
534 save = p;
535 for (pl = 0; pl < localcfg.num; pl++) {
536 team = Network_GetTeamState (id, pl);
537 if (team == XBTS_Out) {
538 Dbg_Network ("player %u(%u) is out, ignoring\n", id, pl);
539 continue;
540 }
541 if (p >= MAX_PLAYER) {
542 Dbg_Network ("more players than I can handle (=%u)!\n", MAX_PLAYER);
543 return XBGC_TooManyPlayers;
544 }
545 cfg->players.player[p] = Network_GetPlayer (id, pl);
546 if (ATOM_INVALID == cfg->players.player[p]) {
547 Dbg_Network ("player #%u(%u) has no name, failure\n", id, pl);
548 return XBGC_Error;
549 }
550 cfg->players.control[p] = localcfg.control[pl];
551 if (XBPC_None == cfg->players.control[p]) {
552 Dbg_Network ("warning, player #%u(%u) has no control\n", id, pl);
553 }
554 cfg->players.playerID[p] = localcfg.playerID[pl];
555 cfg->players.host[p] = host;
556 cfg->players.team[p] = team;
557 Dbg_Network ("adding player #%u(%u)=%s, team %u\n", id, pl,
558 GUI_AtomToString (cfg->players.player[p]), team);
559 p += 1;
560 t[team] += 1;
561 }
562 if (save == p) {
563 Dbg_Network ("host %u has no active players, will only watch/chat!\n", id);
564 }
565 }
566 cfg->players.num = p;
567 cfg->setup.maskBytes = (int)(1 + p / 8);
568 Dbg_Network ("--- Results of game config creation ---\n");
569 /* check for invalid teams */
570 if (t[XBTS_Invalid] > 0) {
571 Dbg_Network ("%u invalid teams were assigned, failure", t[XBTS_Invalid]);
572 return XBGC_Error;
573 }
574 /* check player count */
575 if (p <= 1) {
576 Dbg_Network ("at least two players are required!\n");
577 return XBGC_SingleTeam;
578 }
579 /* check for chaos mode */
580 if (t[XBTS_None] == p) {
581 Dbg_Network ("created game config with %u players, chaos mode\n", p);
582 cfg->setup.teamMode = XBTM_None;
583 return XBGC_Global;
584 }
585 else if (t[XBTS_None] > 0) {
586 Dbg_Network ("invalid team mode, failure\n");
587 return XBGC_Error;
588 }
589 /* check for multiple teams */
590 for (team = XBTS_Red; team < NUM_XBTS; team++) {
591 if (t[team] < p) {
592 Dbg_Network ("%u players assigned to team %u\n", t[team], team);
593 }
594 else {
595 Dbg_Network ("all players assigned to team %u\n", team);
596 return XBGC_SingleTeam;
597 }
598 }
599 Dbg_Network ("created game config with %u players, team mode\n", p);
600 cfg->setup.teamMode = XBTM_Team;
601 return XBGC_Global;
602 } /* Network_CreateGameConfig */
603
604 /*
605 * store game config from server or client in database
606 */
607 XBGameConfigResult
Network_ReceiveGameConfig(unsigned id,const char * data)608 Network_ReceiveGameConfig (unsigned id, const char *data)
609 {
610 XBAtom atom;
611 CFGGamePlayers cfg;
612 CFGGameConst con;
613 XBVersion ver;
614 XBBool loc;
615 unsigned char p;
616 /* check if valid id was received */
617 if (id >= MAX_HOSTS) {
618 return XBGC_HostInvalid;
619 }
620 /* set section atom to write to */
621 atom = (id == 0) ? SERVERGAMECONFIG : LOCALGAMECONFIG (id);
622 if (NULL != data) {
623 /* write data and return */
624 AddToGameConfig (CT_Remote, atom, data);
625 return XBGC_Unfinished;
626 }
627 /* game config complete */
628 Dbg_Network ("received game config from host #%u\n", id);
629 /* extract player data in struct, shouldn't fail */
630 if (!RetrieveGamePlayers (CT_Remote, atom, &cfg)) {
631 Dbg_Network ("error in game config\n");
632 return XBGC_Error;
633 }
634 /* check if empty */
635 if (cfg.num == 0) {
636 Dbg_Network ("no players found\n");
637 return XBGC_Empty;
638 }
639 Dbg_Network ("game config contains %u players\n", cfg.num);
640 /* check for too many players */
641 if (cfg.num > MAX_PLAYER) {
642 Dbg_Network ("too many players found\n");
643 return XBGC_TooManyPlayers;
644 }
645 /* extract constants, should not fail */
646 if (!RetrieveGameConst (CT_Remote, atom, &con)) {
647 Dbg_Network ("failed to get constants\n");
648 return XBGC_Error;
649 }
650 /* check for existing version */
651 if (!Version_isDefined (&con.version)) {
652 Dbg_Network ("no version sent\n");
653 return XBGC_NoVersion;
654 }
655 Dbg_Network ("remote constants: MH=%u, MP=%u, ML=%u, MB=%u\n", con.maxhosts, con.maxplayers,
656 con.maxlocals, con.maxbytes);
657 /* register version */
658 if (Version_Join (id & 0xFF, &con.version)) {
659 Version_Get (VERSION_JOINT, &ver);
660 Dbg_Network ("joint version updated to %s\n", Version_ToString (&ver));
661 }
662 /* check type, at least one player has been sent */
663 loc = (cfg.host[0] == XBPH_Local);
664 for (p = 0; p < cfg.num; p++) {
665 if (ATOM_INVALID == cfg.player[p]) {
666 Dbg_Network ("player #%u has no name, error\n", p);
667 return XBGC_Error;
668 }
669 if (loc != (cfg.host[p] == XBPH_Local)) {
670 Dbg_Network ("error in game config\n");
671 return XBGC_Error;
672 }
673 }
674 Dbg_Network ("game config type = %s\n", loc ? "local" : "global");
675 return loc ? XBGC_Local : XBGC_Global;
676 } /* Network_ReceiveGameConfig */
677
678 /*
679 * create local players from game config id
680 */
681 unsigned
Network_CreateLocalPlayers(unsigned id)682 Network_CreateLocalPlayers (unsigned id)
683 {
684 CFGGame cfg;
685 XBVersion ver;
686 XBAtom atom;
687 unsigned p;
688 char name[256];
689 assert (id < MAX_HOSTS);
690 /* get remote atom with received data */
691 atom = (id == 0) ? SERVERGAMECONFIG : LOCALGAMECONFIG (id);
692 /* extract data in struct, shouldn't fail */
693 if (!RetrieveGame (CT_Remote, atom, &cfg)) {
694 Dbg_Network ("error in game config!?\n");
695 return NUM_LOCAL_PLAYER;
696 }
697 /* check local player max */
698 if (cfg.players.num > NUM_LOCAL_PLAYER) {
699 Dbg_Network ("create failed, too many local players\n");
700 return NUM_LOCAL_PLAYER;
701 }
702 /* clear local data */
703 ClearHostLocalData (id);
704 /* for server data, store as local game config */
705 if (id == 0) {
706 StoreGame (CT_Remote, LOCALGAMECONFIG (0), &cfg);
707 if (RetrieveGameVersion (CT_Remote, atom, &ver)) {
708 StoreGameVersion (CT_Remote, LOCALGAMECONFIG (0), &ver);
709 }
710 }
711 /* add players from game config */
712 for (p = 0; p < cfg.players.num; p++) {
713 /* first add name atom, must be valid */
714 assert (ATOM_INVALID != cfg.players.player[p]);
715 Network_SetPlayer2 (id, p, cfg.players.player[p]);
716 /* use plain name as section name for server */
717 atom = cfg.players.player[p];
718 /* add @host:port for non-server, to make it unique */
719 if (id != 0) {
720 sprintf (name, "%s@%s:%d", GUI_AtomToString (atom), cfg.host.name, cfg.host.port);
721 atom = GUI_StringToAtom (name);
722 }
723 /* now store player section atom */
724 Network_SetPlayer (id, p, atom);
725 Dbg_Network ("hostPlayer[%u][%d] = %s\n", id, p, GUI_AtomToString (atom));
726 /* set chat controls */
727 if (localId == id) {
728 switch (cfg.players.control[p]) {
729 case XBPC_RightKeyboard:
730 Dbg_Network ("local player #%u on right keyboard, enabling chat\n", id);
731 Chat_AddEventCode (p, XBE_KEYB_1);
732 break;
733 case XBPC_LeftKeyboard:
734 Dbg_Network ("local player #%u on left keyboard, enabling chat\n", id);
735 Chat_AddEventCode (p, XBE_KEYB_2);
736 break;
737 default:
738 Dbg_Network ("local player #%u has no keyboard control, no chatting\n", id);
739 break;
740 }
741 }
742 }
743 Dbg_Network ("created %u players, total %u\n", cfg.players.num, players);
744 return cfg.players.num;
745 } /* Network_CreateLocalPlayers */
746
747 /*
748 * create global players from game config, only allowed from server
749 */
750 unsigned
Network_CreateGlobalPlayers(unsigned id)751 Network_CreateGlobalPlayers (unsigned id)
752 {
753 unsigned h, p, pl;
754 assert (id == 0);
755 /* extract data in struct, shouldn't fail */
756 if (!RetrieveGame (CT_Remote, SERVERGAMECONFIG, &globalcfg)) {
757 Dbg_Network ("error in game config!?\n");
758 return MAX_PLAYER;
759 }
760 /* check max player */
761 if (globalcfg.players.num > MAX_PLAYER) {
762 Dbg_Network ("create failed, too many global players\n");
763 return MAX_PLAYER;
764 }
765 /* check mask bytes */
766 if (globalcfg.setup.maskBytes > MAX_MASK_BYTES) {
767 Dbg_Network ("create failed, too many mask bytes\n");
768 return MAX_PLAYER;
769 }
770 /* now link with local */
771 memset (s2l, 0xFF, sizeof (s2l));
772 memset (l2s, 0xFF, sizeof (l2s));
773 for (pl = 0; pl < globalcfg.players.num; pl++) {
774 for (h = 0; h < MAX_HOSTS; h++) {
775 for (p = 0; p < localPlayers[h]; p++) {
776 if (globalcfg.players.player[pl] == hostPlayer[h][p]) {
777 Dbg_Network ("linking global player %u with local player #%u(%u)\n", pl, h, p);
778 s2l[pl].host = h;
779 s2l[pl].player = p;
780 l2s[h][p] = pl;
781 break;
782 }
783 }
784 }
785 if (s2l[pl].host >= MAX_HOSTS) {
786 Dbg_Network ("failed to match global player with local\n");
787 return MAX_PLAYER;
788 }
789 }
790 /* success */
791 global = XBTrue;
792 return globalcfg.players.num;
793 } /* Network_CreateGlobalPlayers */
794
795 /*
796 * getting current mask bytes
797 */
798 unsigned
Network_GetMaskBytes(void)799 Network_GetMaskBytes (void)
800 {
801 /* no mask bytes if no global game config */
802 if (!global) {
803 return 0;
804 }
805 return globalcfg.setup.maskBytes;
806 } /* Network_GetMaskBytes */
807
808 /*****************
809 * player config *
810 *****************/
811
812 /*
813 * player config received from client
814 */
815 XBAtom
Network_ReceivePlayerConfig(CFGType cfgType,unsigned id,int player,const char * line)816 Network_ReceivePlayerConfig (CFGType cfgType, unsigned id, int player, const char *line)
817 {
818 XBAtom atom;
819
820 assert (id < MAX_HOSTS);
821 assert (player < NUM_LOCAL_PLAYER);
822 /* get player for config */
823 atom = Network_GetPlayer (id, player);
824 if (ATOM_INVALID == atom) {
825 return ATOM_INVALID;
826 }
827 /* check if there is any data */
828 if (NULL != line) {
829 AddToPlayerConfig (cfgType, atom, line);
830 /* ok that's all for now */
831 return ATOM_INVALID;
832 }
833 /* all data received */
834 Dbg_Network ("received player config for %u(%u)\n", id, player);
835 switch (player) {
836 case 0:
837 Network_QueueEvent (XBNW_RightPlayerConfig, id);
838 break;
839 case 1:
840 Network_QueueEvent (XBNW_LeftPlayerConfig, id);
841 break;
842 case 2:
843 Network_QueueEvent (XBNW_Joy1PlayerConfig, id);
844 break;
845 case 3:
846 Network_QueueEvent (XBNW_Joy2PlayerConfig, id);
847 break;
848 default:
849 break;
850 }
851 return atom;
852 } /* Network_ReceivePlayerConfig */
853
854 /******************
855 * state requests *
856 ******************/
857
858 /*
859 * receive host state for a host
860 */
861 XBBool
Network_ReceiveHostState(unsigned id,XBHostState state)862 Network_ReceiveHostState (unsigned id, XBHostState state)
863 {
864 if (id < MAX_HOSTS) {
865 hostState[id] = state;
866 Network_QueueEvent (XBNW_HostChange, id);
867 return XBTrue;
868 }
869 return XBFalse;
870 } /* Network_ReceiveHostState */
871
872 /*
873 * receive host state request for a host
874 */
875 XBBool
Network_ReceiveHostStateReq(unsigned who,unsigned id,XBHostState state)876 Network_ReceiveHostStateReq (unsigned who, unsigned id, XBHostState state)
877 {
878 if (who < MAX_HOSTS && id < MAX_HOSTS) {
879 hostStateReq[id][who] = state;
880 return XBTrue;
881 }
882 return XBFalse;
883 } /* Network_ReceiveHostStateReq */
884
885 /*
886 * receive team state for a host/player
887 */
888 XBBool
Network_ReceiveTeamState(unsigned host,unsigned player,XBTeamState team)889 Network_ReceiveTeamState (unsigned host, unsigned player, XBTeamState team)
890 {
891 if (host < MAX_HOSTS && player < MAX_PLAYER) {
892 teamState[host][player] = team;
893 return XBTrue;
894 }
895 return XBFalse;
896 } /* Network_ReceiveTeamState */
897
898 /*
899 * receive team state for a host/player
900 */
901 XBBool
Network_ReceiveTeamStateReq(unsigned who,unsigned host,unsigned player,XBTeamState team)902 Network_ReceiveTeamStateReq (unsigned who, unsigned host, unsigned player, XBTeamState team)
903 {
904 if (who < MAX_HOSTS && host < MAX_HOSTS && player < MAX_PLAYER) {
905 teamStateReq[host][player][who] = team;
906 return XBTrue;
907 }
908 return XBFalse;
909 } /* Network_ReceiveTeamStateReq */
910
911 /*
912 * return host state
913 */
914 XBHostState
Network_GetHostState(unsigned id)915 Network_GetHostState (unsigned id)
916 {
917 assert (id < MAX_HOSTS);
918 return hostState[id];
919 } /* Network_GetHostState */
920
921 /*
922 * return if host is in
923 */
924 XBBool
Network_HostIsIn(unsigned id)925 Network_HostIsIn (unsigned id)
926 {
927 switch (Network_GetHostState (id)) {
928 case XBHS_Server:
929 case XBHS_In:
930 case XBHS_Ready:
931 return XBTrue;
932 default:
933 return XBFalse;
934 }
935 } /* Network_HostIsIn */
936
937 /*
938 * store current teams as default
939 */
940 void
Network_SetDefaultTeams(unsigned host,unsigned player)941 Network_SetDefaultTeams (unsigned host, unsigned player)
942 {
943 unsigned id, pl;
944 for (id = 0; id < MAX_HOSTS; id++) {
945 for (pl = 0; pl < NUM_LOCAL_PLAYER; pl++) {
946 if (teamState[id][pl] > XBTS_None) {
947 defTeam[id][pl] = teamState[id][pl];
948 }
949 }
950 }
951 defTeam[host][player] = XBTS_Red;
952 } /* Network_SetDefaultTeams */
953
954 /*
955 * return default team state
956 */
957 XBTeamState
Network_GetDefaultTeam(unsigned id,unsigned player)958 Network_GetDefaultTeam (unsigned id, unsigned player)
959 {
960 assert (id < MAX_HOSTS);
961 assert (player < NUM_LOCAL_PLAYER);
962 return defTeam[id][player];
963 } /* Network_GetTeamState */
964
965 /*
966 * return team state
967 */
968 XBTeamState
Network_GetTeamState(unsigned id,unsigned player)969 Network_GetTeamState (unsigned id, unsigned player)
970 {
971 assert (id < MAX_HOSTS);
972 assert (player < NUM_LOCAL_PLAYER);
973 return teamState[id][player];
974 } /* Network_GetTeamState */
975
976 /*
977 * return host state requests
978 */
979 XBHostState *
Network_GetHostStateReq(unsigned id)980 Network_GetHostStateReq (unsigned id)
981 {
982 assert (id < MAX_HOSTS);
983 return &hostStateReq[id][0];
984 } /* Network_GetHostStateReq */
985
986 /*
987 * return team state requests
988 */
989 XBTeamState *
Network_GetTeamStateReq(unsigned id,unsigned player)990 Network_GetTeamStateReq (unsigned id, unsigned player)
991 {
992 assert (id < MAX_HOSTS);
993 assert (player < NUM_LOCAL_PLAYER);
994 return &teamStateReq[id][player][0];
995 } /* Network_GetTeamStateReq */
996
997 /*
998 * check if all clients agree on a state for a host (at least two)
999 */
1000 XBBool
Network_HostReqClientsAgree(unsigned host,XBHostState state)1001 Network_HostReqClientsAgree (unsigned host, XBHostState state)
1002 {
1003 unsigned id;
1004 unsigned count = 0;
1005 for (id = 1; id < MAX_HOSTS; id++) {
1006 if (id != host) {
1007 switch (hostState[id]) {
1008 case XBHS_In:
1009 case XBHS_Ready:
1010 if (state != hostStateReq[host][id]) {
1011 return XBFalse;
1012 }
1013 count++;
1014 break;
1015 default:
1016 break;
1017 }
1018 }
1019 }
1020 return (count > 1);
1021 } /* Network_HostReqClientsAgree */
1022
1023 /*
1024 * check if all clients are ready (at least one)
1025 */
1026 XBBool
Network_ClientsReady(void)1027 Network_ClientsReady (void)
1028 {
1029 unsigned id;
1030 unsigned count = 0;
1031 for (id = 1; id < MAX_HOSTS; id++) {
1032 switch (hostState[id]) {
1033 case XBHS_Ready:
1034 count++;
1035 case XBHS_None:
1036 break;
1037 default:
1038 return XBFalse;
1039 }
1040 }
1041 return (count > 0);
1042 } /* Network_ClientsReady */
1043
1044 /*
1045 * check if clients agree on team state (at least two)
1046 */
1047 XBBool
Network_TeamReqClientsAgree(unsigned host,unsigned player,unsigned state)1048 Network_TeamReqClientsAgree (unsigned host, unsigned player, unsigned state)
1049 {
1050 unsigned id;
1051 unsigned count = 0;
1052 for (id = 1; id < MAX_HOSTS; id++) {
1053 if (id != host) {
1054 switch (hostState[id]) {
1055 case XBHS_In:
1056 case XBHS_Ready:
1057 if (state != teamStateReq[host][player][id]) {
1058 return XBFalse;
1059 }
1060 count++;
1061 break;
1062 default:
1063 break;
1064 }
1065 }
1066 }
1067 return (count > 1);
1068 } /* Network_TeamReqClientsAgree */
1069
1070 /*
1071 * end of file network.c
1072 */
1073