nillerusr
2 years ago
committed by
GitHub
45 changed files with 1274 additions and 690 deletions
@ -0,0 +1,61 @@
@@ -0,0 +1,61 @@
|
||||
//======== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ========
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
#ifndef MASTER_H |
||||
#define MASTER_H |
||||
#ifdef _WIN32 |
||||
#pragma once |
||||
#endif |
||||
|
||||
#include "engine/iserversinfo.h" |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Implements a master server interface.
|
||||
//-----------------------------------------------------------------------------
|
||||
class IMaster |
||||
{ |
||||
public: |
||||
// Allow master server to register cvars/commands
|
||||
virtual void Init( void ) = 0; |
||||
// System is shutting down
|
||||
virtual void Shutdown( void ) = 0; |
||||
// Server is shutting down
|
||||
virtual void ShutdownConnection( void ) = 0; |
||||
// Sends the actual heartbeat to the master ( after challenge value is parsed )
|
||||
virtual void SendHeartbeat( struct adrlist_s *p ) = 0; |
||||
// Add server to global master list
|
||||
virtual void AddServer( struct netadr_s *adr ) = 0; |
||||
// If parsing for server, etc. fails, always have at least one server around to use.
|
||||
virtual void UseDefault ( void ) = 0; |
||||
// See if it's time to send the next heartbeat
|
||||
virtual void CheckHeartbeat( void ) = 0; |
||||
// Master sent back a challenge value, read it and send the actual heartbeat
|
||||
virtual void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg ) = 0; |
||||
// Console command to set/remove master server
|
||||
virtual void AddMaster_f( const CCommand &args ) = 0; |
||||
// Force a heartbeat to be issued right away
|
||||
virtual void Heartbeat_f( void ) = 0; |
||||
|
||||
virtual void ProcessConnectionlessPacket( netpacket_t *packet ) = 0; |
||||
|
||||
virtual void RunFrame( void ) = 0; |
||||
}; |
||||
|
||||
extern IMaster *master; |
||||
extern IServersInfo *g_pServersInfo; |
||||
|
||||
#endif // MASTER_H
|
@ -0,0 +1,715 @@
@@ -0,0 +1,715 @@
|
||||
//======177== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ========
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
#include "quakedef.h" |
||||
#include "server.h" |
||||
#include "master.h" |
||||
#include "proto_oob.h" |
||||
#include "host.h" |
||||
#include "eiface.h" |
||||
#include "server.h" |
||||
#include "utlmap.h" |
||||
|
||||
extern ConVar sv_tags; |
||||
extern ConVar sv_lan; |
||||
|
||||
#define S2A_EXTRA_DATA_HAS_GAMETAG_DATA 0x01 // Next bytes are the game tag string
|
||||
#define RETRY_INFO_REQUEST_TIME 0.4 // seconds
|
||||
#define MASTER_RESPONSE_TIMEOUT 1.5 // seconds
|
||||
#define INFO_REQUEST_TIMEOUT 5.0 // seconds
|
||||
|
||||
static char g_MasterServers[][64] = |
||||
{ |
||||
"185.192.97.130:27010", |
||||
"168.138.92.21:27016" |
||||
}; |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: List of master servers and some state info about them
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct adrlist_s |
||||
{ |
||||
// Next master in chain
|
||||
struct adrlist_s *next; |
||||
// Challenge request sent to master
|
||||
qboolean heartbeatwaiting; |
||||
// Challenge request send time
|
||||
float heartbeatwaitingtime; |
||||
// Last one is Main master
|
||||
int heartbeatchallenge; |
||||
// Time we sent last heartbeat
|
||||
double last_heartbeat; |
||||
// Master server address
|
||||
netadr_t adr; |
||||
} adrlist_t; |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Implements the master server interface
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMaster : public IMaster, public IServersInfo |
||||
{ |
||||
public: |
||||
CMaster( void ); |
||||
virtual ~CMaster( void ); |
||||
|
||||
// Heartbeat functions.
|
||||
void Init( void ); |
||||
void Shutdown( void ); |
||||
// Sets up master address
|
||||
void ShutdownConnection(void); |
||||
void SendHeartbeat( struct adrlist_s *p ); |
||||
void AddServer( struct netadr_s *adr ); |
||||
void UseDefault ( void ); |
||||
void CheckHeartbeat (void); |
||||
void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg ); |
||||
void PingServer( netadr_t &svadr ); |
||||
|
||||
void ProcessConnectionlessPacket( netpacket_t *packet ); |
||||
|
||||
void AddMaster_f( const CCommand &args ); |
||||
void Heartbeat_f( void ); |
||||
|
||||
void RunFrame(); |
||||
void RetryServersInfoRequest(); |
||||
|
||||
void ReplyInfo( const netadr_t &adr, uint sequence ); |
||||
newgameserver_t &ProcessInfo( bf_read &buf ); |
||||
|
||||
// SeversInfo
|
||||
void RequestInternetServerList( const char *gamedir, IServerListResponse *response ); |
||||
void RequestLANServerList( const char *gamedir, IServerListResponse *response ); |
||||
void AddServerAddresses( netadr_t **adr, int count ); |
||||
void RequestServerInfo( const netadr_t &adr ); |
||||
void StopRefresh(); |
||||
|
||||
private: |
||||
// List of known master servers
|
||||
adrlist_t *m_pMasterAddresses; |
||||
|
||||
bool m_bInitialized; |
||||
bool m_bRefreshing; |
||||
|
||||
int m_iServersResponded; |
||||
|
||||
double m_flStartRequestTime; |
||||
double m_flRetryRequestTime; |
||||
double m_flMasterRequestTime; |
||||
|
||||
uint m_iInfoSequence; |
||||
char m_szGameDir[256]; |
||||
|
||||
// If nomaster is true, the server will not send heartbeats to the master server
|
||||
bool m_bNoMasters; |
||||
|
||||
CUtlMap<netadr_t, bool> m_serverAddresses; |
||||
CUtlMap<uint, double> m_serversRequestTime; |
||||
|
||||
IServerListResponse *m_serverListResponse; |
||||
}; |
||||
|
||||
static CMaster s_MasterServer; |
||||
IMaster *master = (IMaster *)&s_MasterServer; |
||||
|
||||
IServersInfo *g_pServersInfo = (IServersInfo*)&s_MasterServer; |
||||
|
||||
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMaster, IServersInfo, SERVERLIST_INTERFACE_VERSION, s_MasterServer ); |
||||
|
||||
#define HEARTBEAT_SECONDS 140.0 |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CMaster::CMaster( void ) |
||||
{ |
||||
m_pMasterAddresses = NULL; |
||||
m_bNoMasters = false; |
||||
m_bInitialized = false; |
||||
m_iServersResponded = 0; |
||||
|
||||
m_serverListResponse = NULL; |
||||
SetDefLessFunc( m_serverAddresses ); |
||||
SetDefLessFunc( m_serversRequestTime ); |
||||
m_bRefreshing = false; |
||||
m_iInfoSequence = 1; |
||||
|
||||
Init(); |
||||
} |
||||
|
||||
CMaster::~CMaster( void ) |
||||
{ |
||||
} |
||||
|
||||
void CMaster::RunFrame() |
||||
{ |
||||
CheckHeartbeat(); |
||||
|
||||
if( !m_bRefreshing ) |
||||
return; |
||||
|
||||
if( m_serverListResponse && |
||||
m_flStartRequestTime < Plat_FloatTime()-INFO_REQUEST_TIMEOUT ) |
||||
{ |
||||
StopRefresh(); |
||||
m_serverListResponse->RefreshComplete( NServerResponse::nServerFailedToRespond ); |
||||
return; |
||||
} |
||||
|
||||
if( m_iServersResponded > 0 && |
||||
m_iServersResponded >= m_serverAddresses.Count() && |
||||
m_flMasterRequestTime < Plat_FloatTime() - MASTER_RESPONSE_TIMEOUT ) |
||||
{ |
||||
StopRefresh(); |
||||
m_serverListResponse->RefreshComplete( NServerResponse::nServerResponded ); |
||||
return; |
||||
} |
||||
|
||||
if( m_flRetryRequestTime < Plat_FloatTime() - RETRY_INFO_REQUEST_TIME ) |
||||
{ |
||||
m_flRetryRequestTime = Plat_FloatTime(); |
||||
|
||||
if( m_serverAddresses.Count() == 0 ) // Retry masterserver request
|
||||
{ |
||||
g_pServersInfo->RequestInternetServerList(m_szGameDir, NULL); |
||||
return; |
||||
} |
||||
|
||||
if( m_iServersResponded < m_serverAddresses.Count() ) |
||||
RetryServersInfoRequest(); |
||||
} |
||||
} |
||||
|
||||
void CMaster::StopRefresh() |
||||
{ |
||||
if( !m_bRefreshing ) |
||||
return; |
||||
|
||||
m_iServersResponded = 0; |
||||
m_bRefreshing = false; |
||||
m_serverAddresses.RemoveAll(); |
||||
m_serversRequestTime.RemoveAll(); |
||||
} |
||||
|
||||
void CMaster::ReplyInfo( const netadr_t &adr, uint sequence ) |
||||
{ |
||||
static char gamedir[MAX_OSPATH]; |
||||
Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) ); |
||||
|
||||
CUtlBuffer buf; |
||||
buf.EnsureCapacity( 2048 ); |
||||
|
||||
buf.PutUnsignedInt( LittleDWord( CONNECTIONLESS_HEADER ) ); |
||||
buf.PutUnsignedChar( S2C_INFOREPLY ); |
||||
|
||||
buf.PutUnsignedInt(sequence); |
||||
buf.PutUnsignedChar( PROTOCOL_VERSION ); // Hardcoded protocol version number
|
||||
buf.PutString( sv.GetName() ); |
||||
buf.PutString( sv.GetMapName() ); |
||||
buf.PutString( gamedir ); |
||||
buf.PutString( serverGameDLL->GetGameDescription() ); |
||||
|
||||
// player info
|
||||
buf.PutUnsignedChar( sv.GetNumClients() ); |
||||
buf.PutUnsignedChar( sv.GetMaxClients() ); |
||||
buf.PutUnsignedChar( sv.GetNumFakeClients() ); |
||||
|
||||
// Password?
|
||||
buf.PutUnsignedChar( sv.GetPassword() != NULL ? 1 : 0 ); |
||||
|
||||
// Write a byte with some flags that describe what is to follow.
|
||||
const char *pchTags = sv_tags.GetString(); |
||||
int nFlags = 0; |
||||
|
||||
if ( pchTags && pchTags[0] != '\0' ) |
||||
nFlags |= S2A_EXTRA_DATA_HAS_GAMETAG_DATA; |
||||
|
||||
buf.PutUnsignedInt( nFlags ); |
||||
|
||||
if ( nFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA ) |
||||
buf.PutString( pchTags ); |
||||
|
||||
NET_SendPacket( NULL, NS_SERVER, adr, (unsigned char *)buf.Base(), buf.TellPut() ); |
||||
} |
||||
|
||||
newgameserver_t &CMaster::ProcessInfo(bf_read &buf) |
||||
{ |
||||
static newgameserver_t s; |
||||
memset( &s, 0, sizeof(s) ); |
||||
|
||||
s.m_nProtocolVersion = buf.ReadByte(); |
||||
|
||||
buf.ReadString( s.m_szServerName, sizeof(s.m_szServerName) ); |
||||
buf.ReadString( s.m_szMap, sizeof(s.m_szMap) ); |
||||
buf.ReadString( s.m_szGameDir, sizeof(s.m_szGameDir) ); |
||||
|
||||
buf.ReadString( s.m_szGameDescription, sizeof(s.m_szGameDescription) ); |
||||
|
||||
// player info
|
||||
s.m_nPlayers = buf.ReadByte(); |
||||
s.m_nMaxPlayers = buf.ReadByte(); |
||||
s.m_nBotPlayers = buf.ReadByte(); |
||||
|
||||
// Password?
|
||||
s.m_bPassword = buf.ReadByte(); |
||||
s.m_iFlags = buf.ReadLong(); |
||||
|
||||
if( s.m_iFlags & S2A_EXTRA_DATA_HAS_GAMETAG_DATA ) |
||||
{ |
||||
buf.ReadString( s.m_szGameTags, sizeof(s.m_szGameTags) ); |
||||
} |
||||
|
||||
return s; |
||||
} |
||||
|
||||
void CMaster::ProcessConnectionlessPacket( netpacket_t *packet ) |
||||
{ |
||||
static ALIGN4 char string[2048] ALIGN4_POST; // Buffer for sending heartbeat
|
||||
|
||||
uint ip; uint16 port; |
||||
|
||||
bf_read msg = packet->message; |
||||
char c = msg.ReadChar(); |
||||
|
||||
if ( c == 0 ) |
||||
return; |
||||
|
||||
switch( c ) |
||||
{ |
||||
case M2S_CHALLENGE: |
||||
{ |
||||
RespondToHeartbeatChallenge( packet->from, msg ); |
||||
break; |
||||
} |
||||
case M2C_QUERY: |
||||
{ |
||||
if( !m_bRefreshing ) |
||||
break; |
||||
|
||||
ip = msg.ReadLong(); |
||||
port = msg.ReadShort(); |
||||
|
||||
while( ip != 0 && port != 0 ) |
||||
{ |
||||
netadr_t adr(ip, port); |
||||
|
||||
unsigned short index = m_serverAddresses.Find(adr); |
||||
if( index != m_serverAddresses.InvalidIndex() ) |
||||
{ |
||||
ip = msg.ReadLong(); |
||||
port = msg.ReadShort(); |
||||
continue; |
||||
} |
||||
|
||||
m_serverAddresses.Insert(adr, false); |
||||
RequestServerInfo(adr); |
||||
|
||||
ip = msg.ReadLong(); |
||||
port = msg.ReadShort(); |
||||
} |
||||
break; |
||||
} |
||||
case C2S_INFOREQUEST: |
||||
{ |
||||
ReplyInfo(packet->from, msg.ReadLong()); |
||||
break; |
||||
} |
||||
case S2C_INFOREPLY: |
||||
{ |
||||
if( !m_bRefreshing ) |
||||
break; |
||||
|
||||
uint sequence = msg.ReadLong(); |
||||
newgameserver_t &s = ProcessInfo( msg ); |
||||
|
||||
unsigned short index = m_serverAddresses.Find(packet->from); |
||||
unsigned short rindex = m_serversRequestTime.Find(sequence); |
||||
|
||||
if( index == m_serverAddresses.InvalidIndex() || |
||||
rindex == m_serversRequestTime.InvalidIndex() ) |
||||
break; |
||||
|
||||
double requestTime = m_serversRequestTime[rindex]; |
||||
|
||||
if( m_serverAddresses[index] ) // shit happens
|
||||
return; |
||||
|
||||
m_serverAddresses[index] = true; |
||||
s.m_nPing = (Plat_FloatTime()-requestTime)*1000.0; |
||||
s.m_NetAdr = packet->from; |
||||
m_serverListResponse->ServerResponded( s ); |
||||
|
||||
m_iServersResponded++; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void CMaster::RequestServerInfo( const netadr_t &adr ) |
||||
{ |
||||
static ALIGN4 char string[256] ALIGN4_POST; // Buffer for sending heartbeat
|
||||
bf_write msg( string, sizeof(string) ); |
||||
|
||||
msg.WriteLong( CONNECTIONLESS_HEADER ); |
||||
msg.WriteByte( C2S_INFOREQUEST ); |
||||
msg.WriteLong( m_iInfoSequence ); |
||||
m_serversRequestTime.Insert(m_iInfoSequence, Plat_FloatTime()); |
||||
|
||||
m_iInfoSequence++; |
||||
NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() ); |
||||
} |
||||
|
||||
void CMaster::RetryServersInfoRequest() |
||||
{ |
||||
FOR_EACH_MAP_FAST( m_serverAddresses, i ) |
||||
{ |
||||
bool bResponded = m_serverAddresses.Element(i); |
||||
if( bResponded ) |
||||
continue; |
||||
|
||||
const netadr_t adr = m_serverAddresses.Key(i); |
||||
RequestServerInfo( adr ); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sends a heartbeat to the master server
|
||||
// Input : *p - x00\x00\x00\x00\x00\x00
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::SendHeartbeat ( adrlist_t *p ) |
||||
{ |
||||
static ALIGN4 char string[256] ALIGN4_POST; // Buffer for sending heartbeat
|
||||
char szGD[ MAX_OSPATH ]; |
||||
|
||||
if ( !p ) |
||||
return; |
||||
|
||||
// Still waiting on challenge response?
|
||||
if ( p->heartbeatwaiting ) |
||||
return; |
||||
|
||||
// Waited too long
|
||||
if ( (realtime - p->heartbeatwaitingtime ) >= HB_TIMEOUT ) |
||||
return; |
||||
|
||||
// Send to master
|
||||
Q_FileBase( com_gamedir, szGD, sizeof( szGD ) ); |
||||
|
||||
bf_write buf( string, sizeof(string) ); |
||||
buf.WriteByte( S2M_HEARTBEAT ); |
||||
buf.WriteLong( p->heartbeatchallenge ); |
||||
buf.WriteShort( PROTOCOL_VERSION ); |
||||
buf.WriteString( szGD ); |
||||
|
||||
NET_SendPacket( NULL, NS_SERVER, p->adr, buf.GetData(), buf.GetNumBytesWritten() ); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Requests a challenge so we can then send a heartbeat
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::CheckHeartbeat (void) |
||||
{ |
||||
adrlist_t *p; |
||||
ALIGN4 char buf[256] ALIGN4_POST; |
||||
|
||||
if ( m_bNoMasters || // We are ignoring heartbeats
|
||||
sv_lan.GetInt() || // Lan servers don't heartbeat
|
||||
(sv.GetMaxClients() <= 1) || // not a multiplayer server.
|
||||
!sv.IsActive() ) // only heartbeat if a server is running.
|
||||
return; |
||||
|
||||
p = m_pMasterAddresses; |
||||
while ( p ) |
||||
{ |
||||
// Time for another try?
|
||||
if ( ( realtime - p->last_heartbeat) < HEARTBEAT_SECONDS) // not time to send yet
|
||||
{ |
||||
p = p->next; |
||||
continue; |
||||
} |
||||
|
||||
// Should we resend challenge request?
|
||||
if ( p->heartbeatwaiting && |
||||
( ( realtime - p->heartbeatwaitingtime ) < HB_TIMEOUT ) ) |
||||
{ |
||||
p = p->next; |
||||
continue; |
||||
} |
||||
|
||||
int32 challenge = RandomInt( 0, INT_MAX ); |
||||
|
||||
p->heartbeatwaiting = true; |
||||
p->heartbeatwaitingtime = realtime; |
||||
|
||||
p->last_heartbeat = realtime; // Flag at start so we don't just keep trying for hb's when
|
||||
p->heartbeatchallenge = challenge; |
||||
|
||||
bf_write msg("Master Join", buf, sizeof(buf)); |
||||
|
||||
msg.WriteByte( S2M_GETCHALLENGE ); |
||||
msg.WriteLong( challenge ); |
||||
|
||||
// Send to master asking for a challenge #
|
||||
NET_SendPacket( NULL, NS_SERVER, p->adr, msg.GetData(), msg.GetNumBytesWritten() ); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Server is shutting down, unload master servers list, tell masters that we are closing the server
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::ShutdownConnection( void ) |
||||
{ |
||||
adrlist_t *p; |
||||
|
||||
if ( !host_initialized ) |
||||
return; |
||||
|
||||
if ( m_bNoMasters || // We are ignoring heartbeats
|
||||
sv_lan.GetInt() || // Lan servers don't heartbeat
|
||||
(sv.GetMaxClients() <= 1) ) // not a multiplayer server.
|
||||
return; |
||||
|
||||
const char packet = S2M_SHUTDOWN; |
||||
|
||||
p = m_pMasterAddresses; |
||||
while ( p ) |
||||
{ |
||||
NET_SendPacket( NULL, NS_SERVER, p->adr, (unsigned char*)&packet, 1); |
||||
p->last_heartbeat = -99999.0; |
||||
p = p->next; |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add server to the master list
|
||||
// Input : *adr -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::AddServer( netadr_t *adr ) |
||||
{ |
||||
adrlist_t *n; |
||||
|
||||
// See if it's there
|
||||
n = m_pMasterAddresses; |
||||
while ( n ) |
||||
{ |
||||
if ( n->adr.CompareAdr( *adr ) ) |
||||
break; |
||||
n = n->next; |
||||
} |
||||
|
||||
// Found it in the list.
|
||||
if ( n ) |
||||
return; |
||||
|
||||
n = ( adrlist_t * ) malloc ( sizeof( adrlist_t ) ); |
||||
if ( !n ) |
||||
Sys_Error( "Error allocating %zd bytes for master address.", sizeof( adrlist_t ) ); |
||||
|
||||
memset( n, 0, sizeof( adrlist_t ) ); |
||||
|
||||
n->adr = *adr; |
||||
|
||||
// Queue up a full heartbeat to all master servers.
|
||||
n->last_heartbeat = -99999.0; |
||||
|
||||
// Link it in.
|
||||
n->next = m_pMasterAddresses; |
||||
m_pMasterAddresses = n; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add built-in default master if woncomm.lst doesn't parse
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::UseDefault ( void ) |
||||
{ |
||||
netadr_t adr; |
||||
|
||||
for( int i = 0; i < ARRAYSIZE(g_MasterServers);i++ ) |
||||
{ |
||||
// Convert to netadr_t
|
||||
if ( NET_StringToAdr ( g_MasterServers[i], &adr ) ) |
||||
{ |
||||
// Add to master list
|
||||
AddServer( &adr ); |
||||
} |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg ) |
||||
{ |
||||
adrlist_t *p; |
||||
uint challenge, challenge2; |
||||
|
||||
// No masters, just ignore.
|
||||
if ( !m_pMasterAddresses ) |
||||
return; |
||||
|
||||
p = m_pMasterAddresses; |
||||
while ( p ) |
||||
{ |
||||
if ( from.CompareAdr( p->adr ) ) |
||||
break; |
||||
|
||||
p = p->next; |
||||
} |
||||
|
||||
// Not a known master server.
|
||||
if ( !p ) |
||||
return; |
||||
|
||||
challenge = msg.ReadLong(); |
||||
challenge2 = msg.ReadLong(); |
||||
|
||||
if( p->heartbeatchallenge != challenge2 ) |
||||
{ |
||||
Warning("unexpected master server info query packet (wrong challenge!)\n"); |
||||
return; |
||||
} |
||||
|
||||
// Kill timer
|
||||
p->heartbeatwaiting = false; |
||||
p->heartbeatchallenge = challenge; |
||||
|
||||
// Send the actual heartbeat request to this master server.
|
||||
SendHeartbeat( p ); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add/remove master servers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::AddMaster_f ( const CCommand &args ) |
||||
{ |
||||
CUtlString cmd( ( args.ArgC() > 1 ) ? args[ 1 ] : "" ); |
||||
|
||||
netadr_t adr; |
||||
|
||||
if( !NET_StringToAdr(cmd.String(), &adr) ) |
||||
{ |
||||
Warning("Invalid address\n"); |
||||
return; |
||||
} |
||||
|
||||
this->AddServer(&adr); |
||||
} |
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Send a new heartbeat to the master
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::Heartbeat_f (void) |
||||
{ |
||||
adrlist_t *p; |
||||
|
||||
p = m_pMasterAddresses; |
||||
while ( p ) |
||||
{ |
||||
// Queue up a full hearbeat
|
||||
p->last_heartbeat = -9999.0; |
||||
p->heartbeatwaitingtime = -9999.0; |
||||
p = p->next; |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void AddMaster_f( const CCommand &args ) |
||||
{ |
||||
master->AddMaster_f( args ); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void Heartbeat1_f( void ) |
||||
{ |
||||
master->Heartbeat_f(); |
||||
} |
||||
|
||||
static ConCommand setmaster("addmaster", AddMaster_f ); |
||||
static ConCommand heartbeat("heartbeat", Heartbeat1_f, "Force heartbeat of master servers" ); |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Adds master server console commands
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::Init( void ) |
||||
{ |
||||
// Already able to initialize at least once?
|
||||
if ( m_bInitialized ) |
||||
return; |
||||
|
||||
// So we don't do this a send time.sv_mas
|
||||
m_bInitialized = true; |
||||
|
||||
UseDefault(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaster::Shutdown(void) |
||||
{ |
||||
adrlist_t *p, *n; |
||||
|
||||
// Free the master list now.
|
||||
p = m_pMasterAddresses; |
||||
while ( p ) |
||||
{ |
||||
n = p->next; |
||||
free( p ); |
||||
p = n; |
||||
} |
||||
|
||||
m_pMasterAddresses = NULL; |
||||
} |
||||
|
||||
// ServersInfo
|
||||
void CMaster::RequestInternetServerList(const char *gamedir, IServerListResponse *response) |
||||
{ |
||||
if( m_bNoMasters ) return; |
||||
strncpy( m_szGameDir, gamedir, sizeof(m_szGameDir) ); |
||||
|
||||
if( response ) |
||||
{ |
||||
StopRefresh(); |
||||
m_bRefreshing = true; |
||||
m_serverListResponse = response; |
||||
m_flRetryRequestTime = m_flStartRequestTime = m_flMasterRequestTime = Plat_FloatTime(); |
||||
} |
||||
|
||||
ALIGN4 char buf[256] ALIGN4_POST; |
||||
bf_write msg(buf, sizeof(buf)); |
||||
|
||||
msg.WriteByte( C2M_CLIENTQUERY ); |
||||
msg.WriteString(gamedir); |
||||
|
||||
adrlist_t *p; |
||||
|
||||
p = m_pMasterAddresses; |
||||
while ( p ) |
||||
{ |
||||
NET_SendPacket(NULL, NS_CLIENT, p->adr, msg.GetData(), msg.GetNumBytesWritten() ); |
||||
p = p->next; |
||||
} |
||||
} |
||||
|
||||
void CMaster::RequestLANServerList(const char *gamedir, IServerListResponse *response) |
||||
{ |
||||
|
||||
} |
||||
|
||||
void CMaster::AddServerAddresses( netadr_t **adr, int count ) |
||||
{ |
||||
|
||||
} |
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: interface to steam managing game server/client match making
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef ISERVERSINFO_H |
||||
#define ISERVERSINFO_H |
||||
#ifdef _WIN32 |
||||
#pragma once |
||||
#endif |
||||
|
||||
#define MAX_GAME_DESCRIPTION 8192 |
||||
#define MAX_SERVER_NAME 2048 |
||||
|
||||
enum NServerResponse |
||||
{ |
||||
nServerResponded = 0, |
||||
nServerFailedToRespond, |
||||
nNoServersListedOnMasterServer, |
||||
}; |
||||
|
||||
class newgameserver_t |
||||
{ |
||||
public: |
||||
newgameserver_t() = default; |
||||
|
||||
netadr_t m_NetAdr; ///< IP/Query Port/Connection Port for this server
|
||||
int m_nPing; ///< current ping time in milliseconds
|
||||
int m_nProtocolVersion; |
||||
bool m_bHadSuccessfulResponse; ///< server has responded successfully in the past
|
||||
bool m_bDoNotRefresh; ///< server is marked as not responding and should no longer be refreshed
|
||||
char m_szGameDir[MAX_PATH]; ///< current game directory
|
||||
char m_szMap[MAX_PATH]; ///< current map
|
||||
char m_szGameTags[MAX_PATH]; |
||||
char m_szGameDescription[MAX_GAME_DESCRIPTION]; ///< game description
|
||||
|
||||
int m_nPlayers; |
||||
int m_nMaxPlayers; ///< Maximum players that can join this server
|
||||
int m_nBotPlayers; ///< Number of bots (i.e simulated players) on this server
|
||||
bool m_bPassword; ///< true if this server needs a password to join
|
||||
|
||||
int m_iFlags; |
||||
|
||||
/// Game server name
|
||||
char m_szServerName[MAX_SERVER_NAME]; |
||||
}; |
||||
|
||||
class IServerListResponse |
||||
{ |
||||
public: |
||||
// Server has responded ok with updated data
|
||||
virtual void ServerResponded( newgameserver_t &server ) = 0; |
||||
virtual void RefreshComplete( NServerResponse response ) = 0; |
||||
}; |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Callback interface for receiving responses after pinging an individual server
|
||||
//
|
||||
class IServerPingResponse |
||||
{ |
||||
public: |
||||
// Server has responded successfully and has updated data
|
||||
virtual void ServerResponded( newgameserver_t &server ) = 0; |
||||
}; |
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Callback interface for receiving responses after requesting details on
|
||||
// who is playing on a particular server.
|
||||
//
|
||||
class IServerPlayersResponse |
||||
{ |
||||
public: |
||||
// Got data on a new player on the server -- you'll get this callback once per player
|
||||
// on the server which you have requested player data on.
|
||||
virtual void AddPlayerToList( const char *pchName, int nScore, float flTimePlayed ) = 0; |
||||
|
||||
// The server failed to respond to the request for player details
|
||||
virtual void PlayersFailedToRespond() = 0; |
||||
|
||||
// The server has finished responding to the player details request
|
||||
virtual void PlayersRefreshComplete() = 0; |
||||
}; |
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Functions for match making services for clients to get to game lists and details
|
||||
//-----------------------------------------------------------------------------
|
||||
class IServersInfo |
||||
{ |
||||
public: |
||||
virtual void RequestInternetServerList( const char *gamedir, IServerListResponse *response ) = 0; |
||||
virtual void RequestLANServerList( const char *gamedir, IServerListResponse *response ) = 0; |
||||
virtual void StopRefresh() = 0; |
||||
|
||||
//virtual HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0;
|
||||
//virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0;
|
||||
|
||||
}; |
||||
#define SERVERLIST_INTERFACE_VERSION "ServerList001" |
||||
|
||||
extern IServersInfo *g_pServersInfo; |
||||
|
||||
#endif // ISERVERSINFO_H
|
Loading…
Reference in new issue