Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
465 lines
12 KiB
C++
465 lines
12 KiB
C++
#include "AdeptHeaders.hpp"
|
|
#include "GameSpy.h"
|
|
#include <gameOS/GUNGameList.h>
|
|
#include "buildnum/buildnum.h"
|
|
#pragma comment(lib, "wsock32")
|
|
|
|
#ifndef NEW_GAMESPY
|
|
|
|
/******
|
|
goasample.c
|
|
GameSpy Developer SDK Sample App
|
|
|
|
Copyright 1999 GameSpy Industries, Inc
|
|
|
|
Suite E-204
|
|
2900 Bristol Street
|
|
Costa Mesa, CA 92626
|
|
(714)549-7689
|
|
Fax(714)549-0757
|
|
|
|
******
|
|
|
|
This source file includes a "sample" game shell which demonstrates
|
|
how to use the GameSpy Developer SDK (goautil.h)
|
|
|
|
Please see the GameSpy Developer SDK documentation for more
|
|
information
|
|
|
|
******/
|
|
|
|
#define FixSZString(s) ((s)[sizeof(s)-1]) = 0
|
|
|
|
namespace GameSpyOld
|
|
{
|
|
bool bGameSpy;
|
|
};
|
|
|
|
/********
|
|
INCLUDES
|
|
********/
|
|
#include "nonport.h"
|
|
#include "goautil.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <conio.h>
|
|
|
|
/********
|
|
DEFINES
|
|
********/
|
|
#define GAME_VERSION CURRENT_BUILD_FULL_STRING
|
|
#define GAME_NAME GAMESPY_MASTER_ENGINENAME
|
|
#define MAX_PLAYERS 32
|
|
|
|
#ifdef _WIN32_WCE
|
|
void RetailOutputA(CHAR *tszErr, ...);
|
|
#define printf RetailOutputA
|
|
#endif
|
|
|
|
|
|
/********
|
|
TYPDEFS
|
|
********/
|
|
//representative of a game player structure
|
|
typedef struct
|
|
{
|
|
char pname[80];
|
|
char pteam[80];
|
|
int id;
|
|
} player_t;
|
|
|
|
//representative of a game data structure
|
|
typedef struct
|
|
{
|
|
player_t players[MAX_PLAYERS];
|
|
char gamename[50];
|
|
char mapname[20];
|
|
char hostname[120];
|
|
char gamemode[200];
|
|
char gametype[30];
|
|
GUID guid;
|
|
int locationid;
|
|
int numplayers;
|
|
int maxplayers;
|
|
int fraglimit;
|
|
int timelimit;
|
|
int teamplay;
|
|
int rankingson;
|
|
int hostport;
|
|
int flags;
|
|
} gamedata_t;
|
|
|
|
/********
|
|
GLOBAL VARS
|
|
********/
|
|
|
|
//just to give us bogus data
|
|
char *constnames[MAX_PLAYERS]={"Joe Player","L33t 0n3","Raptor","Gr81","Flubber","Sarge","Void","runaway","Ph3ar","wh00t","gr1nder","Mace","stacy","lamby","Thrush"};
|
|
gamedata_t gamedata;
|
|
|
|
|
|
/*************
|
|
basic_callback
|
|
sends a (sample) response to the basic query
|
|
includes the following keys:
|
|
\gamename\
|
|
\gamever\
|
|
\location\
|
|
*************/
|
|
static void basic_callback(char *outbuf, int maxlen, void *userdata)
|
|
{
|
|
sprintf(outbuf, "\\%s\\%s\\%s\\%s\\%s\\%d",
|
|
GAMESPY_KEY_GAME_NAME, gamedata.gamename,
|
|
GAMESPY_KEY_PRODUCT_VERSION, GAME_VERSION,
|
|
GAMESPY_KEY_LOCATION, gamedata.locationid);
|
|
|
|
// printf("Basic callback, sent: %s\n",outbuf);
|
|
}
|
|
|
|
/************
|
|
info_callback
|
|
Sends a (sample) response to the info query
|
|
including the following keys:
|
|
\hostname\
|
|
\hostport\
|
|
\mapname\
|
|
\gametype\
|
|
\numplayers\
|
|
\maxplayers\
|
|
\gamemode\
|
|
************/
|
|
static void info_callback(char *outbuf, int maxlen, void *userdata)
|
|
{
|
|
char keyvalue[200];
|
|
|
|
sprintf(keyvalue,"\\%s\\%s", GAMESPY_KEY_HOSTNAME, gamedata.hostname);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_HOSTPORT, gamedata.hostport);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\%s", GAMESPY_KEY_MAP_TYPE, gamedata.mapname);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\%s", GAMESPY_KEY_GAME_TYPE, gamedata.gametype);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_NUM_PLAYERS, gamedata.numplayers);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_MAX_PLAYERS, gamedata.maxplayers);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\%s", GAMESPY_KEY_GAMEMODE, gamedata.gamemode);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_FLAGS, gamedata.flags);strcat(outbuf, keyvalue);
|
|
sprintf(keyvalue,"\\%s\\{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", GAMESPY_KEY_INSTANCE,
|
|
gamedata.guid.Data1,
|
|
gamedata.guid.Data2,
|
|
gamedata.guid.Data3,
|
|
gamedata.guid.Data4[0],
|
|
gamedata.guid.Data4[1],
|
|
gamedata.guid.Data4[2],
|
|
gamedata.guid.Data4[3],
|
|
gamedata.guid.Data4[4],
|
|
gamedata.guid.Data4[5],
|
|
gamedata.guid.Data4[6],
|
|
gamedata.guid.Data4[7]);strcat(outbuf, keyvalue);
|
|
|
|
// printf("Info callback, sent: %s\n",outbuf);
|
|
|
|
}
|
|
|
|
/***************
|
|
rules_callback
|
|
Sends a response to the rules query. You may
|
|
need to add custom fields for your game in here. Some are provided
|
|
as an example
|
|
The following rules are included:
|
|
\timelimit\
|
|
\fraglimit\
|
|
\teamplay\
|
|
\rankedserver\
|
|
****************/
|
|
static void rules_callback(char *outbuf, int maxlen, void *userdata)
|
|
{
|
|
// char keyvalue[80];
|
|
|
|
// sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_TIMELIMIT, gamedata.timelimit);strcat(outbuf, keyvalue);
|
|
// sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_FRAGLIMIT, gamedata.fraglimit);strcat(outbuf, keyvalue);
|
|
// sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_TEAMPLAY, gamedata.teamplay);strcat(outbuf, keyvalue);
|
|
|
|
// //sample custom key/value
|
|
// sprintf(keyvalue,"\\%s\\%d", GAMESPY_KEY_RANKEDSERVER, gamedata.rankingson);strcat(outbuf, keyvalue);
|
|
// printf("Rules callback, sent: %s\n",outbuf);
|
|
|
|
}
|
|
|
|
/***************
|
|
players_callback
|
|
sends the players and their information.
|
|
Note that \ characters are not stripped out of player names. If
|
|
your game allows players or team names with the \ character, you will need
|
|
to strip or change it here.
|
|
The following keys are included for each player:
|
|
\player_N\
|
|
\frags_N\
|
|
\deaths_N\
|
|
\skill_N\
|
|
\ping_N\
|
|
\team_N\
|
|
***************/
|
|
static void players_callback(char *outbuf, int maxlen, void *userdata)
|
|
{
|
|
char keyvalue[160];
|
|
int i;
|
|
|
|
for (i = 0; i < gamedata.numplayers ; i++)
|
|
{
|
|
sprintf(keyvalue,
|
|
"\\player_%d\\%s\\team_%d\\%s",
|
|
i, gamedata.players[i].pname,
|
|
i, gamedata.players[i].pteam);
|
|
|
|
strcat(outbuf, keyvalue);
|
|
}
|
|
//printf("Players callback, sent: %s\n",outbuf);
|
|
|
|
}
|
|
|
|
|
|
/////***********
|
|
////init_game
|
|
////Initialize the sample data structures with bogus data
|
|
////************/
|
|
////static void init_game(void)
|
|
////{
|
|
//// int i;
|
|
//// int team;
|
|
////
|
|
//// srand( current_time() );
|
|
//// gamedata.numplayers = rand() % 15;
|
|
//// gamedata.maxplayers = 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);
|
|
}
|
|
|
|
/////*******************
|
|
//// main
|
|
////Simulates a main program loop
|
|
////First, initializes the GOA items, then enters a main loop
|
|
////*****************/
|
|
////int main_1(int argc, char* argv[])
|
|
////{
|
|
//// //set the callback functions
|
|
//// goa_basic_callback = basic_callback;
|
|
//// goa_info_callback = info_callback;
|
|
//// goa_rules_callback = rules_callback;
|
|
//// goa_players_callback = players_callback;
|
|
//// //set the secret key, in a semi-obfuscated manner
|
|
////
|
|
////#if 0
|
|
//// goa_secret_key[0] = 'H';
|
|
//// goa_secret_key[1] = 'A';
|
|
//// goa_secret_key[2] = '6';
|
|
//// goa_secret_key[3] = 'z';
|
|
//// goa_secret_key[4] = 'k';
|
|
//// goa_secret_key[5] = 'S';
|
|
//// goa_secret_key[6] = '\0';
|
|
////#endif
|
|
//// init_game();
|
|
////
|
|
//// //call goa_init with the query port number and gamename, default IP address, and no user data
|
|
//// if (goa_init(27950,GAME_NAME, "localhost", NULL) != 0)
|
|
//// {
|
|
//// fprintf(stderr,"Error starting query sockets\n");
|
|
//// return -1;
|
|
//// }
|
|
////
|
|
//// while (kbhit())
|
|
//// _getch();
|
|
////
|
|
//// printf("Press any key to quit\n");
|
|
//// while (!kbhit())
|
|
//// {
|
|
//// DoGameStuff();
|
|
//// //check for / process incoming queries
|
|
//// goa_process_queries();
|
|
////
|
|
//// }
|
|
//// _getch();
|
|
////
|
|
//// //let gamemaster know we are shutting down
|
|
//// strcpy(gamedata.gamemode,"exiting");
|
|
//// goa_send_statechanged();
|
|
//// goa_shutdown();
|
|
////
|
|
//// return 0;
|
|
////
|
|
////}
|
|
|
|
//========================================================================
|
|
//========================================================================
|
|
bool GameSpyOld::BeginAdvertisingOnGameSpy(const char * GameName, const char *PlayerName, int MaxPlayers, const char *Password, const GUID &guidInstance, bool Secure, DWORD dwFlags)
|
|
{
|
|
EndAdvertisingOnGameSpy();
|
|
gosASSERT(GameName != NULL);
|
|
#ifdef _DEBUG
|
|
if (!GameName)
|
|
GameName = "testgame";
|
|
#endif
|
|
|
|
strcpy(goa_secret_key, GetKeyName());
|
|
|
|
//set the callback functions
|
|
goa_basic_callback = basic_callback;
|
|
goa_info_callback = info_callback;
|
|
goa_rules_callback = rules_callback;
|
|
goa_players_callback = players_callback;
|
|
|
|
//init_game();
|
|
|
|
strncpy(gamedata.players[0].pname, PlayerName, sizeof(gamedata.players[0].pname));
|
|
strncpy(gamedata.gamename, GameName, sizeof(gamedata.gamename));
|
|
//strncpy(gamedata.gametype, Environment.applicationName, sizeof(gamedata.gametype));
|
|
|
|
FixSZString(gamedata.players[0].pname);
|
|
FixSZString(gamedata.gamename);
|
|
//FixSZString(gamedata.gametype);
|
|
|
|
//strncpy(gamedata.mapname, "map", sizeof(gamedata.mapname));
|
|
//strncpy(gamedata.hostname, GameName, sizeof(gamedata.hostname));
|
|
|
|
gamedata.numplayers = 1;
|
|
gamedata.maxplayers = MaxPlayers;
|
|
gamedata.guid = guidInstance;
|
|
gamedata.flags = dwFlags;
|
|
|
|
//call goa_init with the query port number and gamename, default IP address, and no user data
|
|
if (goa_init(GetQueryPort(), GAMESPY_MASTER_ENGINENAME, "localhost", NULL) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bGameSpy = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
//========================================================================
|
|
//========================================================================
|
|
void GameSpyOld::SetKey(const char *szKey, const char *szValue)
|
|
{
|
|
if (!strcmp(szKey, GAMELIST_KEY_MAP_TYPE))
|
|
{
|
|
strcpy(gamedata.mapname, szValue);
|
|
}
|
|
if (!strcmp(szKey, GAMELIST_KEY_GAME_TYPE))
|
|
{
|
|
strcpy(gamedata.gametype, szValue);
|
|
}
|
|
goa_send_statechanged();
|
|
}
|
|
|
|
//========================================================================
|
|
//========================================================================
|
|
void GameSpyOld::EndAdvertisingOnGameSpy(void)
|
|
{
|
|
if (bGameSpy)
|
|
{
|
|
goa_send_statechanged();
|
|
goa_shutdown();
|
|
bGameSpy = false;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//========================================================================
|
|
//========================================================================
|
|
bool GameSpyOld::AddPlayer(int id, const char *szName, const char *szTeam, int reserved)
|
|
{
|
|
if (gamedata.numplayers == MAX_PLAYERS)
|
|
return false;
|
|
|
|
if (szName)
|
|
{
|
|
strncpy(gamedata.players[gamedata.numplayers].pname, szName, sizeof(gamedata.players[gamedata.numplayers].pname));
|
|
gamedata.players[gamedata.numplayers].pname[sizeof(gamedata.players[gamedata.numplayers].pname)-1]=0;
|
|
}
|
|
else
|
|
gamedata.players[gamedata.numplayers].pname[0]=0;
|
|
|
|
if (szTeam)
|
|
{
|
|
strncpy(gamedata.players[gamedata.numplayers].pteam, szTeam, sizeof(gamedata.players[gamedata.numplayers].pteam));
|
|
gamedata.players[gamedata.numplayers].pteam[sizeof(gamedata.players[gamedata.numplayers].pteam)-1]=0;
|
|
}
|
|
else
|
|
gamedata.players[gamedata.numplayers].pteam[0]=0;
|
|
|
|
gamedata.players[gamedata.numplayers].id = id;
|
|
gamedata.numplayers++;
|
|
goa_send_statechanged();
|
|
|
|
return true;
|
|
}
|
|
|
|
//========================================================================
|
|
//========================================================================
|
|
bool GameSpyOld::RemovePlayer(int id, const char *szName, const char *szTeam, int reserved)
|
|
{
|
|
int i;
|
|
for (i=0 ; i<gamedata.numplayers ; i++)
|
|
{
|
|
if (gamedata.players[gamedata.numplayers].id == id)
|
|
break;
|
|
}
|
|
|
|
if (i==gamedata.numplayers)
|
|
return false;
|
|
|
|
strcpy(gamedata.players[i].pname, gamedata.players[gamedata.numplayers].pname);
|
|
strcpy(gamedata.players[i].pteam, gamedata.players[gamedata.numplayers].pteam);
|
|
gamedata.players[i].id = gamedata.players[gamedata.numplayers].id;
|
|
gamedata.numplayers--;
|
|
|
|
goa_send_statechanged();
|
|
|
|
return true;
|
|
}
|
|
|
|
//========================================================================
|
|
//========================================================================
|
|
extern bool UpdateGameSpyGameList(void);
|
|
bool GameSpyOld::ProcessGameSpy(void)
|
|
{
|
|
if (bGameSpy)
|
|
{
|
|
goa_process_queries();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif |