Promocionar servidor

Initial release 1.0.0

Browse Source
1.0.0 - Initial release.
Daemon666 committed commit 4daeb72cc6c3d94bca0735080d128a4bd9584050
4 changed files with 218 additions and 0 deletions
+3 -0 CHANGELOG.md A
@@ -0,0 +1,3 @@
1 +## 1.0.0 (2025-10-28)
2 +
3 +1.0.0 - Initial release.
+1 -0 README.md A
@@ -0,0 +1 @@
1 +<p><strong>CSB Stats Web Export</strong> collects kills, deaths, headshots, damage and playtime per player and writes them to a MySQL table at map end. Everything goes out as a <strong>single multi-row INSERT ... ON DUPLICATE KEY UPDATE</strong> through a threaded SQLx query, so the game thread never blocks and the database sees one query per map. An external website can then render ladders straight from the table.</p><h2>Features</h2><ul><li>Threaded SQLx - zero main-thread blocking.</li><li>One batched query per map, additive on conflict.</li><li>Connection details set by cvar.</li></ul><h2>Installation</h2><ol><li>Enable the <code>sqlx</code> and <code>hamsandwich</code> modules and configure the MySQL section in <code>addons/amxmodx/configs/sql.cfg</code> or the <code>csb_sql_*</code> cvars.</li><li>Create the <code>csb_webstats</code> table (schema in the source header).</li><li>Compile, install, add to <code>plugins.ini</code>, change map.</li></ol>
+168 -0 addons/amxmodx/scripting/csb_stats_webexport.sma A
@@ -0,0 +1,168 @@
1 +/*
2 + * CSB Stats Web Export
3 + * Copyright (C) 2026 counter-strike-boost.com
4 + *
5 + * Pushes end-of-map player stats into a MySQL table so an external website
6 + * can render ladders. At map end (plugin_end) all connected players are
7 + * written in a single multi-row INSERT ... ON DUPLICATE KEY UPDATE through a
8 + * threaded SQLx query, so the game thread never blocks on the database and
9 + * the query count stays at one per map.
10 + *
11 + * Table layout (create once):
12 + * CREATE TABLE csb_webstats (
13 + * steamid VARCHAR(40) NOT NULL,
14 + * name VARCHAR(32) NOT NULL DEFAULT '',
15 + * kills INT NOT NULL DEFAULT 0,
16 + * deaths INT NOT NULL DEFAULT 0,
17 + * headshots INT NOT NULL DEFAULT 0,
18 + * damage INT NOT NULL DEFAULT 0,
19 + * seconds INT NOT NULL DEFAULT 0,
20 + * PRIMARY KEY (steamid)
21 + * );
22 + *
23 + * This program is free software: you can redistribute it and/or modify it under
24 + * the terms of the GNU General Public License as published by the Free Software
25 + * Foundation, either version 3 of the License, or (at your option) any later
26 + * version. It is distributed in the hope that it will be useful, but WITHOUT
27 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
28 + * FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
29 + */
30 +
31 +#include <amxmodx>
32 +#include <hamsandwich>
33 +#include <sqlx>
34 +
35 +new const PLUGIN[] = "CSB Stats Web Export"
36 +new const VERSION[] = "1.0.0"
37 +new const AUTHOR[] = "counter-strike-boost.com"
38 +
39 +new g_iKills[33]
40 +new g_iDeaths[33]
41 +new g_iHs[33]
42 +new g_iDamage[33]
43 +new Float:g_fJoined[33]
44 +
45 +new g_pHost, g_pUser, g_pPass, g_pDb
46 +
47 +public plugin_init()
48 +{
49 + register_plugin(PLUGIN, VERSION, AUTHOR)
50 +
51 + g_pHost = register_cvar("csb_sql_host", "localhost")
52 + g_pUser = register_cvar("csb_sql_user", "amxx")
53 + g_pPass = register_cvar("csb_sql_pass", "")
54 + g_pDb = register_cvar("csb_sql_db", "csb_stats")
55 +
56 + register_event("DeathMsg", "onDeath", "a")
57 + RegisterHam(Ham_TakeDamage, "player", "OnDamage", 1)
58 +}
59 +
60 +public client_putinserver(id)
61 +{
62 + g_iKills[id] = 0
63 + g_iDeaths[id] = 0
64 + g_iHs[id] = 0
65 + g_iDamage[id] = 0
66 + g_fJoined[id] = get_gametime()
67 +}
68 +
69 +public onDeath()
70 +{
71 + new killer = read_data(1)
72 + new victim = read_data(2)
73 + new hs = read_data(3)
74 +
75 + if (victim < 1 || victim > 32)
76 + return
77 +
78 + g_iDeaths[victim]++
79 +
80 + if (killer >= 1 && killer <= 32 && killer != victim
81 + && get_user_team(killer) != get_user_team(victim))
82 + {
83 + g_iKills[killer]++
84 +
85 + if (hs)
86 + g_iHs[killer]++
87 + }
88 +}
89 +
90 +public OnDamage(victim, inflictor, attacker, Float:damage, damagetype)
91 +{
92 + if (attacker < 1 || attacker > 32 || attacker == victim)
93 + return HAM_IGNORED
94 +
95 + if (get_user_team(attacker) == get_user_team(victim))
96 + return HAM_IGNORED
97 +
98 + g_iDamage[attacker] += floatround(damage)
99 +
100 + return HAM_IGNORED
101 +}
102 +
103 +public plugin_end()
104 +{
105 + exportStats()
106 +}
107 +
108 +exportStats()
109 +{
110 + new host[64], user[64], pass[64], db[64]
111 + get_pcvar_string(g_pHost, host, charsmax(host))
112 + get_pcvar_string(g_pUser, user, charsmax(user))
113 + get_pcvar_string(g_pPass, pass, charsmax(pass))
114 + get_pcvar_string(g_pDb, db, charsmax(db))
115 +
116 + new Handle:tuple = SQL_MakeDbTuple(host, user, pass, db)
117 +
118 + static query[4096]
119 + new len
120 +
121 + len = formatex(query, charsmax(query),
122 + "INSERT INTO csb_webstats (steamid, name, kills, deaths, headshots, damage, seconds) VALUES ")
123 +
124 + new rows = 0
125 +
126 + for (new id = 1; id <= 32; id++)
127 + {
128 + if (!is_user_connected(id) || is_user_bot(id))
129 + continue
130 +
131 + new auth[36], name[32], ename[64]
132 + get_user_authid(id, auth, charsmax(auth))
133 + get_user_name(id, name, charsmax(name))
134 +
135 + /* cheap escape: single quotes are doubled */
136 + copy(ename, charsmax(ename), name)
137 + replace_all(ename, charsmax(ename), "'", "''")
138 +
139 + new secs = floatround(get_gametime() - g_fJoined[id])
140 +
141 + len += formatex(query[len], charsmax(query) - len,
142 + "%s('%s','%s',%d,%d,%d,%d,%d)",
143 + rows > 0 ? "," : "",
144 + auth, ename, g_iKills[id], g_iDeaths[id], g_iHs[id], g_iDamage[id], secs)
145 +
146 + rows++
147 +
148 + if (len > charsmax(query) - 200)
149 + break
150 + }
151 +
152 + if (rows < 1)
153 + {
154 + SQL_FreeHandle(tuple)
155 + return
156 + }
157 +
158 + len += formatex(query[len], charsmax(query) - len,
159 + " ON DUPLICATE KEY UPDATE name=VALUES(name), kills=kills+VALUES(kills), deaths=deaths+VALUES(deaths), headshots=headshots+VALUES(headshots), damage=damage+VALUES(damage), seconds=seconds+VALUES(seconds)")
160 +
161 + SQL_ThreadQuery(tuple, "onExported", query)
162 +}
163 +
164 +public onExported(failstate, Handle:query, error[], errcode, data[], datasize)
165 +{
166 + if (failstate != TQUERY_SUCCESS)
167 + log_amx("[CSB WebExport] query failed (%d): %s", errcode, error)
168 +}
+46 -0 csb.json A
@@ -0,0 +1,46 @@
1 +{
2 + "name": "CSB Stats Web Export",
3 + "category": "stats",
4 + "tags": "export, mysql, website",
5 + "image": "",
6 + "original_author": "",
7 + "original_url": "",
8 + "license": "GPL-3.0",
9 + "title": "CSB Stats Web Export",
10 + "short_desc": "Pushes end-of-map player stats to MySQL with one threaded multi-row INSERT for external ladder websites.",
11 + "version": "1.0.0",
12 + "amxx_min": "1.9",
13 + "amxx_compile_default": "1.9",
14 + "rehlds_ok": true,
15 + "hlds_ok": true,
16 + "regamedll_required": false,
17 + "metamod_flavor": "any",
18 + "reapi_required": false,
19 + "modules": "hamsandwich,sqlx",
20 + "install_notes": "1. Enable the sqlx and hamsandwich modules in addons/amxmodx/configs/modules.ini\n2. Create the csb_webstats table (schema is documented in the source header)\n3. Compile, install, add to plugins.ini, change map",
21 + "known_conflicts": "",
22 + "cvars": [
23 + {
24 + "name": "csb_sql_host",
25 + "default": "localhost",
26 + "description": "MySQL host."
27 + },
28 + {
29 + "name": "csb_sql_user",
30 + "default": "amxx",
31 + "description": "MySQL user."
32 + },
33 + {
34 + "name": "csb_sql_pass",
35 + "default": "",
36 + "description": "MySQL password."
37 + },
38 + {
39 + "name": "csb_sql_db",
40 + "default": "csb_stats",
41 + "description": "MySQL database."
42 + }
43 + ],
44 + "commands": [],
45 + "main": "addons/amxmodx/scripting/csb_stats_webexport.sma"
46 +}
0 47