diff --git a/Status/gamedata/serverfps.games.txt b/Status/gamedata/serverfps.games.txt new file mode 100644 index 00000000..f5146772 --- /dev/null +++ b/Status/gamedata/serverfps.games.txt @@ -0,0 +1,45 @@ +"Games" +{ + "#default" + { + "Addresses" + { + "HostTimeFrame" + { + "windows" + { + "signature" "GetStatsString" + "read" "79" + // ALTERNATIVE 1: -4 + } + "linux" + { + "signature" "host_frametime" + } + "mac" + { + "signature" "host_frametime" + } + } + } + + "Signatures" + { + "GetStatsString" + { + "library" "engine" + "windows" "\x55\x8B\xEC\x83\xEC\x0C\xD9\xEE\x8D\x45\xFC\x56\x57\x50\x8D\x45\xF8" + /* 55 8B EC 83 EC 0C D9 EE 8D 45 FC 56 57 50 8D 45 F8 */ + /* ALTERNATIVE 1: 2B F0 D9 E8 8D 47 FF DE F1 56 83 EC 08 DD 1C 24 50 */ + } + + "host_frametime" + { + "library" "engine" + "linux" "@host_frametime" + "mac" "@host_frametime" + } + } + } +} + diff --git a/Status/scripting/Status_RevEmu.sp b/Status/scripting/Status_RevEmu.sp new file mode 100644 index 00000000..24880ac1 --- /dev/null +++ b/Status/scripting/Status_RevEmu.sp @@ -0,0 +1,212 @@ +#pragma semicolon 1 + +#include +#include +#include + +#tryinclude "serverfps.inc" + +#pragma newdecls required + +ConVar g_Cvar_HostIP; +ConVar g_Cvar_HostPort; +ConVar g_Cvar_HostName; +ConVar g_Cvar_HostTags; + +#if !defined _serverfps_included +int g_iTickRate; +#endif + +public Plugin myinfo = +{ + name = "Status Fixer", + author = "zaCade + BotoX + Obus", + description = "Fixes the \"status\" command", + version = "2.0", + url = "https://github.com/CSSZombieEscape/sm-plugins/tree/master/Status/" +}; + +public void OnPluginStart() +{ + g_Cvar_HostIP = FindConVar("hostip"); + g_Cvar_HostPort = FindConVar("hostport"); + g_Cvar_HostName = FindConVar("hostname"); + g_Cvar_HostTags = FindConVar("sv_tags"); + + AddCommandListener(Command_Status, "status"); +} + +public Action Command_Status(int client, const char[] command, int args) +{ + if(!client) + return Plugin_Continue; + + static char sServerName[128]; + static char sServerTags[128]; + static char sServerAdress[128]; + + int iServerIP = g_Cvar_HostIP.IntValue; + int iServerPort = g_Cvar_HostPort.IntValue; + + g_Cvar_HostName.GetString(sServerName, sizeof(sServerName)); + g_Cvar_HostTags.GetString(sServerTags, sizeof(sServerTags)); + + Format(sServerAdress, sizeof(sServerAdress), "%d.%d.%d.%d:%d", iServerIP >>> 24 & 255, iServerIP >>> 16 & 255, iServerIP >>> 8 & 255, iServerIP & 255, iServerPort); + + static char sMapName[128]; + GetCurrentMap(sMapName, sizeof(sMapName)); + + float fPosition[3]; + GetClientAbsOrigin(client, fPosition); + + float fClientDataIn = GetClientAvgData(client, NetFlow_Incoming); + float fClientDataOut = GetClientAvgData(client, NetFlow_Outgoing); + float fServerDataIn; + float fServerDataOut; + + GetServerNetStats(fServerDataIn, fServerDataOut); + + int iRealClients; + int iFakeClients; + int iTotalClients; + + for(int player = 1; player <= MaxClients; player++) + { + if(IsClientConnected(player)) + { + iTotalClients++; + + if(IsFakeClient(player)) + iFakeClients++; + else + iRealClients++; + } + } + +#if defined _serverfps_included + float fServerTickRate = 1.0 / GetTickInterval(); + float fServerFPS = GetServerFPS(); + + fServerFPS = fServerFPS <= fServerTickRate ? fServerFPS : fServerTickRate; +#else + int iServerTickRate = RoundToZero(1.0 / GetTickInterval()); + int iTickRate = g_iTickRate; + + iTickRate = iTickRate <= iServerTickRate ? iTickRate : iServerTickRate; +#endif + + PrintToConsole(client, "hostname: %s", + sServerName); + +#if defined _serverfps_included + PrintToConsole(client, "tickrate: %.2f/%.2f (%d%%)", + fServerFPS, fServerTickRate, RoundToNearest((fServerFPS / fServerTickRate) * 100)); +#else + PrintToConsole(client, "tickrate: %d/%d (%d%%)", + iTickRate, iServerTickRate, RoundToNearest((float(iTickRate) / float(iServerTickRate)) * 100)); +#endif + + PrintToConsole(client, "udp/ip : %s", + sServerAdress); + + PrintToConsole(client, "net I/O : %.2f/%.2f KiB/s (You: %.2f/%.2f KiB/s)", + fServerDataIn / 1024, fServerDataOut / 1024, fClientDataIn / 1024, fClientDataOut / 1024); + + PrintToConsole(client, "map : %s at: %.0f x, %.0f y, %.0f z", + sMapName, fPosition[0], fPosition[1], fPosition[2]); + + PrintToConsole(client, "tags : %s", + sServerTags); + + PrintToConsole(client, "edicts : %d/%d/%d (used/max/free)", + GetEntityCount(), GetMaxEntities(), GetMaxEntities() - GetEntityCount()); + + PrintToConsole(client, "players : %d %s | %d %s (%d/%d)", + iRealClients, Multiple(iRealClients) ? "humans" : "human", iFakeClients, Multiple(iFakeClients) ? "bots" : "bot", iTotalClients, MaxClients); + + PrintToConsole(client, "# %8s %40s %24s %12s %4s %4s %10s %16s %s", + "userid", "name", "uniqueid", "connected", "ping", "loss", "state", "addr", "type"); + + for(int player = 1; player <= MaxClients; player++) + { + if(!IsClientConnected(player)) + continue; + + static char sPlayerID[8]; + static char sPlayerName[MAX_NAME_LENGTH + 2]; + static char sPlayerAuth[24]; + char sPlayerTime[12]; + char sPlayerPing[4]; + char sPlayerLoss[4]; + static char sPlayerState[16]; + char sPlayerAddr[16]; + char sPlayerType[64]; + + FormatEx(sPlayerID, sizeof(sPlayerID), "%d", GetClientUserId(player)); + FormatEx(sPlayerName, sizeof(sPlayerName), "\"%N\"", player); + + if(!GetClientAuthId(player, AuthId_Steam2, sPlayerAuth, sizeof(sPlayerAuth))) + FormatEx(sPlayerAuth, sizeof(sPlayerAuth), "STEAM_ID_PENDING"); + + if(!IsFakeClient(player)) + { + int iHours = RoundToFloor((GetClientTime(player) / 3600)); + int iMinutes = RoundToFloor((GetClientTime(player) - (iHours * 3600)) / 60); + int iSeconds = RoundToFloor((GetClientTime(player) - (iHours * 3600)) - (iMinutes * 60)); + + if (iHours) + FormatEx(sPlayerTime, sizeof(sPlayerTime), "%d:%02d:%02d", iHours, iMinutes, iSeconds); + else + FormatEx(sPlayerTime, sizeof(sPlayerTime), "%d:%02d", iMinutes, iSeconds); + + FormatEx(sPlayerPing, sizeof(sPlayerPing), "%d", RoundFloat(GetClientLatency(player, NetFlow_Outgoing) * 800)); + FormatEx(sPlayerLoss, sizeof(sPlayerLoss), "%d", RoundFloat(GetClientAvgLoss(player, NetFlow_Outgoing) * 100)); + } + + if(IsClientInGame(player)) + FormatEx(sPlayerState, sizeof(sPlayerState), "active"); + else + FormatEx(sPlayerState, sizeof(sPlayerState), "spawning"); + + if(GetAdminFlag(GetUserAdmin(client), Admin_RCON)) + { + GetClientIP(player, sPlayerAddr, sizeof(sPlayerAddr)); + + if (IsFakeClient(player)) + FormatEx(sPlayerType, sizeof(sPlayerType), "FakeClient"); + else + RevEmu_GetPlayerType(player, sPlayerType, sizeof(sPlayerType)); + + PrintToConsole(client, "# %8s %40s %24s %12s %4s %4s %10s %16s %s", + sPlayerID, sPlayerName, sPlayerAuth, sPlayerTime, sPlayerPing, sPlayerLoss, sPlayerState, sPlayerAddr, sPlayerType); + } + else + PrintToConsole(client, "# %8s %40s %24s %12s %4s %4s %s", + sPlayerID, sPlayerName, sPlayerAuth, sPlayerTime, sPlayerPing, sPlayerLoss, sPlayerState); + } + + return Plugin_Handled; +} + +public void OnGameFrame() +{ +#if !defined _serverfps_included //Inaccurate fallback + static float fLastEngineTime; + static int iTicks; + float fCurEngineTime = GetEngineTime(); //GetEngineTime() will become less and less accurate as server uptime goes up! + + iTicks++; + + if (fCurEngineTime - fLastEngineTime >= 1.0) + { + g_iTickRate = iTicks; + iTicks = 0; + fLastEngineTime = fCurEngineTime; + } +#endif +} + +stock bool Multiple(int num) +{ + return (!num || num > 1); +} diff --git a/Status/scripting/include/serverfps.inc b/Status/scripting/include/serverfps.inc new file mode 100644 index 00000000..165b3656 --- /dev/null +++ b/Status/scripting/include/serverfps.inc @@ -0,0 +1,49 @@ +#if defined _serverfps_included + #endinput +#endif +#define _serverfps_included + +#include +#include + +stock float GetServerFPS() +{ + return 1.0 / view_as(LoadFromAddress(GetHostTimeFrame(), NumberType_Int32)); +} + +/* +* Internal Functions +*/ +stock Handle GetServerFPSConf() +{ + static Handle hGameConf = null; + + if (hGameConf == null) + { + hGameConf = LoadGameConfigFile("serverfps.games"); + + if (hGameConf == null) + { + SetFailState("Couldn't find \"serverfps.games\" configuration file"); + } + } + + return hGameConf; +} + +stock Address GetHostTimeFrame() +{ + static Address pHostTimeFrame = Address_Null; + + if (pHostTimeFrame == Address_Null) + { + pHostTimeFrame = GameConfGetAddress(GetServerFPSConf(), "HostTimeFrame"); + + if (pHostTimeFrame == Address_Null) + { + SetFailState("Failed to find time frame address"); + } + } + + return pHostTimeFrame; +}