mirror of
https://github.com/YGGverse/xash3d-fwgs.git
synced 2025-01-29 16:24:16 +00:00
server: implement correct answers to TSourceEngineQuery server queries
* count bots as clients as in goldsrc * handle source-style packets after xash's built-in packets to not interfere with them
This commit is contained in:
parent
58df771c9e
commit
d9ef1d4608
@ -701,4 +701,9 @@ void SV_SetLightStyle( int style, const char* s, float f );
|
||||
const char *SV_GetLightStyle( int style );
|
||||
int SV_LightForEntity( edict_t *pEdict );
|
||||
|
||||
//
|
||||
// sv_query.c
|
||||
//
|
||||
qboolean SV_SourceQuery_HandleConnnectionlessPacket( const char *c, netadr_t from );
|
||||
|
||||
#endif//SERVER_H
|
||||
|
@ -3062,64 +3062,6 @@ void SV_ExecuteClientCommand( sv_client_t *cl, const char *s )
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_TSourceEngineQuery
|
||||
==================
|
||||
*/
|
||||
void SV_TSourceEngineQuery( netadr_t from )
|
||||
{
|
||||
// A2S_INFO
|
||||
char answer[1024] = "";
|
||||
int count, bots;
|
||||
int index;
|
||||
sizebuf_t buf;
|
||||
|
||||
SV_GetPlayerCount( &count, &bots );
|
||||
|
||||
MSG_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer ));
|
||||
|
||||
MSG_WriteLong( &buf, -1 ); // Mark as connectionless
|
||||
MSG_WriteByte( &buf, 'm' );
|
||||
MSG_WriteString( &buf, NET_AdrToString( net_local ));
|
||||
MSG_WriteString( &buf, hostname.string );
|
||||
MSG_WriteString( &buf, sv.name );
|
||||
MSG_WriteString( &buf, GI->gamefolder );
|
||||
MSG_WriteString( &buf, GI->title );
|
||||
MSG_WriteByte( &buf, count );
|
||||
MSG_WriteByte( &buf, svs.maxclients );
|
||||
MSG_WriteByte( &buf, PROTOCOL_VERSION );
|
||||
MSG_WriteByte( &buf, Host_IsDedicated() ? 'D' : 'L' );
|
||||
#if defined(_WIN32)
|
||||
MSG_WriteByte( &buf, 'W' );
|
||||
#else
|
||||
MSG_WriteByte( &buf, 'L' );
|
||||
#endif
|
||||
if( Q_stricmp( GI->gamefolder, "valve" ))
|
||||
{
|
||||
MSG_WriteByte( &buf, 1 ); // mod
|
||||
MSG_WriteString( &buf, GI->game_url );
|
||||
MSG_WriteString( &buf, GI->update_url );
|
||||
MSG_WriteByte( &buf, 0 );
|
||||
MSG_WriteLong( &buf, (int)GI->version );
|
||||
MSG_WriteLong( &buf, GI->size );
|
||||
|
||||
if( GI->gamemode == 2 )
|
||||
MSG_WriteByte( &buf, 1 ); // multiplayer_only
|
||||
else MSG_WriteByte( &buf, 0 );
|
||||
|
||||
if( Q_strstr( GI->game_dll, "hl." ))
|
||||
MSG_WriteByte( &buf, 0 ); // Half-Life DLL
|
||||
else MSG_WriteByte( &buf, 1 ); // Own DLL
|
||||
}
|
||||
else MSG_WriteByte( &buf, 0 ); // Half-Life
|
||||
|
||||
MSG_WriteByte( &buf, GI->secure ); // unsecure
|
||||
MSG_WriteByte( &buf, bots );
|
||||
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ), from );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_ConnectionlessPacket
|
||||
@ -3159,8 +3101,8 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||
else if( !Q_strcmp( pcmd, "rcon" )) SV_RemoteCommand( from, msg );
|
||||
else if( !Q_strcmp( pcmd, "netinfo" )) SV_BuildNetAnswer( from );
|
||||
else if( !Q_strcmp( pcmd, "s" )) SV_AddToMaster( from, msg );
|
||||
else if( !Q_strcmp( pcmd, "T" "Source" )) SV_TSourceEngineQuery( from );
|
||||
else if( !Q_strcmp( pcmd, "i" )) NET_SendPacket( NS_SERVER, 5, "\xFF\xFF\xFF\xFFj", from ); // A2A_PING
|
||||
else if( SV_SourceQuery_HandleConnnectionlessPacket( pcmd, from ) ) return;
|
||||
else if( !Q_strcmp( pcmd, "c" ) && sv_nat.value && NET_IsMasterAdr( from ))
|
||||
{
|
||||
netadr_t to;
|
||||
|
203
engine/server/sv_query.c
Normal file
203
engine/server/sv_query.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
sv_query.c - Source-engine like server querying
|
||||
Copyright (C) 2023 jeefo
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "server.h"
|
||||
|
||||
#define SOURCE_QUERY_INFO 'T'
|
||||
#define SOURCE_QUERY_DETAILS 'I'
|
||||
|
||||
#define SOURCE_QUERY_RULES 'V'
|
||||
#define SOURCE_QUERY_RULES_RESPONSE 'E'
|
||||
|
||||
#define SOURCE_QUERY_PLAYERS 'U'
|
||||
#define SOURCE_QUERY_PLAYERS_RESPONSE 'D'
|
||||
|
||||
#define SOURCE_QUERY_CONNECTIONLESS -1
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_SourceQuery_Details
|
||||
==================
|
||||
*/
|
||||
void SV_SourceQuery_Details( netadr_t from )
|
||||
{
|
||||
sizebuf_t buf;
|
||||
char answer[2048] = "";
|
||||
char version[128] = "";
|
||||
|
||||
int i, bot_count = 0, client_count = 0;
|
||||
int is_private = 0;
|
||||
|
||||
if ( svs.clients )
|
||||
{
|
||||
for ( i = 0; i < svs.maxclients; i++ )
|
||||
{
|
||||
if ( svs.clients[i].state >= cs_connected )
|
||||
{
|
||||
if ( svs.clients[i].edict->v.flags & FL_FAKECLIENT )
|
||||
bot_count++;
|
||||
|
||||
client_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
is_private = ( sv_password.string[0] && ( Q_stricmp( sv_password.string, "none" ) || !Q_strlen( sv_password.string ) ) ? 1 : 0 );
|
||||
|
||||
MSG_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer ));
|
||||
|
||||
MSG_WriteLong( &buf, SOURCE_QUERY_CONNECTIONLESS );
|
||||
MSG_WriteByte( &buf, SOURCE_QUERY_DETAILS );
|
||||
MSG_WriteByte( &buf, PROTOCOL_VERSION );
|
||||
|
||||
MSG_WriteString( &buf, hostname.string );
|
||||
MSG_WriteString( &buf, sv.name );
|
||||
MSG_WriteString( &buf, GI->gamefolder );
|
||||
MSG_WriteString( &buf, svgame.dllFuncs.pfnGetGameDescription( ) );
|
||||
|
||||
MSG_WriteShort( &buf, 0 );
|
||||
MSG_WriteByte( &buf, client_count );
|
||||
MSG_WriteByte( &buf, svs.maxclients );
|
||||
MSG_WriteByte( &buf, bot_count );
|
||||
|
||||
MSG_WriteByte( &buf, Host_IsDedicated( ) ? 'd' : 'l' );
|
||||
#if defined( _WIN32 )
|
||||
MSG_WriteByte( &buf, 'w' );
|
||||
#elif defined( __APPLE__ )
|
||||
MSG_WriteByte( &buf, 'm' );
|
||||
#else
|
||||
MSG_WriteByte( &buf, 'l' );
|
||||
#endif
|
||||
MSG_WriteByte( &buf, is_private );
|
||||
MSG_WriteByte( &buf, GI->secure );
|
||||
MSG_WriteString( &buf, XASH_VERSION );
|
||||
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ), from );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_SourceQuery_Rules
|
||||
==================
|
||||
*/
|
||||
void SV_SourceQuery_Rules( netadr_t from )
|
||||
{
|
||||
sizebuf_t buf;
|
||||
char answer[1024 * 8] = "";
|
||||
|
||||
cvar_t *cvar;
|
||||
int cvar_count = 0;
|
||||
|
||||
for ( cvar = Cvar_GetList( ); cvar; cvar = cvar->next )
|
||||
{
|
||||
if ( cvar->flags & FCVAR_SERVER )
|
||||
cvar_count++;
|
||||
}
|
||||
if ( cvar_count <= 0 )
|
||||
return;
|
||||
|
||||
MSG_Init( &buf, "TSourceEngineQueryRules", answer, sizeof( answer ) );
|
||||
|
||||
MSG_WriteLong( &buf, SOURCE_QUERY_CONNECTIONLESS );
|
||||
MSG_WriteByte( &buf, SOURCE_QUERY_RULES_RESPONSE );
|
||||
MSG_WriteShort( &buf, cvar_count );
|
||||
|
||||
for ( cvar = Cvar_GetList( ); cvar; cvar = cvar->next )
|
||||
{
|
||||
if ( !( cvar->flags & FCVAR_SERVER ) )
|
||||
continue;
|
||||
|
||||
MSG_WriteString( &buf, cvar->name );
|
||||
|
||||
if ( cvar->flags & FCVAR_PROTECTED )
|
||||
MSG_WriteString( &buf, ( Q_strlen( cvar->string ) > 0 && Q_stricmp( cvar->string, "none" ) ) ? "1" : "0" );
|
||||
else
|
||||
MSG_WriteString( &buf, cvar->string );
|
||||
}
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ), from );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_SourceQuery_Players
|
||||
==================
|
||||
*/
|
||||
void SV_SourceQuery_Players( netadr_t from )
|
||||
{
|
||||
sizebuf_t buf;
|
||||
char answer[1024 * 8] = "";
|
||||
|
||||
int i, client_count = 0;
|
||||
|
||||
if ( svs.clients )
|
||||
{
|
||||
for ( i = 0; i < svs.maxclients; i++ )
|
||||
{
|
||||
if ( svs.clients[i].state >= cs_connected )
|
||||
client_count++;
|
||||
}
|
||||
}
|
||||
if ( client_count <= 0 )
|
||||
return;
|
||||
|
||||
MSG_Init( &buf, "TSourceEngineQueryPlayers", answer, sizeof( answer ) );
|
||||
|
||||
MSG_WriteLong( &buf, SOURCE_QUERY_CONNECTIONLESS );
|
||||
MSG_WriteByte( &buf, SOURCE_QUERY_PLAYERS_RESPONSE );
|
||||
MSG_WriteByte( &buf, client_count );
|
||||
|
||||
for ( i = 0; i < svs.maxclients; i++ )
|
||||
{
|
||||
sv_client_t *cl = &svs.clients[i];
|
||||
|
||||
if ( cl->state < cs_connected )
|
||||
continue;
|
||||
|
||||
MSG_WriteByte( &buf, i );
|
||||
MSG_WriteString( &buf, cl->name );
|
||||
MSG_WriteLong( &buf, cl->edict->v.frags );
|
||||
MSG_WriteFloat( &buf, ( cl->edict->v.flags & FL_FAKECLIENT ) ? -1.0 : ( host.realtime - cl->connecttime ) );
|
||||
}
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ), from );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_SourceQuery_HandleConnnectionlessPacket
|
||||
==================
|
||||
*/
|
||||
qboolean SV_SourceQuery_HandleConnnectionlessPacket( const char *c, netadr_t from )
|
||||
{
|
||||
int request = c[0];
|
||||
|
||||
switch ( request )
|
||||
{
|
||||
case SOURCE_QUERY_INFO:
|
||||
SV_SourceQuery_Details( from );
|
||||
return true;
|
||||
|
||||
case SOURCE_QUERY_RULES:
|
||||
SV_SourceQuery_Rules( from );
|
||||
return true;
|
||||
|
||||
case SOURCE_QUERY_PLAYERS:
|
||||
SV_SourceQuery_Players( from );
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user