WIP: initial masterserver client implementation

This commit is contained in:
nillerusr 2023-01-28 05:29:26 +03:00
parent 17ff01c7ab
commit 0df7838ee1
11 changed files with 703 additions and 18 deletions

View File

@ -16,6 +16,8 @@
// This is used, unless overridden in the registry
#define VALVE_MASTER_ADDRESS "207.173.177.10:27011"
#define HB_TIMEOUT 15
#define PORT_RCON 27015 // defualt RCON port, TCP
#define PORT_MASTER 27011 // Default master port, UDP
#define PORT_CLIENT 27005 // Default client port, UDP/TCP
@ -29,6 +31,8 @@
#endif // ENABLE_RPT
#define PORT_REPLAY 27040 // Default replay port
#define PORT_SERVERSINFO 27069 // Default matchmaking port
// out of band message id bytes
// M = master, S = server, C = client, A = any
@ -80,16 +84,17 @@
// 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 S2M_GETCHALLENGE 'w' // + dword challenge
#define S2M_HEARTBEAT 'y'
#define S2M_SHUTDOWN 'z' // Master peering message
#define M2S_CHALLENGE 'x' // + dword challenge
#define M2C_QUERY 'J' // request module from master
#define C2M_CLIENTQUERY '1' // New style server query
#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
#define C2S_INFOREQUEST 'v'
#define S2C_INFOREPLY 'K'
// SERVER TO CLIENT/ANY
@ -106,9 +111,6 @@
#define S2A_INFO_SRC 'I' // + Address, hostname, map, gamedir, gamedescription, active players, maxplayers, protocol
#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
@ -133,8 +135,6 @@
#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' //

View File

@ -37,6 +37,7 @@
#include "sv_plugin.h"
#include "sys_dll.h"
#include "host.h"
#include "master.h"
#if defined( REPLAY_ENABLED )
#include "replay_internal.h"
#include "replayserver.h"
@ -875,6 +876,8 @@ bool CBaseClientState::ProcessConnectionlessPacket( netpacket_t *packet )
Assert( packet );
master->ProcessConnectionlessPacket( packet );
bf_read &msg = packet->message; // handy shortcut
int c = msg.ReadByte();

View File

