mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
408 lines
9.6 KiB
C
408 lines
9.6 KiB
C
/******
|
|
gt2nat.c
|
|
GameSpy Transport 2 SDK
|
|
|
|
Copyright 2000 GameSpy Industries, Inc
|
|
|
|
******
|
|
|
|
This sample demonstrates sharing a UDP socket with the Query & Reporting 2 SDK
|
|
to enable developers to create games that can be hosted behind a NAT.
|
|
|
|
Please see the GameSpy Query & Reporting 2 SDK documentation for more
|
|
information
|
|
|
|
******/
|
|
|
|
|
|
/********
|
|
INCLUDES
|
|
********/
|
|
#include "../gt2.h"
|
|
#include "../../qr2/qr2.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
#include <conio.h>
|
|
#endif
|
|
|
|
/********
|
|
DEFINES
|
|
********/
|
|
#define QR2_GAME_VERSION "2.00"
|
|
#define QR2_GAME_NAME "gmtest"
|
|
#define QR2_MAX_PLAYERS 32
|
|
#define QR2_BASE_PORT 26900
|
|
#define QR2_RANKINGSON_KEY 100
|
|
|
|
#ifdef _WIN32_WCE
|
|
void RetailOutputA(CHAR *tszErr, ...);
|
|
#define printf RetailOutputA
|
|
#endif
|
|
|
|
/********
|
|
TYPDEFS
|
|
********/
|
|
//representative of a game player structure
|
|
typedef struct
|
|
{
|
|
char pname[80];
|
|
int pfrags;
|
|
int pdeaths;
|
|
int pskill;
|
|
int pping;
|
|
char pteam[80];
|
|
} player_t;
|
|
|
|
//representative of a game data structure
|
|
typedef struct
|
|
{
|
|
player_t players[QR2_MAX_PLAYERS];
|
|
char mapname[20];
|
|
char hostname[120];
|
|
char gamemode[200];
|
|
char gametype[30];
|
|
int locationid;
|
|
int numplayers;
|
|
int maxplayers;
|
|
int fraglimit;
|
|
int timelimit;
|
|
int teamplay;
|
|
int rankingson;
|
|
int hostport;
|
|
} gamedata_t;
|
|
|
|
/********
|
|
GLOBAL VARS
|
|
********/
|
|
|
|
//just to give us bogus data
|
|
char *constnames[QR2_MAX_PLAYERS]={"Joe Player","L33t 0n3","Raptor","Gr81","Flubber","Sarge","Void","runaway","Ph3ar","wh00t","gr1nder","Mace","stacy","lamby","Thrush"};
|
|
gamedata_t gamedata;
|
|
|
|
// Called when a server key needs to be reported
|
|
void serverkey_callback(int keyid, qr2_buffer_t outbuf, void *userdata)
|
|
{
|
|
switch (keyid)
|
|
{
|
|
case HOSTNAME_KEY:
|
|
qr2_buffer_add(outbuf, gamedata.hostname);
|
|
break;
|
|
case GAMEVER_KEY:
|
|
qr2_buffer_add(outbuf, QR2_GAME_VERSION);
|
|
break;
|
|
case HOSTPORT_KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.hostport);
|
|
break;
|
|
case MAPNAME_KEY:
|
|
qr2_buffer_add(outbuf, gamedata.mapname);
|
|
break;
|
|
case GAMETYPE_KEY:
|
|
qr2_buffer_add(outbuf, gamedata.gametype);
|
|
break;
|
|
case NUMPLAYERS_KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.numplayers);
|
|
break;
|
|
case MAXPLAYERS_KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.maxplayers);
|
|
break;
|
|
case GAMEMODE_KEY:
|
|
qr2_buffer_add(outbuf, gamedata.gamemode);
|
|
break;
|
|
case TEAMPLAY_KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.teamplay);
|
|
break;
|
|
case FRAGLIMIT_KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.fraglimit);
|
|
break;
|
|
case TIMELIMIT_KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.timelimit);
|
|
break;
|
|
case QR2_RANKINGSON_KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.rankingson);
|
|
break;
|
|
default:
|
|
qr2_buffer_add(outbuf, _T(""));
|
|
}
|
|
|
|
GSI_UNUSED(userdata);
|
|
}
|
|
|
|
// Called when a player key needs to be reported
|
|
void playerkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata)
|
|
{
|
|
//check for valid index
|
|
if (index >= gamedata.numplayers)
|
|
{
|
|
qr2_buffer_add(outbuf, _T(""));
|
|
return;
|
|
}
|
|
switch (keyid)
|
|
{
|
|
case PLAYER__KEY:
|
|
qr2_buffer_add(outbuf, gamedata.players[index].pname);
|
|
break;
|
|
case SKILL__KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.players[index].pskill);
|
|
break;
|
|
case SCORE__KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.players[index].pfrags);
|
|
break;
|
|
case DEATHS__KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.players[index].pdeaths);
|
|
break;
|
|
case PING__KEY:
|
|
qr2_buffer_add_int(outbuf, gamedata.players[index].pping);
|
|
break;
|
|
case TEAM__KEY:
|
|
qr2_buffer_add(outbuf, gamedata.players[index].pteam);
|
|
break;
|
|
default:
|
|
qr2_buffer_add(outbuf, _T(""));
|
|
break;
|
|
}
|
|
|
|
GSI_UNUSED(userdata);
|
|
}
|
|
|
|
// Called when a team key needs to be reported
|
|
void teamkey_callback(int keyid, int index, qr2_buffer_t outbuf, void *userdata)
|
|
{
|
|
qr2_buffer_add(outbuf, _T(""));
|
|
|
|
GSI_UNUSED(userdata);
|
|
GSI_UNUSED(index);
|
|
GSI_UNUSED(keyid);
|
|
}
|
|
|
|
// Called when we need to report the list of keys we report values for
|
|
void keylist_callback(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata)
|
|
{
|
|
//need to add all the keys we support
|
|
switch (keytype)
|
|
{
|
|
case key_server:
|
|
qr2_keybuffer_add(keybuffer, HOSTNAME_KEY);
|
|
qr2_keybuffer_add(keybuffer, GAMEVER_KEY);
|
|
qr2_keybuffer_add(keybuffer, HOSTPORT_KEY);
|
|
qr2_keybuffer_add(keybuffer, MAPNAME_KEY);
|
|
qr2_keybuffer_add(keybuffer, GAMETYPE_KEY);
|
|
qr2_keybuffer_add(keybuffer, NUMPLAYERS_KEY);
|
|
qr2_keybuffer_add(keybuffer, NUMTEAMS_KEY);
|
|
qr2_keybuffer_add(keybuffer, MAXPLAYERS_KEY);
|
|
qr2_keybuffer_add(keybuffer, GAMEMODE_KEY);
|
|
qr2_keybuffer_add(keybuffer, TEAMPLAY_KEY);
|
|
qr2_keybuffer_add(keybuffer, FRAGLIMIT_KEY);
|
|
qr2_keybuffer_add(keybuffer, TIMELIMIT_KEY);
|
|
break;
|
|
case key_player:
|
|
qr2_keybuffer_add(keybuffer, PLAYER__KEY);
|
|
qr2_keybuffer_add(keybuffer, SCORE__KEY);
|
|
qr2_keybuffer_add(keybuffer, SKILL__KEY);
|
|
qr2_keybuffer_add(keybuffer, DEATHS__KEY);
|
|
qr2_keybuffer_add(keybuffer, PING__KEY);
|
|
qr2_keybuffer_add(keybuffer, TEAM__KEY);
|
|
break;
|
|
case key_team:
|
|
break;
|
|
}
|
|
|
|
GSI_UNUSED(userdata);
|
|
}
|
|
|
|
// Called when we need to report the number of players and teams
|
|
int count_callback(qr2_key_type keytype, void *userdata)
|
|
{
|
|
if (keytype == key_player)
|
|
return gamedata.numplayers;
|
|
else if (keytype == key_team)
|
|
return 0;
|
|
else
|
|
return 0;
|
|
|
|
GSI_UNUSED(userdata);
|
|
}
|
|
|
|
// Called if our registration with the GameSpy master server failed
|
|
void adderror_callback(qr2_error_t error, gsi_char *errmsg, void *userdata)
|
|
{
|
|
_tprintf(_T("Error adding server: %d, %s\n"), error, errmsg);
|
|
|
|
GSI_UNUSED(userdata);
|
|
}
|
|
|
|
/***********
|
|
init_game
|
|
Initialize the sample data structures with bogus data
|
|
************/
|
|
static void init_game(void)
|
|
{
|
|
int i;
|
|
int team;
|
|
|
|
srand((unsigned int) current_time() );
|
|
gamedata.numplayers = rand() % 15;
|
|
gamedata.maxplayers = QR2_MAX_PLAYERS;
|
|
for (i = 0 ; i < gamedata.numplayers ; i++)
|
|
{
|
|
strcpy(gamedata.players[i].pname, constnames[i]);
|
|
gamedata.players[i].pfrags = rand() % 32;
|
|
gamedata.players[i].pdeaths = rand() % 32;
|
|
gamedata.players[i].pskill = rand() % 1000;
|
|
gamedata.players[i].pping = rand() % 500;
|
|
team = rand() % 3;
|
|
if (team == 0)
|
|
strcpy(gamedata.players[i].pteam,"Red");
|
|
else if (team == 1)
|
|
strcpy(gamedata.players[i].pteam,"Blue");
|
|
else if (team == 2)
|
|
strcpy(gamedata.players[i].pteam,"");
|
|
}
|
|
strcpy(gamedata.mapname,"gmtmap1");
|
|
strcpy(gamedata.gametype,"arena");
|
|
strcpy(gamedata.hostname,"GameMaster Arena Server");
|
|
strcpy(gamedata.gamemode,"openplaying");
|
|
gamedata.fraglimit = 0;
|
|
gamedata.timelimit = 40;
|
|
gamedata.teamplay = 1;
|
|
gamedata.locationid = 1;
|
|
gamedata.rankingson = 1;
|
|
gamedata.hostport = 25000;
|
|
}
|
|
|
|
/*******
|
|
DoGameStuff
|
|
Simulate whatever else a game server does
|
|
********/
|
|
void DoGameStuff(void)
|
|
{
|
|
msleep(10);
|
|
}
|
|
|
|
GT2Bool UnrecognizedMessageCallback(GT2Socket socket, unsigned int ip, unsigned short port, GT2Byte * message, int len)
|
|
{
|
|
static char buffer[8 * 1024];
|
|
struct sockaddr_in saddr;
|
|
|
|
if(!len || !message || ((message[0] != QR_MAGIC_1) && (message[1] != QR_MAGIC_2) && (message[0] != '\\')))
|
|
return GT2False;
|
|
|
|
// we want to make sure it is NUL-terminated
|
|
len = min(len, (sizeof(buffer) - 1));
|
|
memcpy(buffer, message, len);
|
|
buffer[len] = '\0';
|
|
|
|
memset(&saddr, 0, sizeof(saddr));
|
|
saddr.sin_family = AF_INET;
|
|
saddr.sin_addr.s_addr = ip;
|
|
saddr.sin_port = htons(port);
|
|
//qr_parse_query(NULL, buffer, len, (struct sockaddr *)&saddr);
|
|
qr2_parse_query(NULL, buffer, len, (struct sockaddr *)&saddr);
|
|
return GT2True;
|
|
|
|
GSI_UNUSED(socket);
|
|
}
|
|
|
|
void ConnectAttemptCallback
|
|
(
|
|
GT2Socket socket,
|
|
GT2Connection connection,
|
|
unsigned int ip,
|
|
unsigned short port,
|
|
int latency,
|
|
GT2Byte * message,
|
|
int len
|
|
)
|
|
{
|
|
printf("Connection attempt from %s (%d ping)\n", gt2AddressToString(ip, port, NULL), latency);
|
|
|
|
gt2Reject(connection, NULL, 0);
|
|
|
|
GSI_UNUSED(len);
|
|
GSI_UNUSED(message);
|
|
GSI_UNUSED(socket);
|
|
}
|
|
|
|
/*******************
|
|
main
|
|
Simulates a main program loop
|
|
First, initializes the Q&R items, then enters a main loop
|
|
*****************/
|
|
#if defined(_PS2)
|
|
int test_main(int argc, char **argp)
|
|
#else
|
|
int main(int argc, char **argp)
|
|
#endif
|
|
{
|
|
char secret_key[9];
|
|
GT2Socket socket;
|
|
GT2Result result;
|
|
int natNegotiate = 1;
|
|
result = gt2CreateSocket(&socket, gt2AddressToString(0, QR2_BASE_PORT, NULL), 0, 0, NULL);
|
|
if(result != GT2Success)
|
|
return -1;
|
|
|
|
gt2Listen(socket, ConnectAttemptCallback);
|
|
|
|
//set the secret key, in a semi-obfuscated manner
|
|
secret_key[0] = 'H';
|
|
secret_key[1] = 'A';
|
|
secret_key[2] = '6';
|
|
secret_key[3] = 'z';
|
|
secret_key[4] = 'k';
|
|
secret_key[5] = 'S';
|
|
secret_key[6] = '\0';
|
|
|
|
qr2_register_key(QR2_RANKINGSON_KEY, _T("rankingson"));
|
|
/*
|
|
//call qr_init_socket with the socket and gamename
|
|
if (qr_init_socket(NULL,gt2GetSocketSOCKET(socket), QR2_GAME_NAME, secret_key, basic_callback,
|
|
info_callback, rules_callback, players_callback, NULL) != 0)
|
|
{
|
|
printf("Error starting Q&R SDK\n");
|
|
return -1;
|
|
}
|
|
*/
|
|
|
|
// call the qr2_init_socket with the socket and gamename
|
|
if (qr2_init_socket(NULL, gt2GetSocketSOCKET(socket), QR2_BASE_PORT, QR2_GAME_NAME, secret_key, 1, natNegotiate,
|
|
serverkey_callback, playerkey_callback, teamkey_callback, keylist_callback, count_callback,
|
|
adderror_callback, NULL) != e_qrnoerror)
|
|
|
|
{
|
|
printf("Error starting QR2 SDK\n");
|
|
return -1;
|
|
}
|
|
// set the unrecognized message callback
|
|
gt2SetUnrecognizedMessageCallback(socket, UnrecognizedMessageCallback);
|
|
|
|
init_game();
|
|
|
|
printf("Press any key to quit\n");
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
while (!_kbhit())
|
|
#else
|
|
while (1)
|
|
#endif
|
|
{
|
|
DoGameStuff();
|
|
//process our game networking
|
|
gt2Think(socket);
|
|
//check for / process incoming queries
|
|
//qr_process_queries(NULL);
|
|
qr2_think(NULL);
|
|
}
|
|
//let gamemaster know we are shutting down
|
|
strcpy(gamedata.gamemode,"exiting");
|
|
//qr_send_exiting(NULL);
|
|
//qr_shutdown(NULL);
|
|
qr2_shutdown(NULL);
|
|
gt2CloseSocket(socket);
|
|
return 0;
|
|
|
|
GSI_UNUSED(argp);
|
|
GSI_UNUSED(argc);
|
|
}
|