Add proper/clean method for a2s_info and a2s_player
This commit is contained in:
+2
-1
@@ -480,7 +480,8 @@ class ExtensionConfig(object):
|
||||
['public', 'mathlib'],
|
||||
['public', 'vstdlib'],
|
||||
['public', 'tier0'],
|
||||
['public', 'tier1']
|
||||
['public', 'tier1'],
|
||||
['public', 'appframework']
|
||||
]
|
||||
if sdk.name == 'episode1' or sdk.name == 'darkm':
|
||||
paths.append(['public', 'dlls'])
|
||||
|
||||
+253
-136
@@ -34,6 +34,11 @@
|
||||
#include "CDetour/detours.h"
|
||||
#include "steam/steam_gameserver.h"
|
||||
#include "sm_namehashset.h"
|
||||
#include "proto_oob.h"
|
||||
#include "protocol.h"
|
||||
#include "inetworksystem.h"
|
||||
#include <strtools.h>
|
||||
#include <utlbuffer.h>
|
||||
#include <sourcehook.h>
|
||||
#include <bitbuf.h>
|
||||
#include <netadr.h>
|
||||
@@ -88,8 +93,12 @@ ConVar *g_SvGameDesc = CreateConVar("sv_gamedesc_override", "default", FCVAR_NOT
|
||||
ConVar *g_SvMapName = CreateConVar("sv_mapname_override", "default", FCVAR_NOTIFY, "Overwrite the map name. Set to 'default' to keep default name.");
|
||||
ConVar *g_SvCountBotsInfo = CreateConVar("sv_count_bots_info", "1", FCVAR_NOTIFY, "Display bots as players in the a2s_info server query. Enable = '1', Disable = '0'");
|
||||
ConVar *g_SvCountBotsPlayer = CreateConVar("sv_count_bots_player", "0", FCVAR_NOTIFY, "Display bots as players in the a2s_player server query. Enable = '1', Disable = '0'");
|
||||
ConVar *g_pSvVisibleMaxPlayers;
|
||||
ConVar *g_pSvTags;
|
||||
#if SOURCE_ENGINE < SE_CSGO
|
||||
ConVar *g_SvHostNameStore = CreateConVar("host_name_store", "1", FCVAR_NOTIFY, "Whether hostname is recorded in game events and GOTV.");
|
||||
#endif
|
||||
ConVar *g_pSvVisibleMaxPlayers = NULL;
|
||||
ConVar *g_pSvTags = NULL;
|
||||
ConVar *g_pSvEnableOldQueries = NULL;
|
||||
|
||||
IGameConfig *g_pGameConf = NULL;
|
||||
IGameEventManager2 *g_pGameEvents = NULL;
|
||||
@@ -156,53 +165,48 @@ struct CQueryCache
|
||||
{
|
||||
struct CPlayer
|
||||
{
|
||||
bool active;
|
||||
bool fake;
|
||||
int userid;
|
||||
IClient *pClient;
|
||||
char name[MAX_PLAYER_NAME_LENGTH];
|
||||
unsigned nameLen;
|
||||
int32_t score;
|
||||
double time;
|
||||
bool active = false;
|
||||
bool fake = false;
|
||||
int userid = 0;
|
||||
IClient *pClient = NULL;
|
||||
char name[MAX_PLAYER_NAME_LENGTH] = "\0";
|
||||
unsigned nameLen = 0;
|
||||
int32_t score = 0;
|
||||
double time = 0.0;
|
||||
} players[SM_MAXPLAYERS + 1];
|
||||
|
||||
struct CInfo
|
||||
{
|
||||
uint8_t nProtocol = 17; // Protocol | byte | Protocol version used by the server.
|
||||
char aHostName[255]; // Name | string | Name of the server.
|
||||
uint8_t aHostNameLen;
|
||||
char aHostName[255] = "\0"; // Name | string | Name of the server.
|
||||
uint8_t aHostNameLen = 0;
|
||||
char aMapName[255]; // Map | string | Map the server has currently loaded.
|
||||
uint8_t aMapNameLen;
|
||||
uint8_t aMapNameLen = 0;
|
||||
char aGameDir[255]; // Folder | string | Name of the folder containing the game files.
|
||||
uint8_t aGameDirLen;
|
||||
char aGameDescription[255]; // Game | string | Full name of the game.
|
||||
uint8_t aGameDescriptionLen;
|
||||
uint16_t iSteamAppID; // ID | short | Steam Application ID of game.
|
||||
uint8_t aGameDirLen = 0;
|
||||
char aGameDescription[255] = "\0"; // Game | string | Full name of the game.
|
||||
uint8_t aGameDescriptionLen = 0;
|
||||
uint16_t iSteamAppID = 0; // ID | short | Steam Application ID of game.
|
||||
uint8_t nNumClients = 0; // Players | byte | Number of players on the server.
|
||||
uint8_t nMaxClients; // Max. Players | byte | Maximum number of players the server reports it can hold.
|
||||
uint8_t nMaxClients = 0; // Max. Players | byte | Maximum number of players the server reports it can hold.
|
||||
uint8_t nFakeClients = 0; // Bots | byte | Number of bots on the server.
|
||||
uint8_t nServerType = 'd'; // Server type | byte | Indicates the type of server: 'd' for a dedicated server, 'l' for a non-dedicated server, 'p' for a SourceTV relay (proxy)
|
||||
uint8_t nEnvironment = 'l'; // Environment | byte | Indicates the operating system of the server: 'l' for Linux, 'w' for Windows, 'm' or 'o' for Mac (the code changed after L4D1)
|
||||
uint8_t nPassword; // Visibility | byte | Indicates whether the server requires a password: 0 for public, 1 for private
|
||||
uint8_t bIsSecure; // VAC | byte | Specifies whether the server uses VAC: 0 for unsecured, 1 for secured
|
||||
char aVersion[40]; // Version | string | Version of the game installed on the server.
|
||||
uint8_t aVersionLen;
|
||||
uint8_t nPassword = 0; // Visibility | byte | Indicates whether the server requires a password: 0 for public, 1 for private
|
||||
uint8_t bIsSecure = 0; // VAC | byte | Specifies whether the server uses VAC: 0 for unsecured, 1 for secured
|
||||
char aVersion[40] = "\0"; // Version | string | Version of the game installed on the server.
|
||||
uint8_t aVersionLen = 0;
|
||||
uint8_t nNewFlags = 0; // Extra Data Flag (EDF) | byte | If present, this specifies which additional data fields will be included.
|
||||
uint16_t iUDPPort; // EDF & 0x80 -> Port | short | The server's game port number.
|
||||
uint64_t iSteamID; // EDF & 0x10 -> SteamID | long long | Server's SteamID.
|
||||
uint16_t iHLTVUDPPort; // EDF & 0x40 -> Port | short | Spectator port number for SourceTV.
|
||||
char aHLTVName[255]; // EDF & 0x40 -> Name | string | Name of the spectator server for SourceTV.
|
||||
uint8_t aHLTVNameLen;
|
||||
char aKeywords[255]; // EDF & 0x20 -> Keywords | string | Tags that describe the game according to the server (for future use.) (sv_tags)
|
||||
uint8_t aKeywordsLen;
|
||||
uint64_t iGameID; // EDF & 0x01 -> GameID | long long | The server's 64-bit GameID. If this is present, a more accurate AppID is present in the low 24 bits. The earlier AppID could have been truncated as it was forced into 16-bit storage.
|
||||
uint16_t iUDPPort = 0; // EDF & S2A_EXTRA_DATA_HAS_GAME_PORT -> Port | short | The server's game port number.
|
||||
uint64_t iSteamID = 0; // EDF & S2A_EXTRA_DATA_HAS_STEAMID -> SteamID | long long | Server's SteamID.
|
||||
uint16_t iHLTVUDPPort = 0; // EDF & S2A_EXTRA_DATA_HAS_SPECTATOR_DATA -> Port | short | Spectator port number for SourceTV.
|
||||
char aHLTVName[255] = "\0"; // EDF & S2A_EXTRA_DATA_HAS_SPECTATOR_DATA -> Name | string | Name of the spectator server for SourceTV.
|
||||
uint8_t aHLTVNameLen = 0;
|
||||
char aKeywords[255] = "\0"; // EDF & S2A_EXTRA_DATA_HAS_GAMETAG_DATA -> Keywords | string | Tags that describe the game according to the server (for future use.) (sv_tags)
|
||||
uint8_t aKeywordsLen = 0;
|
||||
uint64_t iGameID = 0; // EDF & S2A_EXTRA_DATA_GAMEID -> GameID | long long | The server's 64-bit GameID. If this is present, a more accurate AppID is present in the low 24 bits. The earlier AppID could have been truncated as it was forced into 16-bit storage.
|
||||
} info;
|
||||
|
||||
uint8_t info_cache[sizeof(CInfo)] = {0xFF, 0xFF, 0xFF, 0xFF, 'I'};
|
||||
uint16_t info_cache_len;
|
||||
|
||||
uint8_t players_cache[4+1+1+SM_MAXPLAYERS*(1+MAX_PLAYER_NAME_LENGTH+4+4)] = {0xFF, 0xFF, 0xFF, 0xFF, 'D', 0};
|
||||
uint16_t players_cache_len;
|
||||
} g_QueryCache;
|
||||
|
||||
class CBaseClient;
|
||||
@@ -213,7 +217,8 @@ void UpdateQueryCache()
|
||||
{
|
||||
// A2S_INFO
|
||||
CQueryCache::CInfo &info = g_QueryCache.info;
|
||||
info.aHostNameLen = strlcpy(info.aHostName, iserver->GetName(), sizeof(info.aHostName));
|
||||
|
||||
info.aHostNameLen = strlcpy(info.aHostName, g_SvHostNameStore->GetBool() ? iserver->GetName() : gamedll->GetGameDescription(), sizeof(info.aHostName));
|
||||
|
||||
if(strcmp(g_SvMapName->GetString(), "default") == 0)
|
||||
info.aMapNameLen = strlcpy(info.aMapName, iserver->GetMapName(), sizeof(info.aMapName));
|
||||
@@ -229,16 +234,32 @@ void UpdateQueryCache()
|
||||
info.nMaxClients = g_pSvVisibleMaxPlayers->GetInt();
|
||||
else
|
||||
info.nMaxClients = iserver->GetMaxClients();
|
||||
|
||||
// NOTE: This key's meaning is changed in the new version. Since we send gameport and specport,
|
||||
// it knows whether we're running SourceTV or not. Then it only needs to know if we're a dedicated or listen server.
|
||||
if ( iserver->IsDedicated() )
|
||||
info.nServerType = 'd'; // d = dedicated server
|
||||
else
|
||||
info.nServerType = 'l'; // l = listen server
|
||||
|
||||
#if defined(_WIN32)
|
||||
info.nEnvironment = 'w';
|
||||
#elif defined(OSX)
|
||||
info.nEnvironment = 'm';
|
||||
#else // LINUX?
|
||||
info.nEnvironment = 'l';
|
||||
#endif
|
||||
|
||||
info.nPassword = iserver->GetPassword() ? 1 : 0;
|
||||
info.bIsSecure = true;
|
||||
|
||||
if(!(info.nNewFlags & 0x10) && engine->GetGameServerSteamID())
|
||||
if(!(info.nNewFlags & S2A_EXTRA_DATA_HAS_STEAMID) && engine->GetGameServerSteamID())
|
||||
{
|
||||
info.iSteamID = engine->GetGameServerSteamID()->ConvertToUint64();
|
||||
info.nNewFlags |= 0x10;
|
||||
info.nNewFlags |= S2A_EXTRA_DATA_HAS_STEAMID;
|
||||
}
|
||||
|
||||
if(!(info.nNewFlags & 0x40) && hltvdirector->IsActive()) // tv_name can't change anymore
|
||||
if(!(info.nNewFlags & S2A_EXTRA_DATA_HAS_SPECTATOR_DATA) && hltvdirector->IsActive()) // tv_name can't change anymore
|
||||
{
|
||||
#if SOURCE_ENGINE >= SE_CSGO
|
||||
hltv = hltvdirector->GetHLTVServer(0);
|
||||
@@ -252,144 +273,235 @@ void UpdateQueryCache()
|
||||
{
|
||||
info.iHLTVUDPPort = ihltvserver->GetUDPPort();
|
||||
info.aHLTVNameLen = strlcpy(info.aHLTVName, ihltvserver->GetName(), sizeof(info.aHLTVName));
|
||||
info.nNewFlags |= 0x40;
|
||||
info.nNewFlags |= S2A_EXTRA_DATA_HAS_SPECTATOR_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info.aKeywordsLen = strlcpy(info.aKeywords, g_pSvTags->GetString(), sizeof(info.aKeywords));
|
||||
if(info.aKeywordsLen)
|
||||
info.nNewFlags |= 0x20;
|
||||
info.nNewFlags |= S2A_EXTRA_DATA_HAS_GAMETAG_DATA;
|
||||
else
|
||||
info.nNewFlags &= ~0x20;
|
||||
|
||||
|
||||
uint8_t *info_cache = g_QueryCache.info_cache;
|
||||
uint16_t pos = 5; // header: FF FF FF FF I
|
||||
|
||||
info_cache[pos++] = info.nProtocol;
|
||||
|
||||
memcpy(&info_cache[pos], info.aHostName, info.aHostNameLen + 1);
|
||||
pos += info.aHostNameLen + 1;
|
||||
|
||||
memcpy(&info_cache[pos], info.aMapName, info.aMapNameLen + 1);
|
||||
pos += info.aMapNameLen + 1;
|
||||
|
||||
memcpy(&info_cache[pos], info.aGameDir, info.aGameDirLen + 1);
|
||||
pos += info.aGameDirLen + 1;
|
||||
|
||||
memcpy(&info_cache[pos], info.aGameDescription, info.aGameDescriptionLen + 1);
|
||||
pos += info.aGameDescriptionLen + 1;
|
||||
|
||||
*(uint16_t *)&info_cache[pos] = info.iSteamAppID;
|
||||
pos += 2;
|
||||
|
||||
info_cache[pos++] = info.nNumClients;
|
||||
|
||||
info_cache[pos++] = info.nMaxClients;
|
||||
|
||||
if (g_SvCountBotsInfo->GetInt())
|
||||
info_cache[pos++] = 0;
|
||||
else
|
||||
info_cache[pos++] = info.nFakeClients;
|
||||
|
||||
info_cache[pos++] = info.nServerType;
|
||||
|
||||
info_cache[pos++] = info.nEnvironment;
|
||||
|
||||
info_cache[pos++] = info.nPassword;
|
||||
|
||||
info_cache[pos++] = info.bIsSecure;
|
||||
|
||||
memcpy(&info_cache[pos], info.aVersion, info.aVersionLen + 1);
|
||||
pos += info.aVersionLen + 1;
|
||||
|
||||
info_cache[pos++] = info.nNewFlags;
|
||||
|
||||
if(info.nNewFlags & 0x80) {
|
||||
*(uint16_t *)&info_cache[pos] = info.iUDPPort;
|
||||
pos += 2;
|
||||
info.nNewFlags &= ~S2A_EXTRA_DATA_HAS_GAMETAG_DATA;
|
||||
}
|
||||
|
||||
if(info.nNewFlags & 0x10) {
|
||||
*(uint64_t *)&info_cache[pos] = info.iSteamID;
|
||||
pos += 8;
|
||||
bool RequireValidChallenge( const netadr_t &adr )
|
||||
{
|
||||
if ( g_pSvEnableOldQueries->GetBool() == true )
|
||||
{
|
||||
return false; // don't enforce challenge numbers
|
||||
}
|
||||
|
||||
if(info.nNewFlags & 0x40) {
|
||||
*(uint16_t *)&info_cache[pos] = info.iHLTVUDPPort;
|
||||
pos += 2;
|
||||
|
||||
memcpy(&info_cache[pos], info.aHLTVName, info.aHLTVNameLen + 1);
|
||||
pos += info.aHLTVNameLen + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(info.nNewFlags & 0x20) {
|
||||
memcpy(&info_cache[pos], info.aKeywords, info.aKeywordsLen + 1);
|
||||
pos += info.aKeywordsLen + 1;
|
||||
bool ValidInfoChallenge( const netadr_t & adr, const char *nugget )
|
||||
{
|
||||
if ( !iserver->IsActive() ) // Must be running a server.
|
||||
return false ;
|
||||
|
||||
if ( !iserver->IsMultiplayer() ) // ignore in single player
|
||||
return false ;
|
||||
|
||||
if ( RequireValidChallenge( adr ) )
|
||||
{
|
||||
if ( Q_stricmp( nugget, A2S_KEY_STRING ) ) // if the string isn't equal then fail out
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(info.nNewFlags & 0x01) {
|
||||
*(uint64_t *)&info_cache[pos] = info.iGameID;
|
||||
pos += 8;
|
||||
return true;
|
||||
}
|
||||
|
||||
g_QueryCache.info_cache_len = pos;
|
||||
void SendA2S_PlayerChallenge(netpacket_t * packet, int32_t realChallengeNr)
|
||||
{
|
||||
struct sockaddr addr;
|
||||
packet->from.ToSockadr ( &addr );
|
||||
|
||||
CUtlBuffer buf;
|
||||
buf.EnsureCapacity( MAX_ROUTABLE_PAYLOAD );
|
||||
|
||||
// A2S_PLAYER
|
||||
uint8_t *players_cache = g_QueryCache.players_cache;
|
||||
pos = 6; // header: FF FF FF FF D 0[numplayers]
|
||||
buf.PutUnsignedInt( LittleDWord( CONNECTIONLESS_HEADER ) );
|
||||
buf.PutUnsignedChar( S2C_CHALLENGE );
|
||||
buf.PutInt( realChallengeNr );
|
||||
|
||||
sendto(g_ServerUDPSocket, (const char*)buf.Base(), buf.TellPut(), 0, &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
void SendA2S_Player(netpacket_t * packet)
|
||||
{
|
||||
struct sockaddr addr;
|
||||
packet->from.ToSockadr ( &addr );
|
||||
|
||||
CUtlBuffer buf;
|
||||
buf.EnsureCapacity( MAX_ROUTABLE_PAYLOAD );
|
||||
|
||||
buf.PutUnsignedInt( LittleDWord( CONNECTIONLESS_HEADER ) );
|
||||
buf.PutUnsignedChar( S2A_PLAYER );
|
||||
|
||||
unsigned char nPlayerCount = 0;
|
||||
for(int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||
{
|
||||
const CQueryCache::CPlayer &player = g_QueryCache.players[i];
|
||||
if(!player.active || (player.fake && !g_SvCountBotsPlayer->GetInt()))
|
||||
continue;
|
||||
nPlayerCount++;
|
||||
}
|
||||
|
||||
// Number of players
|
||||
buf.PutUnsignedChar( nPlayerCount );
|
||||
|
||||
unsigned char nPlayerUserID = 0;
|
||||
for(int i = 1; i <= SM_MAXPLAYERS; i++)
|
||||
{
|
||||
const CQueryCache::CPlayer &player = g_QueryCache.players[i];
|
||||
if(!player.active || (player.fake && !g_SvCountBotsPlayer->GetInt()))
|
||||
continue;
|
||||
|
||||
players_cache[pos++] = players_cache[5]; // Index | byte | Index of player chunk starting from 0.
|
||||
players_cache[5]++; // Players | byte | Number of players whose information was gathered.
|
||||
memcpy(&players_cache[pos], player.name, player.nameLen + 1); // Name | string | Name of the player.
|
||||
pos += player.nameLen + 1;
|
||||
*(int32_t *)&players_cache[pos] = player.score; // Score | long | Player's score (usually "frags" or "kills".)
|
||||
pos += 4;
|
||||
*(float *)&players_cache[pos] = *net_time - player.time; // Duration | float | Time (in seconds) player has been connected to the server.
|
||||
pos += 4;
|
||||
// User ID
|
||||
buf.PutUnsignedChar( nPlayerUserID );
|
||||
// Player Name
|
||||
buf.PutString( player.name );
|
||||
// Player Score
|
||||
buf.PutInt( player.score );
|
||||
// Player Duration
|
||||
buf.PutFloat( *net_time - player.time );
|
||||
|
||||
nPlayerUserID++;
|
||||
}
|
||||
|
||||
g_QueryCache.players_cache_len = pos;
|
||||
sendto(g_ServerUDPSocket, (const char *)buf.Base(), buf.TellPut(), 0, &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
void SendA2S_Info(netpacket_t * packet)
|
||||
{
|
||||
struct sockaddr addr;
|
||||
packet->from.ToSockadr ( &addr );
|
||||
|
||||
CUtlBuffer buf;
|
||||
buf.EnsureCapacity( MAX_ROUTABLE_PAYLOAD );
|
||||
|
||||
buf.PutUnsignedInt( LittleDWord( CONNECTIONLESS_HEADER ) );
|
||||
buf.PutUnsignedChar( S2A_INFO_SRC );
|
||||
buf.PutUnsignedChar( 17 ); // Hardcoded protocol version number
|
||||
buf.PutString( g_SvHostNameStore->GetBool() ? iserver->GetName() : gamedll->GetGameDescription() );
|
||||
buf.PutString( strcmp(g_SvMapName->GetString(), "default") == 0 ? iserver->GetMapName() : g_SvMapName->GetString());
|
||||
buf.PutString( smutils->GetGameFolderName() );
|
||||
buf.PutString( strcmp(g_SvGameDesc->GetString(), "default") == 0 ? gamedll->GetGameDescription() : g_SvGameDesc->GetString() );
|
||||
|
||||
// The next field is a 16-bit version of the AppID. If our AppID < 65536,
|
||||
// then let's go ahead and put in in there, to maximize compatibility
|
||||
// with old clients who might be only using this field but not the new one.
|
||||
// However, if our AppID won't fit, there's no way we can be compatible,
|
||||
// anyway, so just put in a zero, which is better than a bogus AppID.
|
||||
buf.PutShort( LittleWord( g_QueryCache.info.iSteamAppID ) );
|
||||
|
||||
// player info
|
||||
buf.PutUnsignedChar( g_QueryCache.info.nNumClients );
|
||||
buf.PutUnsignedChar( g_pSvVisibleMaxPlayers->GetInt() >= 0 ? g_pSvVisibleMaxPlayers->GetInt() : iserver->GetMaxClients() );
|
||||
buf.PutUnsignedChar( g_SvCountBotsInfo->GetInt() ? 0 : g_QueryCache.info.nFakeClients );
|
||||
|
||||
// NOTE: This key's meaning is changed in the new version. Since we send gameport and specport,
|
||||
// it knows whether we're running SourceTV or not. Then it only needs to know if we're a dedicated or listen server.
|
||||
buf.PutUnsignedChar( g_QueryCache.info.nServerType );
|
||||
|
||||
buf.PutUnsignedChar( g_QueryCache.info.nEnvironment );
|
||||
|
||||
// Password?
|
||||
buf.PutUnsignedChar( iserver->GetPassword() ? 1 : 0 );
|
||||
|
||||
// buf.PutUnsignedChar( Steam3Server().BSecure() ? 1 : 0 );
|
||||
|
||||
// Secure?
|
||||
buf.PutUnsignedChar( 1 );
|
||||
|
||||
buf.PutString( g_QueryCache.info.aVersion );
|
||||
|
||||
//
|
||||
// NEW DATA.
|
||||
//
|
||||
|
||||
buf.PutUnsignedChar( g_QueryCache.info.nNewFlags );
|
||||
|
||||
// Write the rest of the data.
|
||||
if ( g_QueryCache.info.nNewFlags & S2A_EXTRA_DATA_HAS_GAME_PORT )
|
||||
{
|
||||
buf.PutShort( LittleWord( iserver->GetUDPPort() ) );
|
||||
}
|
||||
|
||||
if ( g_QueryCache.info.nNewFlags & S2A_EXTRA_DATA_HAS_STEAMID )
|
||||
{
|
||||
buf.PutShort( LittleWord( g_QueryCache.info.iSteamID ) );
|
||||
}
|
||||
|
||||
if ( g_QueryCache.info.nNewFlags & S2A_EXTRA_DATA_HAS_SPECTATOR_DATA )
|
||||
{
|
||||
buf.PutShort( LittleWord( g_QueryCache.info.iHLTVUDPPort ) );
|
||||
buf.PutString( g_SvHostNameStore->GetBool() ? iserver->GetName() : g_QueryCache.info.aHLTVName );
|
||||
}
|
||||
|
||||
if ( g_QueryCache.info.nNewFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA )
|
||||
{
|
||||
buf.PutString( g_QueryCache.info.aKeywords );
|
||||
}
|
||||
|
||||
if ( g_QueryCache.info.nNewFlags & S2A_EXTRA_DATA_GAMEID )
|
||||
{
|
||||
// !FIXME! Is there a reason we aren't using the other half
|
||||
// of this field? Shouldn't we put the game mod ID in there, too?
|
||||
// We have the game dir.
|
||||
// buf.PutInt64( LittleQWord( CGameID( appIdResponse ).ToUint64() ) );
|
||||
buf.PutInt64( LittleQWord( g_QueryCache.info.iGameID ) );
|
||||
}
|
||||
|
||||
sendto(g_ServerUDPSocket, (const char *)buf.Base(), buf.TellPut(), 0, &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
bool Hook_ProcessConnectionlessPacket(netpacket_t * packet)
|
||||
{
|
||||
if(packet->size >= 25 && packet->data[4] == 'T')
|
||||
bf_read msg = packet->message; // handy shortcut
|
||||
|
||||
char c = msg.ReadChar();
|
||||
|
||||
switch ( c )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if(!CIPRateLimit__CheckIP(s_queryRateChecker, packet->from))
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
}
|
||||
|
||||
sockaddr_in to;
|
||||
to.sin_family = AF_INET;
|
||||
to.sin_port = packet->from.port;
|
||||
to.sin_addr.s_addr = *(int32_t *)&packet->from.ip;
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
break;
|
||||
}
|
||||
case A2S_INFO:
|
||||
{
|
||||
if(!CIPRateLimit__CheckIP(s_queryRateChecker, packet->from))
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
}
|
||||
|
||||
sendto(g_ServerUDPSocket, g_QueryCache.info_cache, g_QueryCache.info_cache_len, 0, (sockaddr *)&to, sizeof(to));
|
||||
// Validate challenge
|
||||
char nugget[ 64 ];
|
||||
if ( !msg.ReadString( nugget, sizeof( nugget ) ) )
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, true);
|
||||
if ( !ValidInfoChallenge( packet->from, nugget ) )
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, true);
|
||||
|
||||
SendA2S_Info(packet);
|
||||
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if((packet->size == 5 || packet->size == 9) && packet->data[4] == 'U')
|
||||
case A2S_PLAYER:
|
||||
{
|
||||
if(!CIPRateLimit__CheckIP(s_queryRateChecker, packet->from))
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
}
|
||||
|
||||
sockaddr_in to;
|
||||
to.sin_family = AF_INET;
|
||||
to.sin_port = packet->from.port;
|
||||
to.sin_addr.s_addr = *(int32_t *)&packet->from.ip;
|
||||
|
||||
int32_t challengeNr = -1;
|
||||
if(packet->size == 9)
|
||||
challengeNr = *(int32_t *)&packet->data[5];
|
||||
@@ -404,15 +516,16 @@ bool Hook_ProcessConnectionlessPacket(netpacket_t * packet)
|
||||
int32_t realChallengeNr = *(int32_t *)&packet->from.ip ^ 0x55AADD88;
|
||||
if(challengeNr != realChallengeNr)
|
||||
{
|
||||
uint8_t response[9] = {0xFF, 0xFF, 0xFF, 0xFF, 'A'};
|
||||
*(int32_t *)&response[5] = realChallengeNr;
|
||||
sendto(g_ServerUDPSocket, response, sizeof(response), 0, (sockaddr *)&to, sizeof(to));
|
||||
SendA2S_PlayerChallenge(packet, realChallengeNr);
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, true);
|
||||
}
|
||||
|
||||
sendto(g_ServerUDPSocket, g_QueryCache.players_cache, g_QueryCache.players_cache_len, 0, (sockaddr *)&to, sizeof(to));
|
||||
SendA2S_Player(packet);
|
||||
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
@@ -515,6 +628,10 @@ bool A2SQCache::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, boo
|
||||
|
||||
g_pSvVisibleMaxPlayers = g_pCVar->FindVar("sv_visiblemaxplayers");
|
||||
g_pSvTags = g_pCVar->FindVar("sv_tags");
|
||||
g_pSvEnableOldQueries = g_pCVar->FindVar("sv_enableoldqueries");
|
||||
#if SOURCE_ENGINE >= SE_CSGO
|
||||
g_SvHostNameStore = g_pCVar->FindVar("host_name_store");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -589,10 +706,10 @@ void A2SQCache::SDK_OnAllLoaded()
|
||||
#endif
|
||||
|
||||
info.iUDPPort = iserver->GetUDPPort();
|
||||
info.nNewFlags |= 0x80;
|
||||
info.nNewFlags |= S2A_EXTRA_DATA_HAS_GAME_PORT;
|
||||
|
||||
info.iGameID = info.iSteamAppID;
|
||||
info.nNewFlags |= 0x01;
|
||||
info.nNewFlags |= S2A_EXTRA_DATA_GAMEID;
|
||||
|
||||
UpdateQueryCache();
|
||||
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef INETWORKSYSTEM_H
|
||||
#define INETWORKSYSTEM_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "appframework/IAppSystem.h"
|
||||
|
||||
|
||||
// This is the packet payload without any header bytes (which are attached for actual sending)
|
||||
#define NET_MAX_PAYLOAD ( 262144 - 4) // largest message we can send in bytes
|
||||
#define NET_MAX_PAYLOAD_BITS 18 // 2^NET_MAX_PAYLOAD_BITS > NET_MAX_PAYLOAD
|
||||
// This is just the client_t->netchan.datagram buffer size (shouldn't ever need to be huge)
|
||||
#define NET_MAX_DATAGRAM_PAYLOAD 4000 // = maximum unreliable playload size
|
||||
|
||||
// UDP has 28 byte headers
|
||||
#define UDP_HEADER_SIZE (20+8) // IP = 20, UDP = 8
|
||||
|
||||
#define MAX_ROUTABLE_PAYLOAD 1200 // x360 requires <= 1260, but now that listen servers can support "steam" mediated sockets, steam enforces 1200 byte limit
|
||||
|
||||
#if (MAX_ROUTABLE_PAYLOAD & 3) != 0
|
||||
#error Bit buffers must be a multiple of 4 bytes
|
||||
#endif
|
||||
|
||||
#define MIN_ROUTABLE_PAYLOAD 16 // minimum playload size
|
||||
|
||||
#define NETMSG_TYPE_BITS 8 // must be 2^NETMSG_TYPE_BITS > SVC_LASTMSG
|
||||
|
||||
// This is the payload plus any header info (excluding UDP header)
|
||||
|
||||
#define HEADER_BYTES 9 // 2*4 bytes seqnr, 1 byte flags
|
||||
|
||||
// Pad this to next higher 16 byte boundary
|
||||
// This is the largest packet that can come in/out over the wire, before processing the header
|
||||
// bytes will be stripped by the networking channel layer
|
||||
#define NET_MAX_MESSAGE PAD_NUMBER( ( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 )
|
||||
|
||||
#define NET_HEADER_FLAG_SPLITPACKET -2
|
||||
#define NET_HEADER_FLAG_COMPRESSEDPACKET -3
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations:
|
||||
//-----------------------------------------------------------------------------
|
||||
class INetworkMessageHandler;
|
||||
class INetworkMessage;
|
||||
class INetChannel;
|
||||
class INetworkMessageFactory;
|
||||
class bf_read;
|
||||
class bf_write;
|
||||
typedef struct netadr_s netadr_t;
|
||||
class CNetPacket;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Default ports
|
||||
//-----------------------------------------------------------------------------
|
||||
enum
|
||||
{
|
||||
NETWORKSYSTEM_DEFAULT_SERVER_PORT = 27001,
|
||||
NETWORKSYSTEM_DEFAULT_CLIENT_PORT = 27002
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This interface encompasses a one-way communication path between two
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef int ConnectionHandle_t;
|
||||
|
||||
enum ConnectionStatus_t
|
||||
{
|
||||
CONNECTION_STATE_DISCONNECTED = 0,
|
||||
CONNECTION_STATE_CONNECTING,
|
||||
CONNECTION_STATE_CONNECTION_FAILED,
|
||||
CONNECTION_STATE_CONNECTED,
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This interface encompasses a one-way communication path between two machines
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// abstract_class INetChannel
|
||||
// {
|
||||
// public:
|
||||
// // virtual INetworkMessageHandler *GetMsgHandler( void ) const = 0;
|
||||
// virtual const netadr_t &GetRemoteAddress( void ) const = 0;
|
||||
//
|
||||
// // send a net message
|
||||
// // NOTE: There are special connect/disconnect messages?
|
||||
// virtual bool AddNetMsg( INetworkMessage *msg, bool bForceReliable = false ) = 0;
|
||||
// // virtual bool RegisterMessage( INetworkMessage *msg ) = 0;
|
||||
//
|
||||
// virtual ConnectionStatus_t GetConnectionState( ) = 0;
|
||||
//
|
||||
// /*
|
||||
// virtual ConnectTo( const netadr_t& to ) = 0;
|
||||
// virtual Disconnect() = 0;
|
||||
//
|
||||
// virtual const netadr_t& GetLocalAddress() = 0;
|
||||
//
|
||||
// virtual const netadr_t& GetRemoteAddress() = 0;
|
||||
// */
|
||||
// };
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Network event types + structures
|
||||
//-----------------------------------------------------------------------------
|
||||
enum NetworkEventType_t
|
||||
{
|
||||
NETWORK_EVENT_CONNECTED = 0,
|
||||
NETWORK_EVENT_DISCONNECTED,
|
||||
NETWORK_EVENT_MESSAGE_RECEIVED,
|
||||
};
|
||||
|
||||
struct NetworkEvent_t
|
||||
{
|
||||
NetworkEventType_t m_nType;
|
||||
};
|
||||
|
||||
struct NetworkConnectionEvent_t : public NetworkEvent_t
|
||||
{
|
||||
INetChannel *m_pChannel;
|
||||
};
|
||||
|
||||
struct NetworkDisconnectionEvent_t : public NetworkEvent_t
|
||||
{
|
||||
INetChannel *m_pChannel;
|
||||
};
|
||||
|
||||
struct NetworkMessageReceivedEvent_t : public NetworkEvent_t
|
||||
{
|
||||
INetChannel *m_pChannel;
|
||||
INetworkMessage *m_pNetworkMessage;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main interface for low-level networking (packet sending). This is a low-level interface
|
||||
//-----------------------------------------------------------------------------
|
||||
abstract_class INetworkSystem : public IAppSystem
|
||||
{
|
||||
public:
|
||||
// Installs network message factories to be used with all connections
|
||||
virtual bool RegisterMessage( INetworkMessage *msg ) = 0;
|
||||
|
||||
// Start, shutdown a server
|
||||
virtual bool StartServer( unsigned short nServerListenPort = NETWORKSYSTEM_DEFAULT_SERVER_PORT ) = 0;
|
||||
virtual void ShutdownServer( ) = 0;
|
||||
|
||||
// Process server-side network messages
|
||||
virtual void ServerReceiveMessages() = 0;
|
||||
virtual void ServerSendMessages() = 0;
|
||||
|
||||
// Start, shutdown a client
|
||||
virtual bool StartClient( unsigned short nClientListenPort = NETWORKSYSTEM_DEFAULT_CLIENT_PORT ) = 0;
|
||||
virtual void ShutdownClient( ) = 0;
|
||||
|
||||
// Process client-side network messages
|
||||
virtual void ClientSendMessages() = 0;
|
||||
virtual void ClientReceiveMessages() = 0;
|
||||
|
||||
// Connect, disconnect a client to a server
|
||||
virtual INetChannel* ConnectClientToServer( const char *pServer, int nServerListenPort = NETWORKSYSTEM_DEFAULT_SERVER_PORT ) = 0;
|
||||
virtual void DisconnectClientFromServer( INetChannel* pChan ) = 0;
|
||||
|
||||
// Event queue
|
||||
virtual NetworkEvent_t *FirstNetworkEvent( ) = 0;
|
||||
virtual NetworkEvent_t *NextNetworkEvent( ) = 0;
|
||||
|
||||
// Returns the local host name
|
||||
virtual const char* GetLocalHostName( void ) const = 0;
|
||||
virtual const char* GetLocalAddress( void ) const = 0;
|
||||
|
||||
/*
|
||||
// NOTE: Server methods
|
||||
// NOTE: There's only 1 client INetChannel ever
|
||||
// There can be 0-N server INetChannels.
|
||||
virtual INetChannel* CreateConnection( bool bIsClientConnection ) = 0;
|
||||
|
||||
// Add methods for setting unreliable payloads
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
#endif // INETWORKSYSTEM_H
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#if !defined( PROTO_OOB_H )
|
||||
#define PROTO_OOB_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// This is used, unless overridden in the registry
|
||||
#define VALVE_MASTER_ADDRESS "207.173.177.10:27011"
|
||||
|
||||
#define PORT_RCON 27015 // Default RCON port, TCP
|
||||
#define PORT_MASTER 27011 // Default master port, UDP
|
||||
#define PORT_CLIENT 27005 // Default client port, UDP/TCP
|
||||
#define PORT_SERVER 27015 // Default server port, UDP/TCP
|
||||
#define PORT_HLTV 27020 // Default hltv port
|
||||
#define PORT_HLTV1 27021 // Default hltv[instance 1] port
|
||||
|
||||
#define PORT_X360_RESERVED_FIRST 27026 // X360 reserved port first
|
||||
#define PORT_X360_RESERVED_LAST 27034 // X360 reserved port last
|
||||
#ifdef ENABLE_RPT
|
||||
#define PORT_RPT 27035 // default RPT (remote perf testing) port, TCP
|
||||
#define PORT_RPT_LISTEN 27036 // RPT connection listener (remote perf testing) port, TCP
|
||||
#endif // ENABLE_RPT
|
||||
#define PORT_REPLAY 27040 // Default replay port
|
||||
|
||||
// out of band message id bytes
|
||||
|
||||
// M = master, S = server, C = client, A = any
|
||||
// the second character will always be \n if the message isn't a single
|
||||
// byte long (?? not true anymore?)
|
||||
|
||||
|
||||
// Requesting for full server list from Server Master
|
||||
#define A2M_GET_SERVERS 'c' // no params
|
||||
|
||||
// Master response with full server list
|
||||
#define M2A_SERVERS 'd' // + 6 byte IP/Port list.
|
||||
|
||||
// Request for full server list from Server Master done in batches
|
||||
#define A2M_GET_SERVERS_BATCH 'e' // + in532 uniqueID ( -1 for first batch )
|
||||
|
||||
// Master response with server list for channel
|
||||
#define M2A_SERVER_BATCH 'f' // + int32 next uniqueID( -1 for last batch ) + 6 byte IP/Port list.
|
||||
|
||||
// Request for MOTD from Server Master (Message of the Day)
|
||||
#define A2M_GET_MOTD 'g' // no params
|
||||
|
||||
// MOTD response Server Master
|
||||
#define M2A_MOTD 'h' // + string
|
||||
|
||||
// Generic Ping Request
|
||||
#define A2A_PING 'i' // respond with an A2A_ACK
|
||||
|
||||
// Generic Ack
|
||||
#define A2A_ACK 'j' // general acknowledgement without info
|
||||
|
||||
#define C2S_CONNECT 'k' // client requests to connect
|
||||
|
||||
// Print to client console.
|
||||
#define A2A_PRINT 'l' // print a message on client
|
||||
|
||||
// info request
|
||||
#define S2A_INFO_DETAILED 'm' // New Query protocol, returns dedicated or not, + other performance info.
|
||||
|
||||
#define A2S_RESERVE 'n' // reserves this server for specific players for a short period of time. Fails if not empty.
|
||||
|
||||
#define S2A_RESERVE_RESPONSE 'p' // server response to reservation request
|
||||
|
||||
// Another user is requesting a challenge value from this machine
|
||||
// NOTE: this is currently duplicated in SteamClient.dll but for a different purpose,
|
||||
// so these can safely diverge anytime. SteamClient will be using a different protocol
|
||||
// to update the master servers anyway.
|
||||
#define A2S_GETCHALLENGE 'q' // Request challenge # from another machine
|
||||
|
||||
#define A2S_RCON 'r' // client rcon command
|
||||
|
||||
#define A2A_CUSTOM 't' // a custom command, follow by a string for 3rd party tools
|
||||
|
||||
|
||||
// A user is requesting the list of master servers, auth servers, and titan dir servers from the Client Master server
|
||||
#define A2M_GETMASTERSERVERS 'v' // + byte (type of request, TYPE_CLIENT_MASTER or TYPE_SERVER_MASTER)
|
||||
|
||||
// Master server list response
|
||||
#define M2A_MASTERSERVERS 'w' // + byte type + 6 byte IP/Port List
|
||||
|
||||
#define A2M_GETACTIVEMODS 'x' // + string Request to master to provide mod statistics ( current usage ). "1" for first mod.
|
||||
|
||||
#define M2A_ACTIVEMODS 'y' // response: modname\r\nusers\r\nservers
|
||||
|
||||
#define M2M_MSG 'z' // Master peering message
|
||||
|
||||
// SERVER TO CLIENT/ANY
|
||||
|
||||
// Client connection is initiated by requesting a challenge value
|
||||
// the server sends this value back
|
||||
#define S2C_CHALLENGE 'A' // + challenge value
|
||||
|
||||
// Server notification to client to commence signon process using challenge value.
|
||||
#define S2C_CONNECTION 'B' // no params
|
||||
|
||||
// Response to server info requests
|
||||
|
||||
// Request for detailed server/rule information.
|
||||
#define S2A_INFO_GOLDSRC 'm' // Reserved for use by goldsrc servers
|
||||
|
||||
#define S2M_GETFILE 'J' // request module from master
|
||||
#define M2S_SENDFILE 'K' // send module to server
|
||||
|
||||
#define S2C_REDIRECT 'L' // + IP x.x.x.x:port, redirect client to other server/proxy
|
||||
|
||||
#define C2M_CHECKMD5 'M' // player client asks secure master if Module MD5 is valid
|
||||
#define M2C_ISVALIDMD5 'N' // secure servers answer to C2M_CHECKMD5
|
||||
|
||||
// MASTER TO SERVER
|
||||
#define M2A_ACTIVEMODS3 'P' // response: keyvalues struct of mods
|
||||
#define A2M_GETACTIVEMODS3 'Q' // get a list of mods and the stats about them
|
||||
|
||||
#define S2A_LOGSTRING 'R' // send a log string
|
||||
#define S2A_LOGKEY 'S' // send a log event as key value
|
||||
#define S2A_LOGSTRING2 'S' // send a log string including a secret value << this clashes with S2A_LOGKEY that nothing seems to use in CS:GO and is followed by secret value so should be compatible for server ops with their existing tools
|
||||
|
||||
#define A2S_SERVERQUERY_GETCHALLENGE 'W' // Request challenge # from another machine
|
||||
|
||||
#define A2S_KEY_STRING "Source Engine Query" // required postfix to a A2S_INFO query
|
||||
|
||||
#define A2M_GET_SERVERS_BATCH2 '1' // New style server query
|
||||
|
||||
#define A2M_GETACTIVEMODS2 '2' // New style mod info query
|
||||
|
||||
#define C2S_AUTHREQUEST1 '3' //
|
||||
#define S2C_AUTHCHALLENGE1 '4' //
|
||||
#define C2S_AUTHCHALLENGE2 '5' //
|
||||
#define S2C_AUTHCOMPLETE '6'
|
||||
#define C2S_AUTHCONNECT '7' // Unused, signals that the client has
|
||||
// authenticated the server
|
||||
|
||||
#define C2S_VALIDATE_SESSION '8'
|
||||
// #define UNUSED_A2S_LANSEARCH 'C' // LAN game details searches
|
||||
// #define UNUSED_S2A_LANSEARCHREPLY 'F' // LAN game details reply
|
||||
|
||||
#define S2C_CONNREJECT '9' // Special protocol for rejected connections.
|
||||
|
||||
#define MAX_OOB_KEYVALUES 600 // max size in bytes for keyvalues included in an OOB msg
|
||||
#define MAKE_4BYTES( a, b, c, d ) ( ( ((unsigned char)(d)) << 24 ) | ( ((unsigned char)(c)) << 16 ) | ( ((unsigned char)(b)) << 8 ) | ( ((unsigned char)(a)) << 0 ) )
|
||||
|
||||
#define A2A_KV_CMD '?' // generic KeyValues command [1 byte: version] [version dependent data...]
|
||||
#define A2A_KV_VERSION 1 // version of generic KeyValues command
|
||||
// [4 bytes: header] [4 bytes: replyid] [4 bytes: challenge] [4 bytes: extra] [4 bytes: numbytes] [numbytes: serialized KV]
|
||||
|
||||
// These can be owned by Steam after we get rid of this legacy code.
|
||||
#define S2A_INFO_SRC 'I' // + Address, hostname, map, gamedir, gamedescription, active players, maxplayers, protocol
|
||||
#define S2M_HEARTBEAT 'a' // + challeange + sequence + active + #channels + channels
|
||||
#define S2M_HEARTBEAT2 '0' // New style heartbeat
|
||||
#define S2M_SHUTDOWN 'b' // no params
|
||||
#define M2A_CHALLENGE 's' // + challenge value
|
||||
#define M2S_REQUESTRESTART 'O' // HLMaster rejected a server's connection because the server needs to be updated
|
||||
#define A2S_RULES 'V' // request rules list from server
|
||||
#define S2A_RULES 'E' // + number of rules + string key and string value pairs
|
||||
#define A2S_INFO 'T' // server info request - this must match the Goldsrc engine
|
||||
#define S2A_PLAYER 'D' // + Playernum, name, frags, /*deaths*/, time on server
|
||||
#define A2S_PLAYER 'U' // request player list
|
||||
|
||||
#define A2S_PING2 'Y' // new-style minimalist ping request
|
||||
#define S2A_PING2REPLY 'Z' // new-style minimalist ping reply
|
||||
|
||||
|
||||
// temp hack until we kill the legacy interface
|
||||
// The new S2A_INFO_SRC packet has a byte at the end that has these bits in it, telling
|
||||
// which data follows.
|
||||
#define S2A_EXTRA_DATA_HAS_GAME_PORT 0x80 // Next 2 bytes include the game port.
|
||||
#define S2A_EXTRA_DATA_HAS_SPECTATOR_DATA 0x40 // Next 2 bytes include the spectator port, then the spectator server name.
|
||||
#define S2A_EXTRA_DATA_HAS_GAMETAG_DATA 0x20 // Next bytes are the game tag string
|
||||
#define S2A_EXTRA_DATA_HAS_STEAMID 0x10 // Next 8 bytes are the steamID
|
||||
#define S2A_EXTRA_DATA_GAMEID 0x01 // Next 8 bytes are the gameID of the server
|
||||
|
||||
#define A2S_RESERVE_CHECK '!' // check if server reservation cookie is same as the one we are holding
|
||||
#define S2A_RESERVE_CHECK_RESPONSE '%' // server response to reservation request
|
||||
|
||||
#define A2S_PING '$'
|
||||
#define S2A_PING_RESPONSE '^'
|
||||
|
||||
#endif
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// protocol.h -- communications protocols
|
||||
#ifndef PROTOCOL_H
|
||||
#define PROTOCOL_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#define INSTANCE_BASELINE_TABLENAME "instancebaseline"
|
||||
#define LIGHT_STYLES_TABLENAME "lightstyles"
|
||||
#define USER_INFO_TABLENAME "userinfo"
|
||||
#define SERVER_STARTUP_DATA_TABLENAME "server_query_info" // the name is a remnant...
|
||||
#define DYNAMIC_MODEL_TABLENAME "dynamicmodel"
|
||||
|
||||
|
||||
//#define CURRENT_PROTOCOL 1
|
||||
|
||||
|
||||
#define DELTA_OFFSET_BITS 5
|
||||
#define DELTA_OFFSET_MAX ( ( 1 << DELTA_OFFSET_BITS ) - 1 )
|
||||
|
||||
#define DELTASIZE_BITS 20 // must be: 2^DELTASIZE_BITS > (NET_MAX_PAYLOAD * 8)
|
||||
|
||||
// Largest # of commands to send in a packet
|
||||
#define NUM_NEW_COMMAND_BITS 4
|
||||
#define MAX_NEW_COMMANDS ((1 << NUM_NEW_COMMAND_BITS)-1)
|
||||
|
||||
// Max number of history commands to send ( 2 by default ) in case of dropped packets
|
||||
#define NUM_BACKUP_COMMAND_BITS 3
|
||||
#define MAX_BACKUP_COMMANDS ((1 << NUM_BACKUP_COMMAND_BITS)-1)
|
||||
|
||||
|
||||
#define PROTOCOL_AUTHCERTIFICATE 0x01 // Connection from client is using a WON authenticated certificate
|
||||
#define PROTOCOL_HASHEDCDKEY 0x02 // Connection from client is using hashed CD key because WON comm. channel was unreachable
|
||||
#define PROTOCOL_STEAM 0x03 // Steam certificates
|
||||
#define PROTOCOL_LASTVALID 0x03 // Last valid protocol
|
||||
|
||||
#define CONNECTIONLESS_HEADER 0xFFFFFFFF // all OOB packet start with this sequence
|
||||
#define STEAM_KEYSIZE 2048 // max size needed to contain a steam authentication key (both server and client)
|
||||
|
||||
// each channel packet has 1 byte of FLAG bits
|
||||
#define PACKET_FLAG_RELIABLE (1<<0) // packet contains subchannel stream data
|
||||
#define PACKET_FLAG_COMPRESSED (1<<1) // packet is compressed
|
||||
#define PACKET_FLAG_ENCRYPTED (1<<2) // packet is encrypted
|
||||
#define PACKET_FLAG_SPLIT (1<<3) // packet is split
|
||||
#define PACKET_FLAG_CHOKED (1<<4) // packet was choked by sender
|
||||
|
||||
// NOTE: Bits 5, 6, and 7 are used to specify the # of padding bits at the end of the packet!!!
|
||||
#define ENCODE_PAD_BITS( x ) ( ( x << 5 ) & 0xff )
|
||||
#define DECODE_PAD_BITS( x ) ( ( x >> 5 ) & 0xff )
|
||||
|
||||
//
|
||||
// client to server
|
||||
//
|
||||
|
||||
#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file.
|
||||
#define RES_PRELOAD (1<<1) // Load on client rather than just reserving name
|
||||
|
||||
// Some day we may want to integrate Zoid's CL 1295766 - Rewrite of Source networking to be protobuf based.
|
||||
|
||||
#endif // PROTOCOL_H
|
||||
|
||||
Reference in New Issue
Block a user