This commit is contained in:
speedvoltage 2025-04-03 17:21:49 -07:00 committed by GitHub
commit c55a06dbe9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 4033 additions and 36 deletions

View file

@ -0,0 +1,7 @@
"Admins"
{
"[U:1:00000000]"
{
"flags" "z"
}
}

View file

@ -35,6 +35,7 @@
#include "datacache/imdlcache.h"
#include "basemultiplayerplayer.h"
#include "voice_gamemgr.h"
#include "tier0/icommandline.h"
#ifdef TF_DLL
#include "tf_player.h"
@ -249,6 +250,48 @@ void Host_Say( edict_t *pEdict, const CCommand &args, bool teamonly )
bSenderDead = false;
}
if ( !CommandLine()->CheckParm( "-noadmin" ) )
{
if ( Q_strncmp( p, "/kick", strlen( "/kick" ) ) == 0 ||
Q_strncmp( p, "/ban", strlen( "/ban" ) ) == 0 ||
Q_strncmp( p, "/addban", strlen( "/addban" ) ) == 0 ||
Q_strncmp( p, "/unban", strlen( "/unban" ) ) == 0 ||
Q_strncmp( p, "/slap", strlen( "/slap" ) ) == 0 ||
Q_strncmp( p, "/slay", strlen( "/slay" ) ) == 0 ||
Q_strncmp( p, "/noclip", strlen( "/noclip" ) ) == 0 ||
Q_strncmp( p, "/team", strlen( "/team" ) ) == 0 ||
Q_strncmp( p, "/gag", strlen( "/gag" ) ) == 0 ||
Q_strncmp( p, "/ungag", strlen( "/ungag" ) ) == 0 ||
Q_strncmp( p, "/mute", strlen( "/mute" ) ) == 0 ||
Q_strncmp( p, "/unmute", strlen( "/unmute" ) ) == 0 ||
Q_strncmp( p, "/bring", strlen( "/bring" ) ) == 0 ||
Q_strncmp( p, "/goto", strlen( "/goto" ) ) == 0 ||
Q_strncmp( p, "/map", strlen( "/map" ) ) == 0 ||
Q_strncmp( p, "/cvar", strlen( "/cvar" ) ) == 0 ||
Q_strncmp( p, "/exec", strlen( "/exec" ) ) == 0 ||
Q_strncmp( p, "/rcon", strlen( "/rcon" ) ) == 0 ||
Q_strncmp( p, "/say", strlen( "/say" ) ) == 0 ||
Q_strncmp( p, "/csay", strlen( "/csay" ) ) == 0 ||
Q_strncmp( p, "/psay", strlen( "/psay" ) ) == 0 ||
Q_strncmp( p, "/chat", strlen( "/chat" ) ) == 0 )
{
if ( args.ArgC() > 1 )
{
return;
}
}
if ( FStrEq( p, "/sa" ) ||
FStrEq( p, "/credits" ) ||
FStrEq( p, "/version" ) ||
FStrEq( p, "/help" ) ||
FStrEq( p, "/reloadadmins" ) )
return;
}
if ( pPlayer && pPlayer->IsGagged() )
return;
const char *pszFormat = NULL;
const char *pszPrefix = NULL;
const char *pszLocation = NULL;

View file

@ -85,6 +85,7 @@
#include "particle_parse.h"
#ifndef NO_STEAM
#include "steam/steam_gameserver.h"
#include "hl2mp/admin/hl2mp_serveradmin.h"
#endif
#include "tier3/tier3.h"
#include "serverbenchmark_base.h"
@ -967,6 +968,8 @@ bool CServerGameDLL::LevelInit( const char *pMapName, char const *pMapEntities,
pItemSchema->BInitFromDelayedBuffer();
}
#endif // USES_ECON_ITEMS
CHL2MP_Admin::InitAdminSystem();
ResetWindspeed();
UpdateChapterRestrictions( pMapName );

View file

