2 * Copyright (C) Volition, Inc. 2005. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
11 //Game Tracker client code
14 InitGameTracker(int game_type); //D3 or Freespace
16 //Call periodically so we can send our update, and make sure it is received
19 StartTrackerGame(void *buffer) //Call with a freespace_net_game_data or d3_net_game_data structure
20 //Call with a freespace_net_game_data or d3_net_game_data structure
21 //Updates our memory so when it is time, we send the latest game data
22 UpdateGameData(gamedata);
25 //Call to signify end of game
27 RequestGameList();//Sends a GNT_GAMELIST_REQ packet to the server.
29 game_list * GetGameList();//returns a pointer to a game_list struct
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
44 #include "multi_pxo.h"
50 SOCKADDR_IN gtrackaddr;
52 game_list GameBuffer[MAX_GAME_BUFFERS];
53 int GameType;//d3 or fs
55 unsigned int LastTrackerUpdate;
56 unsigned int LastSentToTracker;
57 unsigned int TrackerAckdUs;
58 unsigned int TrackerGameIsRunning;
60 game_packet_header TrackerGameData;
61 game_packet_header GameListReq;
62 game_packet_header TrackAckPacket;
63 game_packet_header GameOverPacket;
66 freespace_net_game_data *FreeSpaceTrackerGameData;
68 freespace2_net_game_data *FreeSpace2TrackerGameData;
72 unsigned int LastGameOverPacket;
73 unsigned int FirstGameOverPacket;
79 int InitGameTrackerClient(int gametype)
85 LastTrackerUpdate = 0;
93 TrackerGameData.len = GAME_HEADER_ONLY_SIZE+sizeof(freespace_net_game_data);
102 TrackerGameData.len = GAME_HEADER_ONLY_SIZE+sizeof(freespace2_net_game_data);
110 TrackerGameData.game_type = (unsigned char)gametype; //1==freespace (GT_FREESPACE), 2==D3, 3==tuberacer, etc.
111 TrackerGameData.type = GNT_GAMEUPDATE; //Used to specify what to do ie. Add a new net game (GNT_GAMESTARTED), remove a net game (game over), etc.
114 FreeSpaceTrackerGameData = (freespace_net_game_data *)&TrackerGameData.data;
116 FreeSpace2TrackerGameData = (freespace2_net_game_data *)&TrackerGameData.data;
119 GameListReq.game_type = (unsigned char)gametype;
120 GameListReq.type = GNT_GAMELIST_REQ;
121 GameListReq.len = GAME_HEADER_ONLY_SIZE;
123 TrackAckPacket.game_type = (unsigned char)gametype;
124 TrackAckPacket.len = GAME_HEADER_ONLY_SIZE;
125 TrackAckPacket.type = GNT_CLIENT_ACK;
127 GameOverPacket.game_type = (unsigned char)gametype;
128 GameOverPacket.len = GAME_HEADER_ONLY_SIZE;
129 GameOverPacket.type = GNT_GAMEOVER;
131 // gamesock = socket(AF_INET,SOCK_DGRAM,0);
134 if ( gamesock == INVALID_SOCKET )
136 printf("Unable to open a socket.\n");
141 memset( &sockaddr, 0, sizeof(SOCKADDR_IN) );
142 sockaddr.sin_family = AF_INET;
143 sockaddr.sin_addr.s_addr = INADDR_ANY;
144 sockaddr.sin_port = 0;//htons(GAMEPORT);
147 if (SOCKET_ERROR==bind(gamesock, (SOCKADDR*)&sockaddr, sizeof (sockaddr)))
149 printf("Unable to bind a socket.\n");
150 printf("WSAGetLastError() returned %d.\n",WSAGetLastError());
155 iaddr = inet_addr ( Multi_options_g.game_tracker_ip );
156 if ( iaddr == INADDR_NONE ) {
157 // first try and resolve by name
159 he = gethostbyname( Multi_options_g.game_tracker_ip );
164 // try and resolve by address
165 unsigned int n_order = inet_addr(Multi_game_tracker_ip_address);
166 he = gethostbyaddr((char*)&n_order,4,PF_INET);
173 memcpy(&iaddr, he->h_addr_list[0],4);
176 // This would be a good place to resolve the IP based on a domain name
177 memcpy(>rackaddr.sin_addr.s_addr, &iaddr, 4);
178 gtrackaddr.sin_family = AF_INET;
179 gtrackaddr.sin_port = htons( GAMEPORT );
188 void IdleGameTracker()
193 PSNET_TOP_LAYER_PROCESS();
197 if((TrackerGameIsRunning) && ((timer_get_seconds()-LastTrackerUpdate)>TRACKER_UPDATE_INTERVAL) && !SendingGameOver)
199 //Time to update the tracker again
200 SENDTO(Unreliable_socket, (char *)&TrackerGameData,TrackerGameData.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
202 LastTrackerUpdate = timer_get_seconds();
204 else if((TrackerGameIsRunning)&&(!TrackerAckdUs)&&((timer_get_milliseconds()-LastSentToTracker)>TRACKER_RESEND_TIME))
206 //We still haven't been acked by the last packet and it's time to resend.
207 SENDTO(Unreliable_socket, (char *)&TrackerGameData,TrackerGameData.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
209 LastTrackerUpdate = timer_get_seconds();
210 LastSentToTracker = timer_get_milliseconds();
215 if((timer_get_milliseconds()-LastGameOverPacket)>TRACKER_RESEND_TIME){
217 LastGameOverPacket = timer_get_milliseconds();
218 SENDTO(Unreliable_socket, (char *)&GameOverPacket,GameOverPacket.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
221 else if((timer_get_milliseconds()-FirstGameOverPacket)>NET_ACK_TIMEOUT) {
222 //Giving up, it timed out.
232 FD_SET(Unreliable_socket, &read_fds);
235 if(SELECT(0,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_GAME_TRACKER))
237 if(SELECT(Unreliable_socket+1,&read_fds,NULL,NULL,&timeout, PSNET_TYPE_GAME_TRACKER))
240 unsigned int bytesin;
242 SOCKADDR_IN fromaddr;
244 game_packet_header inpacket;
245 addrsize = sizeof(SOCKADDR_IN);
247 bytesin = RECVFROM(Unreliable_socket, (char *)&inpacket,sizeof(game_packet_header),0,(SOCKADDR *)&fromaddr,&addrsize, PSNET_TYPE_GAME_TRACKER);
250 int wserr=WSAGetLastError();
251 printf("RECVFROM() failure. WSAGetLastError() returned %d\n",wserr);
255 // subtract one from the header
258 //Check to make sure the packets ok
259 if(bytesin==inpacket.len)
261 switch(inpacket.type)
264 //The server got our packet so we can stop sending now
267 // 7/13/98 -- because of the FreeSpace iterative frame process -- set this value to 0, instead
268 // of to 2 (as it originally was) since we call SendGameOver() only once. Once we get the ack
269 // from the server, we can assume that we are done.
270 // need to mark this as 0
273 case GNT_GAMELIST_DATA:
275 //Woohoo! Game data! put it in the buffer (if one's free)
276 for(i=0;i<MAX_GAME_BUFFERS;i++)
278 if(GameBuffer[i].game_type==GT_UNUSED)
280 memcpy(&GameBuffer[i],&inpacket.data,sizeof(game_list));
281 i=MAX_GAME_BUFFERS+1;
286 case GNT_GAME_COUNT_DATA:
287 //Here, inpacket.data contains the following structure
290 // char channel[];//Null terminated
292 //You can add whatever code, or callback, etc. you need to deal with this data
294 // let the PXO screen know about this data
298 // get the user count
299 memcpy(&num_servers,inpacket.data,sizeof(int));
301 // copy the channel name
302 memset(channel,0,512);
303 strcpy(channel,inpacket.data+4);
305 // send it to the PXO screen
306 multi_pxo_channel_count_update(channel,num_servers);
309 AckPacket(inpacket.sig);
314 void UpdateGameData(void *buffer)
323 memcpy(FreeSpaceTrackerGameData,buffer,sizeof(freespace_net_game_data));
331 memcpy(FreeSpace2TrackerGameData,buffer,sizeof(freespace2_net_game_data));
341 game_list * GetGameList()
344 for(int i=0;i<MAX_GAME_BUFFERS;i++)
346 if(GameBuffer[i].game_type!=GT_UNUSED)
348 memcpy(&gl,&GameBuffer[i],sizeof(game_list));
349 GameBuffer[i].game_type = GT_UNUSED;
356 void RequestGameList()
358 GameListReq.len = GAME_HEADER_ONLY_SIZE;
359 SENDTO(Unreliable_socket, (char *)&GameListReq,GameListReq.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
362 void RequestGameListWithFilter(void *filter)
364 memcpy(&GameListReq.data,filter,sizeof(filter_game_list_struct));
365 GameListReq.len = GAME_HEADER_ONLY_SIZE+sizeof(filter_game_list_struct);
366 SENDTO(Unreliable_socket, (char *)&GameListReq,GameListReq.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
373 TrackerGameIsRunning = 0;
374 sendto(gamesock,(const char *)&GameOverPacket,GameOverPacket.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN));
381 if(SendingGameOver==2)
386 if(SendingGameOver==1)
388 //Wait until it's sent.
392 if(SendingGameOver==0)
394 LastGameOverPacket = timer_get_milliseconds();
395 FirstGameOverPacket = timer_get_milliseconds();
397 TrackerGameIsRunning = 0;
398 SENDTO(Unreliable_socket, (char *)&GameOverPacket,GameOverPacket.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
405 void AckPacket(int sig)
407 TrackAckPacket.sig = sig;
408 SENDTO(Unreliable_socket, (char *)&TrackAckPacket,TrackAckPacket.len,0,(SOCKADDR *)>rackaddr,sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);
411 void StartTrackerGame(void *buffer)
420 memcpy(FreeSpaceTrackerGameData,buffer,sizeof(freespace_net_game_data));
428 memcpy(FreeSpace2TrackerGameData,buffer,sizeof(freespace2_net_game_data));
436 TrackerGameIsRunning = 1;
437 LastTrackerUpdate = 0;
441 void RequestGameCountWithFilter(void *filter)
443 game_packet_header GameCountReq;
446 GameCountReq.game_type = GT_FREESPACE;
448 GameCountReq.game_type = GT_FREESPACE2;
450 GameCountReq.type = GNT_GAME_COUNT_REQ;
451 GameCountReq.len = GAME_HEADER_ONLY_SIZE+sizeof(filter_game_list_struct);
452 memcpy(&GameCountReq.data, ((filter_game_list_struct*)filter)->channel, sizeof(filter_game_list_struct) - 4);
453 SENDTO(Unreliable_socket, (char *)&GameCountReq, GameCountReq.len, 0, (SOCKADDR *)>rackaddr, sizeof(SOCKADDR_IN), PSNET_TYPE_GAME_TRACKER);