@ -56,6 +56,7 @@
#include "sv_ipratelimit.h"
#include "cl_steamauth.h"
#include "sv_filter.h"
#include "master.h"
#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
@ -663,6 +664,8 @@ bool CBaseServer::ValidInfoChallenge( netadr_t & adr, const char *nugget )
bool CBaseServer::ProcessConnectionlessPacket(netpacket_t * packet)
{
master->ProcessConnectionlessPacket( packet );
bf_read msg = packet->message; // handy shortcut
char c = msg.ReadChar();

View File

@ -40,6 +40,7 @@
#include "steam/steam_api.h"
#include "LoadScreenUpdate.h"
#include "datacache/idatacache.h"
#include "master.h"
#if !defined SWDS
#include "voice.h"
@ -1820,6 +1821,8 @@ void Host_ShutdownServer( void )
if ( !sv.IsActive() )
return;
master->ShutdownConnection();
Host_AllowQueuedMaterialSystem( false );
// clear structures
#if !defined( SWDS )
@ -4951,7 +4954,7 @@ void Host_Shutdown(void)
TRACESHUTDOWN( HLTV_Shutdown() );
TRACESHUTDOWN( g_Log.Shutdown() );
TRACESHUTDOWN( g_GameEventManager.Shutdown() );
TRACESHUTDOWN( sv.Shutdown() );

63
engine/master.h Normal file
View File

@ -0,0 +1,63 @@
//======== (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"
#define DEFAULT_MASTER_ADDRESS "185.192.97.130:27010"
//-----------------------------------------------------------------------------
// 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 SetMaster_f( void ) = 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

502
engine/masterserver.cpp Normal file
View File

@ -0,0 +1,502 @@
//======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"
extern ConVar sv_lan;
//-----------------------------------------------------------------------------
// 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 ProcessConnectionlessPacket( netpacket_t *packet );
void SetMaster_f( void );
void Heartbeat_f( void );
void RunFrame();
void RequestServersInfo();
// SeversInfo
void RequestInternetServerList( const char *gamedir, IServerListResponse *response );
void RequestLANServerList( const char *gamedir, IServerListResponse *response );
void AddServerAddresses( netadr_t **adr, int count );
private:
// List of known master servers
adrlist_t *m_pMasterAddresses;
bool m_bInitialized;
// If nomaster is true, the server will not send heartbeats to the master server
bool m_bNoMasters;
CUtlLinkedList<netadr_t> m_serverAddresses;
};
static CMaster s_MasterServer;
IMaster *master = (IMaster *)&s_MasterServer;
IServersInfo *g_pServersInfo = (IServersInfo*)&s_MasterServer;
#define HEARTBEAT_SECONDS 140.0
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CMaster::CMaster( void )
{
m_pMasterAddresses = NULL;
m_bNoMasters = false;
m_bInitialized = false;
Init();
}
CMaster::~CMaster( void )
{
}
void CMaster::RunFrame()
{
CheckHeartbeat();
}
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_serverAddresses.Count() > 0 )
m_serverAddresses.RemoveAll();
ip = msg.ReadLong();
port = msg.ReadShort();
while( ip != 0 && port != 0 )
{
netadr_t adr(ip, port);
m_serverAddresses.AddToHead(adr);
ip = msg.ReadLong();
port = msg.ReadShort();
}
RequestServersInfo();
break;
}
case C2S_INFOREQUEST:
{
bf_write p(string, sizeof(string));
p.WriteLong(CONNECTIONLESS_HEADER);
p.WriteByte(S2C_INFOREPLY);
p.WriteString(sv.GetName());
NET_SendPacket(NULL, NS_SERVER, packet->from, p.GetData(), p.GetNumBytesWritten());
break;
}
case S2C_INFOREPLY:
{
char hostname[1024];
msg.ReadString(hostname, sizeof(hostname));
break;
}
}
}
void CMaster::RequestServersInfo()
{
static ALIGN4 char string[256] ALIGN4_POST; // Buffer for sending heartbeat
bf_write msg( string, sizeof(string) );
FOR_EACH_LL( m_serverAddresses, i )
{
const netadr_t adr = m_serverAddresses[i];
msg.WriteLong( CONNECTIONLESS_HEADER );
msg.WriteByte( C2S_INFOREQUEST );
NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() );
}
}
//-----------------------------------------------------------------------------
// 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
// TODO(nillerusr): send engine version in this packet
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 %i 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;
// Convert to netadr_t
if ( NET_StringToAdr ( DEFAULT_MASTER_ADDRESS, &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::SetMaster_f (void)
{
}
//-----------------------------------------------------------------------------
// 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 SetMaster_f( void )
{
master->SetMaster_f();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void Heartbeat1_f( void )
{
master->Heartbeat_f();
}
static ConCommand setmaster("setmaster", SetMaster_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;
ALIGN4 char buf[256] ALIGN4_POST;
bf_write msg(buf, sizeof(buf));
msg.WriteByte( C2M_CLIENTQUERY );
msg.WriteString(gamedir);
// TODO(nillerusr): add switching between masters?
NET_SendPacket(NULL, NS_CLIENT, m_pMasterAddresses->adr, msg.GetData(), msg.GetNumBytesWritten() );
}
void CMaster::RequestLANServerList(const char *gamedir, IServerListResponse *response)
{
}
void CMaster::AddServerAddresses( netadr_t **adr, int count )
{
}
void Master_Request_f()
{
g_pServersInfo->RequestInternetServerList("cstrike", NULL);
}
ConCommand master_request( "master_request", Master_Request_f );

View File

@ -64,10 +64,15 @@ extern int NET_ReceiveStream( int nSock, char * buf, int len, int flags );
// We only need to checksum packets on the PC and only when we're actually sending them over the network.
static bool ShouldChecksumPackets()
{
// nillerusr: temporary solution for testing
return false;
#if 0
if ( !IsPC() )
return false;
return NET_IsMultiplayer();
#endif
}
bool CNetChan::IsLoopback() const

View File

@ -13,6 +13,7 @@
#include "net_ws_headers.h"
#include "net_ws_queued_packet_sender.h"
#include "fmtstr.h"
#include "master.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
@ -1644,7 +1645,7 @@ netpacket_t *NET_GetPacket (int sock, byte *scratch )
// Check loopback first
if ( !NET_GetLoopPacket( &inpacket ) )
{
if ( !NET_IsMultiplayer() )
if ( !NET_IsMultiplayer() && sock != NS_CLIENT )
{
return NULL;
}
@ -2351,7 +2352,7 @@ int NET_SendPacket ( INetChannel *chan, int sock, const netadr_t &to, const uns
Msg("UDP -> %s: sz=%i OOB '%c'\n", to.ToString(), length, data[4] );
}
if ( !NET_IsMultiplayer() || to.type == NA_LOOPBACK || ( to.IsLocalhost() && !net_usesocketsforloopback.GetBool() ) )
if ( (!NET_IsMultiplayer() && sock != NS_CLIENT) || to.type == NA_LOOPBACK || ( to.IsLocalhost() && !net_usesocketsforloopback.GetBool() ) )
{
Assert( !pVoicePayload );
@ -2988,6 +2989,8 @@ void NET_RunFrame( double flRealtime )
#endif // SWDS
master->RunFrame();
#ifdef _X360
if ( net_logserver.GetInt() )
{
@ -3110,7 +3113,7 @@ void NET_ListenSocket( int sock, bool bListen )
NET_CloseSocket( netsock->hTCP, sock );
}
if ( !NET_IsMultiplayer() || net_notcp )
if ( (!NET_IsMultiplayer() && sock != NS_CLIENT) || net_notcp )
return;
if ( bListen )
@ -3296,6 +3299,11 @@ void NET_Init( bool bIsDedicated )
ipname.SetValue( ip ); // update the cvar right now, this will get overwritten by "stuffcmds" later
}
const int nProtocol = X360SecureNetwork() ? IPPROTO_VDP : IPPROTO_UDP;
// open client socket for masterserver
OpenSocketInternal( NS_CLIENT, clientport.GetInt(), PORT_SERVER, "client", nProtocol, true );
if ( bIsDedicated )
{
// set dedicated MP mode

View File

@ -1005,7 +1005,7 @@ void Heartbeat_f()
}
}
static ConCommand heartbeat( "heartbeat", Heartbeat_f, "Force heartbeat of master servers", 0 );
//static ConCommand heartbeat( "heartbeat", Heartbeat_f, "Force heartbeat of master servers", 0 );
//-----------------------------------------------------------------------------

View File

@ -329,7 +329,8 @@ def build(bld):
'vgui_texturebudgetpanel.cpp',
'vgui_vprofgraphpanel.cpp',
'vgui_vprofpanel.cpp',
'toolframework.cpp'
'toolframework.cpp',
'masterserver.cpp',
]
if bld.env.DEST_OS != 'win32':

View File

@ -0,0 +1,97 @@
//====== 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 ServerResponse
{
ServerResponded = 0,
ServerFailedToRespond,
NoServersListedOnMasterServer,
};
class newgameserver_t
{
public:
newgameserver_t() = default;
const char* GetName() const;
void SetName( const char *pName );
netadr_t m_NetAdr; ///< IP/Query Port/Connection Port for this server
int m_nPing; ///< current ping time in milliseconds
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_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
private:
/// 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;
};
//-----------------------------------------------------------------------------
// 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 HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0;
//virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0;
};
#define SERVERLIST_INTERFACE_VERSION "ServerList001"
#endif // ISERVERSINFO_H