@ -10,7 +10,7 @@
#pragma once
#endif
#define VERSION "1.0"
extern Vector g_vecAttackDir;
extern int g_iSkillLevel;
extern bool g_fGameOver;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
#ifndef HL2MP_SERVERADMIN_H
#define HL2MP_SERVERADMIN_H
#include "cbase.h"
// admin permission flags
#define ADMIN_UNDEFINED 'a'
#define ADMIN_GENERIC 'b' // minimum flag required for admin detection
#define ADMIN_KICK 'c' // kicking function
#define ADMIN_BAN 'd' // banning function -- DOES NOT INCLUDE ADDBAN, WHICH NEEDS RCON
#define ADMIN_UNBAN 'e' // to remove a ban in banned_user.cfg -- only is useful for permanent bans
#define ADMIN_SLAY 'f' // to slap and slay
#define ADMIN_CHANGEMAP 'g' // to change levels
#define ADMIN_CVAR 'h' // for sa cvar, accessing any cvar, even those behind FCVAR_DEVELOPMENTONLY
#define ADMIN_CONFIG 'i' // for executing cfg files
#define ADMIN_CHAT 'j' // for chat specific commands (say, gag, mute, etc.)
// UNUSED: ADMIN_VOTE is now unused because cl_showpluginmessages is defaulted to 0 and on some Linux distros,
// top menus outright don't work despite no errors and all the calls suggesting it should pop up on the client's screen.
// A rework of the top menus API will be done to test a potential fix. For now, this permission is unused.
#define ADMIN_VOTE 'k' // for votes (votekick, voteban, votemute, votespec, etc.)
#define ADMIN_PASSWORD 'l' // for sv_password. Combines with CVAR permission to allow `sa cvar sv_password` usage.
#define ADMIN_RCON 'm' // bypasses the need for an rcon password,
// use in-game for issuing commands
// as if they were typed in the server console
#define ADMIN_CHEATS 'n' // primarily for sv_cheats
#define ADMIN_ROOT 'z' // all permissions, immunity for kick, ban, gag & mute
enum SpecialTarget
{
TARGET_INVALID = -1,
TARGET_ALL,
TARGET_BLUE,
TARGET_RED,
TARGET_ALL_BUT_ME,
TARGET_ME,
TARGET_ALIVE,
TARGET_DEAD,
TARGET_BOTS,
TARGET_HUMANS
};
enum AdminReplySource
{
ADMIN_REPLY_SERVER_CONSOLE,
ADMIN_REPLY_CONSOLE,
ADMIN_REPLY_CHAT
};
extern CUtlMap<const char *, SpecialTarget> g_SpecialTargets;
extern CUtlMap<int, bool> g_PlayerCommandSourceMap;
struct AdminData_t
{
CUtlString flags; // Permissions flags string
AdminData_t() {}
AdminData_t( const char *szFlags ) : flags( szFlags ) {}
};
class CHL2MP_Admin
{
public:
CHL2MP_Admin();
~CHL2MP_Admin();
void Initialize( const char *steamID, const char *permissions );
bool HasPermission( char flag ) const;
const char *GetSteamID() const { return m_steamID; }
static void InitAdminSystem();
static CUtlMap<CUtlString, AdminData_t> &GetAdminMap();
static bool ParseAdminFile( const char *filename, CUtlMap<CUtlString, AdminData_t> &outAdminMap );
static void SaveAdminCache(); // For persisting updated list if needed
static bool IsPlayerAdmin( CBasePlayer *pPlayer, const char *requiredFlags );
static void ClearAllAdmins();
static CHL2MP_Admin *GetAdmin( const char *steamID );
// static void RegisterAdminCommands();
static void AddAdmin( const char *steamID, const char *permissions );
bool FindSpecialTargetGroup( const char *targetSpecifier );
void ResetSpecialTargetGroup();
static void CheckChatText( char *p, int bufsize );
static void LogAction( CBasePlayer *pAdmin, CBasePlayer *pTarget, const char *action, const char *details = "", const char *groupTarget = nullptr );
bool IsAllPlayers() const { return bAll; }
bool IsAllBluePlayers() const { return bBlue; }
bool IsAllRedPlayers() const { return bRed; }
bool IsAllButMePlayers() const { return bAllButMe; }
bool IsMe() const { return bMe; }
bool IsAllAlivePlayers() const { return bAlive; }
bool IsAllDeadPlayers() const { return bDead; }
bool IsAllBotsPlayers() const { return bBots; }
bool IsAllHumanPlayers() const { return bHumans; }
void TargetAllPlayers( bool enabled ) { bAll = enabled; }
void TargetAllBlue( bool enabled ) { bBlue = enabled; }
void TargetAllRed( bool enabled ) { bRed = enabled; }
void TargetAllButMe( bool enabled ) { bAllButMe = enabled; }
void TargetMe( bool enabled ) { bMe = enabled; }
void TargetAllPlayersAlive( bool enabled ) { bAlive = enabled; }
void TargetAllPlayersDead( bool enabled ) { bDead = enabled; }
void TargetAllBots( bool enabled ) { bBots = enabled; }
void TargetAllHumans( bool enabled ) { bHumans = enabled; }
private:
const char *m_steamID;
const char *m_permissions;
// special group target
bool bAll;
bool bBlue;
bool bRed;
bool bAllButMe;
bool bMe;
bool bAlive;
bool bDead;
bool bBots;
bool bHumans;
static bool bIsListenServerMsg;
};
extern CUtlVector<CHL2MP_Admin *> g_AdminList;
extern CHL2MP_Admin *g_pHL2MPAdmin;
inline CHL2MP_Admin *HL2MPAdmin()
{
return static_cast< CHL2MP_Admin * >( g_pHL2MPAdmin );
}
#endif // HL2MP_SERVERADMIN_H

