/*
* CSB Playtime Tracker
* Copyright (C) 2026 counter-strike-boost.com
*
* Accumulates connected seconds per SteamID in nVault (flushed every minute and
* on disconnect), prints total hours with say /time and a say /toptime ladder,
* and exposes a native csb_get_playtime(id) that the VIP / rewards plugins can
* read to gate perks by hours played.
*
* 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. It 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 for details.
*/
#include
#include
#include
new const PLUGIN[] = "CSB Playtime Tracker"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
#define NO_VAULT (-1)
new g_iVault = NO_VAULT
new g_iTotal[33] /* total accumulated seconds, loaded from the vault */
new g_iSince[33] /* systime of the last flush / connect */
new g_szAuth[33][35]
new g_szName[33][32]
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
register_clcmd("say /time", "cmdTime")
register_clcmd("say_team /time", "cmdTime")
register_clcmd("say /toptime", "cmdTopTime")
register_clcmd("say_team /toptime", "cmdTopTime")
set_task(60.0, "taskFlush", 0, _, _, "b")
}
public plugin_natives()
{
register_native("csb_get_playtime", "native_get_playtime")
}
public plugin_cfg()
{
g_iVault = nvault_open("csb_playtime")
if (g_iVault == NO_VAULT)
log_amx("[CSB Playtime] could not open nVault 'csb_playtime' - tracking disabled.")
}
public plugin_end()
{
new players[32], num
get_players(players, num, "c")
for (new i = 0; i < num; i++)
flushPlayer(players[i])
if (g_iVault != NO_VAULT)
nvault_close(g_iVault)
}
public client_authorized(id)
{
g_iTotal[id] = 0
g_iSince[id] = get_systime()
g_szAuth[id][0] = 0
g_szName[id][0] = 0
if (is_user_bot(id) || is_user_hltv(id))
return
get_user_authid(id, g_szAuth[id], charsmax(g_szAuth[]))
get_user_name(id, g_szName[id], charsmax(g_szName[]))
if (g_iVault == NO_VAULT)
return
new value[16]
if (nvault_get(g_iVault, g_szAuth[id], value, charsmax(value)))
g_iTotal[id] = str_to_num(value)
}
public client_disconnected(id)
{
flushPlayer(id)
g_iSince[id] = 0
}
flushPlayer(id)
{
if (!g_szAuth[id][0])
return
new now = get_systime()
if (g_iSince[id] > 0 && now > g_iSince[id])
{
g_iTotal[id] += (now - g_iSince[id])
g_iSince[id] = now
}
if (g_iVault != NO_VAULT)
{
new value[16]
num_to_str(g_iTotal[id], value, charsmax(value))
nvault_pset(g_iVault, g_szAuth[id], value)
}
}
public taskFlush()
{
new players[32], num
get_players(players, num, "c")
for (new i = 0; i < num; i++)
flushPlayer(players[i])
}
seconds(id)
{
new extra = 0
if (g_iSince[id] > 0)
extra = get_systime() - g_iSince[id]
return g_iTotal[id] + extra
}
public cmdTime(id)
{
new secs = seconds(id)
new hours = secs / 3600
new mins = (secs % 3600) / 60
client_print(id, print_chat, "[CSB] You have played %d hour(s) and %d minute(s) on this server.", hours, mins)
return PLUGIN_HANDLED
}
public cmdTopTime(id)
{
new players[32], num
get_players(players, num, "c")
/* simple selection sort of the connected players by playtime */
new order[32]
for (new i = 0; i < num; i++)
order[i] = players[i]
for (new i = 0; i < num; i++)
{
new best = i
for (new j = i + 1; j < num; j++)
{
if (seconds(order[j]) > seconds(order[best]))
best = j
}
if (best != i)
{
new tmp = order[i]
order[i] = order[best]
order[best] = tmp
}
}
client_print(id, print_chat, "[CSB] --- Top playtime (online players) ---")
new shown = num < 5 ? num : 5
for (new i = 0; i < shown; i++)
{
new pid = order[i]
new secs = seconds(pid)
new name[32]
get_user_name(pid, name, charsmax(name))
client_print(id, print_chat, "[CSB] %d. %s - %dh %dm", i + 1, name, secs / 3600, (secs % 3600) / 60)
}
return PLUGIN_HANDLED
}
/* native csb_get_playtime(id) -> total seconds played, live */
public native_get_playtime(plugin, params)
{
new id = get_param(1)
if (id < 1 || id > 32 || !is_user_connected(id))
return 0
return seconds(id)
}