View file

@ -22,6 +22,7 @@
#include "gamestats.h"
#include "ammodef.h"
#include "NextBot.h"
#include "admin/hl2mp_serveradmin.h"
#include "engine/IEngineSound.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
@ -1546,6 +1547,7 @@ void CHL2MP_Player::SetReady( bool bReady )
void CHL2MP_Player::CheckChatText( char *p, int bufsize )
{
CHL2MP_Admin::CheckChatText( p, bufsize );
//Look for escape sequences and replace
char *buf = new char[bufsize];

View file

@ -8841,6 +8841,13 @@ CBaseEntity *CBasePlayer::DoubleCheckUseNPC( CBaseEntity *pNPC, const Vector &ve
return pNPC;
}
// because IsBot() && IsFakeClient() just don't seem to work with HL2MP bots??
bool CBasePlayer::IsPlayerBot() const
{
const char *steamID = engine->GetPlayerNetworkIDString( edict() );
return ( steamID && Q_strcmp( steamID, "BOT" ) == 0 );
}
bool CBasePlayer::IsBot() const
{
@ -9679,3 +9686,19 @@ void* SendProxy_SendNonLocalDataTable( const SendProp *pProp, const void *pStruc
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_SendNonLocalDataTable );
// Peter: This is here for the server admin stuff.
// We are doing this because using a chat command goes through `sa`, then calls `sa slap`,
// but between those two calls, the get reply source is reset so it ends up printing
// to console rather than to chat when the command is typed in the chat.
// Therefore this timer below gives enough time for the chat text to be printed.
// There may be a better way, but this will do it for now.
void CBasePlayer::SetChatCommandResetThink()
{
SetContextThink( &CBasePlayer::ChatCommandResetThink, gpGlobals->curtime + 0.05f, "ChatCommandResetThink" );
}
void CBasePlayer::ChatCommandResetThink()
{
SetLastCommandWasFromChat( false );
}

View file

@ -746,6 +746,7 @@ public:
void SetLastUserCommand( const CUserCmd &cmd );
const CUserCmd *GetLastUserCommand( void );
bool IsPlayerBot() const;
virtual bool IsBot() const; // IMPORTANT: This returns true for ANY type of bot. If your game uses different, incompatible types of bots check your specific bot type before casting
virtual bool IsBotOfType( int botType ) const; // return true if this player is a bot of the specific type (zero is invalid)
virtual int GetBotType( void ) const; // return a unique int representing the type of bot instance this is
@ -823,6 +824,15 @@ public:
}
}
bool IsGagged() const { return m_bIsGagged; }
void SetGagged( bool gagged ) { m_bIsGagged = gagged; }
bool IsMuted() const { return m_bIsMuted; }
void SetMuted( bool muted ) { m_bIsMuted = muted; }
void SetLastCommandWasFromChat( bool enabled ) { m_bLastCommandWasFromChat = enabled; }
bool WasCommandUsedFromChat() { return m_bLastCommandWasFromChat; }
void SetChatCommandResetThink();
void ChatCommandResetThink();
private:
// How much of a movement time buffer can we process from this user?
int m_nMovementTicksForUserCmdProcessingRemaining;
@ -839,6 +849,11 @@ private:
int DetermineSimulationTicks( void );
void AdjustPlayerTimeBase( int simulation_ticks );
// Gagged and muted
bool m_bIsGagged;
bool m_bIsMuted;
bool m_bLastCommandWasFromChat;
public:
// How long since this player last interacted with something the game considers an objective/target/goal

View file

@ -388,6 +388,12 @@ $Project "Server (HL2MP)"
}
}
$Folder "Admin"
{
$File "hl2mp\admin\hl2mp_serveradmin.cpp"
$File "hl2mp\admin\hl2mp_serveradmin.h"
}
$Folder "Weapons"
{
$File "hl2mp\grenade_satchel.cpp"

View file

@ -130,7 +130,7 @@ static const char *s_PreserveEnts[] =
"", // END Marker
};
bool bAdminMapChange = false;
#ifdef CLIENT_DLL
void RecvProxy_HL2MPRules( const RecvProp *pProp, void **pOut, void *pData, int objectID )
@ -204,6 +204,11 @@ CHL2MPRules::CHL2MPRules()
m_bAwaitingReadyRestart = false;
m_bChangelevelDone = false;
bAdminMapChange = false;
bMapChangeOnGoing = false;
bMapChange = false;
m_flMapChangeTime = 0.0f;
Q_strncpy( m_scheduledMapName, "", sizeof( m_scheduledMapName ) );
#endif
}
@ -294,6 +299,8 @@ void CHL2MPRules::Think( void )
CGameRules::Think();
HandleMapChange();
if ( g_fGameOver ) // someone else quit the game already
{
// check to see if we should change levels now
@ -351,6 +358,7 @@ void CHL2MPRules::Think( void )
{
CheckAllPlayersReady();
CheckRestartGame();
m_tmNextPeriodicThink = gpGlobals->curtime + 1.0;
}
@ -373,6 +381,28 @@ void CHL2MPRules::Think( void )
#endif
}
#ifndef CLIENT_DLL
void CHL2MPRules::HandleMapChange()
{
if ( IsMapChangeOnGoing() && IsMapChange() )
{
SetMapChange( false );
m_flMapChangeTime = gpGlobals->curtime + 5.0f;
}
if ( IsMapChangeOnGoing() && gpGlobals->curtime > m_flMapChangeTime )
{
SetMapChange( false );
SetMapChangeOnGoing( false );
if ( Q_strlen( m_scheduledMapName ) > 0 )
{
engine->ServerCommand( UTIL_VarArgs( "changelevel %s\n", m_scheduledMapName ) );
}
}
}
#endif
void CHL2MPRules::GoToIntermission( void )
{
#ifndef CLIENT_DLL

View file

@ -152,7 +152,16 @@ public:
void CheckAllPlayersReady( void );
virtual bool IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer );
#ifndef CLIENT_DLL
void SetMapChangeOnGoing( bool enabled ) { bMapChangeOnGoing = enabled; }
void SetMapChange( bool enabled ) { bMapChange = enabled; }
bool IsMapChangeOnGoing() const { return bMapChangeOnGoing; }
bool IsMapChange() const { return bMapChange; }
void SetScheduledMapName( const char *mapName ) { Q_strncpy( m_scheduledMapName, mapName, sizeof( m_scheduledMapName ) ); }
void HandleMapChange();
#endif
private:
CNetworkVar( bool, m_bTeamPlayEnabled );
@ -166,6 +175,11 @@ private:
#ifndef CLIENT_DLL
bool m_bChangelevelDone;
bool bMapChangeOnGoing;
bool bMapChange;
float m_flMapChangeTime;
char m_scheduledMapName[ 64 ]; // The map name to change to
#endif
};

View file

@ -203,71 +203,79 @@ void CVoiceGameMgr::UpdateMasks()
bool bAllTalk = !!sv_alltalk.GetInt();
for(int iClient=0; iClient < m_nMaxPlayers; iClient++)
for ( int iClient = 0; iClient < m_nMaxPlayers; iClient++ )
{
CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1);
if(!pEnt || !pEnt->IsPlayer())
CBaseEntity *pEnt = UTIL_PlayerByIndex( iClient + 1 );
if ( !pEnt || !pEnt->IsPlayer() )
continue;
CBasePlayer *pPlayer = (CBasePlayer*)pEnt;
CBasePlayer *pPlayer = ( CBasePlayer * ) pEnt;
CSingleUserRecipientFilter user( pPlayer );
// Request the state of their "VModEnable" cvar.
if(g_bWantModEnable[iClient])
if ( g_bWantModEnable[ iClient ] )
{
UserMessageBegin( user, "RequestState" );
MessageEnd();
// Since this is reliable, only send it once
g_bWantModEnable[iClient] = false;
g_bWantModEnable[ iClient ] = false;
}
CPlayerBitVec gameRulesMask;
CPlayerBitVec ProximityMask;
bool bProximity = false;
if( g_PlayerModEnable[iClient] )
bool bProximity = false;
if ( g_PlayerModEnable[ iClient ] )
{
// Build a mask of who they can hear based on the game rules.
for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++)
for ( int iOtherClient = 0; iOtherClient < m_nMaxPlayers; iOtherClient++ )
{
CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1);
if(pEnt && pEnt->IsPlayer() &&
(bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt, bProximity )) )
CBaseEntity *pOtherEnt = UTIL_PlayerByIndex( iOtherClient + 1 );
if ( pOtherEnt && pOtherEnt->IsPlayer() )
{
gameRulesMask[iOtherClient] = true;
ProximityMask[iOtherClient] = bProximity;
CBasePlayer *pOtherPlayer = ( CBasePlayer * ) pOtherEnt;
if ( !pOtherPlayer->IsMuted() )
{
if ( bAllTalk || m_pHelper->CanPlayerHearPlayer( pPlayer, pOtherPlayer, bProximity ) )
{
gameRulesMask[ iOtherClient ] = true;
ProximityMask[ iOtherClient ] = bProximity;
}
}
else
{
g_BanMasks[ iClient ][ iOtherClient ] = true;
}
}
}
}
// If this is different from what the client has, send an update.
if(gameRulesMask != g_SentGameRulesMasks[iClient] ||
g_BanMasks[iClient] != g_SentBanMasks[iClient])
// If this is different from what the client has, send an update.
if ( gameRulesMask != g_SentGameRulesMasks[ iClient ] ||
g_BanMasks[ iClient ] != g_SentBanMasks[ iClient ] )
{
g_SentGameRulesMasks[iClient] = gameRulesMask;
g_SentBanMasks[iClient] = g_BanMasks[iClient];
g_SentGameRulesMasks[ iClient ] = gameRulesMask;
g_SentBanMasks[ iClient ] = g_BanMasks[ iClient ];
UserMessageBegin( user, "VoiceMask" );
int dw;
for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++)
{
WRITE_LONG(gameRulesMask.GetDWord(dw));
WRITE_LONG(g_BanMasks[iClient].GetDWord(dw));
}
WRITE_BYTE( !!g_PlayerModEnable[iClient] );
for ( int dw = 0; dw < VOICE_MAX_PLAYERS_DW; dw++ )
{
WRITE_LONG( gameRulesMask.GetDWord( dw ) );
WRITE_LONG( g_BanMasks[ iClient ].GetDWord( dw ) );
}
WRITE_BYTE( !!g_PlayerModEnable[ iClient ] );
MessageEnd();
}
// Tell the engine.
for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++)
// Tell the engine who can hear whom.
for ( int iOtherClient = 0; iOtherClient < m_nMaxPlayers; iOtherClient++ )
{
bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient];
g_pVoiceServer->SetClientListening( iClient+1, iOtherClient+1, bCanHear );
bool bCanHear = gameRulesMask[ iOtherClient ] && !g_BanMasks[ iClient ][ iOtherClient ];
g_pVoiceServer->SetClientListening( iClient + 1, iOtherClient + 1, bCanHear );
if ( bCanHear )
{
g_pVoiceServer->SetClientProximity( iClient+1, iOtherClient+1, !!ProximityMask[iOtherClient] );
g_pVoiceServer->SetClientProximity( iClient + 1, iOtherClient + 1, !!ProximityMask[ iOtherClient ] );
}
}
}