Valve Developer Community:Sandbox

From Valve Developer Community
Revision as of 14:45, 28 November 2011 by Pizzahut (talk | contribs) (remember_the_names_3.sma)
Jump to navigation Jump to search

The Sandbox (Valve Developer Community:Sandbox) is a VDC namespace page designed for testing and experimenting with Wiki syntax. Feel free to try your skills at formatting here: click on edit, make your changes, and click 'Save page' when you are finished. Content added here will not stay permanently.

Please do not edit the "markup" text, at the top of the editing window, that reads "{{sandbox}}".


  1. define PLUGINNAME "Remember the names"
  2. define VERSION "0.4.3"
  3. define AUTHOR "JGHG"

/* Copyleft 2005 Plugin topic: http://www.amxmodx.org/forums/viewtopic.php?p=92039

PLUGINNAME

==

Remembers names used by players.

In console you can type "amx_names <playername>" and you will have a list of the ten most common names ever used by that player. The names are ordered by frequency and last time of use.

When someone enters the server a welcome msg is displayed to all clients (or admins only depending on compile). If someone enters with a name less common than previously used names for that player, the welcome msg will also contain up to three names most commonly used by the player.

Example: If I play 20 maps with the name "JGHG" and then 10 maps with "Johnny got his gun", and I enter another map with the name "Faken Icker" the welcome msg should look like "We welcome Faken Icker, aka: JGHG, Johnny got his gun".

Add these sql info cvars to sql.cfg: rtn_host "127.0.0.1" rtn_user "myusername" rtn_pass "thesecretpassword" rtn_db "thedb"

You can replace ADMIN_CFG with whatever access level you want below. This access is a must to use "amx_names".

  • /
  1. define ACCESS_AMXNAMES ADMIN_KICK // check amxconst.inc for the other access flags...

/* You can also replace ADMIN_ADMIN below with whatever access level you want to be required to get the welcome msg about a user logging in...

  • /
  1. define ACCESS_WELCOMEMSG ADMIN_ALL // you can replace ADMIN_CFG with ADMIN_ALL and everyone will receive the welcome msg

/* Note to SQLITE module users: If you're using this module it doesn't matter what you write in ANY of the cvars BUT rtn_db, in fact that is the only cvar that will exist. The rtn_db cvar should contain the full path to the db file from your top server directory, one step above the mod dir. Ie if you set rtn_db to "cstrike/addons/amxmodx/data/rememberthenames.db" it will end up as that file in that directory.

/JGHG


VERSIONS

==

070519 0.4.3 Sun fixed some issues with displaying names. 070211 0.4.2 Sir fixed some issues with displaying names. 050330 0.4.1 Attempt to work out bugs. 050330 0.4 Fixed some issues with displaying names. 'amx_names' now displays the ten most common names used by specified player. You can now also define (at compile time) what access will be required to recieve the welcome msgs. 050113 0.3.1 Test version made to be compatible with Sqlite module. No new features. 050112 0.3 Prints a public welcome msg when someone enters. If someone enters with a name less common than previously used names for that player, the welcome msg will also contain up to three names most commonly used by the player. 050111 0.2 Removed use of fakemeta, updated some stuff, fixed a real bug with displaying names... ingame names now display in a MOTD window. 050110 0.1 First version


CREDITS

=

Idea of Cryonic

  • /
  1. include <amxmodx>
  2. include <dbi>
  3. include <amxmisc>
  1. define CREATE_TABLE_STEAMIDS "CREATE TABLE IF NOT EXISTS steamids (steamid varchar(40) NOT NULL default , id int(11) NOT NULL auto_increment, PRIMARY KEY (id), UNIQUE KEY STEAMID (steamid)) TYPE=MyISAM;"
  2. define CREATE_TABLE_NAMES "CREATE TABLE IF NOT EXISTS names ( timestamp int(10) unsigned NOT NULL default '0', counter int(10) unsigned NOT NULL default '1', id int(11) NOT NULL default '0', name varchar(32) binary NOT NULL default , PRIMARY KEY (id,name)) TYPE=MyISAM; "
  3. define CREATE_TABLE_STEAMIDS_SQLITE "CREATE TABLE steamids (steamid VARCHAR NOT NULL DEFAULT UNIQUE, id INTEGER PRIMARY KEY)"
  4. define CREATE_TABLE_NAMES_SQLITE "CREATE TABLE names (timestamp INTEGER, counter INTEGER DEFAULT '1', id INTEGER, name VARCHAR BINARY NOT NULL DEFAULT )"
  5. define CVAR_HOST "rtn_host"
  6. define CVAR_USER "rtn_user"
  7. define CVAR_PASS "rtn_pass"
  8. define CVAR_DB "rtn_db"
  9. define QSIZE 511
  10. define NROFCOMMONNAMES 3
  11. define CVAR_NOADMINS "rtn_noadmins"

// Globals below new g_query[QSIZE + 1] new g_dbids[64] // stores the automatically generated id that is handled to each steamid by db new g_lastname[64][64] new bool:g_sqlite new bool:g_inServer[64] // Globals above

stock admin_print(access, const DESTINATION, const MSG[]) { new const MAXPLAYERS = get_maxplayers()

new bool:mustBeAdmin if (access & ADMIN_ADMIN) { mustBeAdmin = true access &= ~ADMIN_ADMIN } else mustBeAdmin = false

for (new i = 1; i <= MAXPLAYERS; i++) { // No offliners, bots or people without the required access. if (!g_inServer[i] || !is_user_connected(i) || is_user_bot(i)) continue

if (mustBeAdmin && !is_user_admin(i)) continue

if (access > 0 && !(get_user_flags(i) & access)) continue

client_print(i, DESTINATION, MSG) } }

public plugin_modules() { require_module("dbi") }

public client_connect(id) { g_lastname[id] = "" g_dbids[id] = 0 g_inServer[id] = false return PLUGIN_CONTINUE }

public client_disconnect(id) { g_inServer[id] = false return PLUGIN_CONTINUE }

jghg_free_result(Result:result) { if (result > RESULT_NONE) { //server_print("!!!REMOVE: %d", result) dbi_free_result(result) } }

public client_authorized(id) { if (is_user_bot(id)) return PLUGIN_CONTINUE

const LEN = 32 new steamid[LEN + 1], name[64]

get_user_authid(id, steamid, LEN) get_user_name(id, name, 31)

new Sql:sql if (!connect(sql)) return PLUGIN_CONTINUE

if (!getdbidfromsteamid(id, steamid, false, sql)) { format(g_query, QSIZE, "INSERT INTO steamids (steamid) VALUES ('%s')", steamid) //server_print("client_authorized: sending query: %s", g_query) new Result:result = dbi_query(sql, g_query) jghg_free_result(result)

// Do this another time to get the dbid from database. if (!getdbidfromsteamid(id, steamid, false, sql)) log_amx("Failed getting dbid for %s (%s)!", steamid, name) } //server_print("client_authorized: dbid for %d is %d", id, g_dbids[id])

disconnect(sql)

return PLUGIN_CONTINUE }

bool:getdbidfromsteamid(id, steamid[], bool:doConnect, &Sql:sql = SQL_FAILED) { g_dbids[id] = 0 new bool:exists = false if (doConnect) { if (!connect(sql)) return false } format(g_query, QSIZE, "SELECT id FROM steamids WHERE steamid = '%s' LIMIT 1", steamid) //server_print("getdbidfromsteamid: Does query: %s", g_query) new Result:result = dbi_query(sql, g_query) //server_print("Query done, result: %d", result) if (result < RESULT_OK && dbi_check_error(sql)) { } else if (dbi_nextrow(result)) { g_dbids[id] = dbi_field(result, 1) exists = true } jghg_free_result(result) if (doConnect) dbi_close(sql)

return exists }

name_to_db(id, name[], &Sql:sql = SQL_FAILED) { if (g_dbids[id] == 0) return

new bool:disconnect_ = false if (sql == SQL_FAILED) { disconnect_ = true if (!connect(sql)) return }

replace_all(name,32,"'","");

format(g_query, QSIZE, "SELECT counter FROM names WHERE id = '%d' AND name = '%s' LIMIT 1", g_dbids[id], name)

//server_print("name_to_db: Sending query: %s", g_query) new Result:result = dbi_query(sql, g_query) //server_print("name_to_db: result=%d rows=%d", result, dbi_num_rows(result)) new const TIMESTAMP = get_systime()

if (result < RESULT_OK && dbi_check_error(sql)) { // Error... } else if (dbi_nextrow(result)) { // Record already in db. Increase counter new counter = dbi_field(result, 1) //server_print("NAME ALREADY MATCHES, INCREASING COUNTER from %d to %d", next, counter, counter + 1) jghg_free_result(result)

counter++

if (g_sqlite) format(g_query, QSIZE, "UPDATE names SET counter = %d, timestamp = %d WHERE id = %d AND name = '%s'", counter, TIMESTAMP, g_dbids[id], name) else format(g_query, QSIZE, "UPDATE names SET counter = %d, timestamp = %d WHERE id = %d AND name = '%s' LIMIT 1", counter, TIMESTAMP, g_dbids[id], name) //server_print("name_to_db: Sending query: %s", g_query) result = dbi_query(sql, g_query) jghg_free_result(result) //server_print("%s is already in db for %d (%d)", name, id, g_dbids[id]) } else { jghg_free_result(result)

format(g_query, QSIZE, "INSERT INTO names (id, name, timestamp) VALUES(%d, '%s', %d)", g_dbids[id], name, TIMESTAMP) //server_print("name_to_db: Sending query: %s", g_query) result = dbi_query(sql, g_query) jghg_free_result(result) }

if (disconnect_) disconnect(sql) }

bool:connect(&Sql:sql) { const LEN = 128 new host[LEN], user[LEN], pass[LEN], db[LEN], error_msg[LEN]

if (!g_sqlite) { get_cvar_string(CVAR_HOST, host, LEN - 1) get_cvar_string(CVAR_USER, user, LEN - 1) get_cvar_string(CVAR_PASS, pass, LEN - 1) } get_cvar_string(CVAR_DB, db, LEN - 1)

//server_print("Passing this to dbi_connect(%s, %s, %s, %s, %d)", host, user, pass, db, LEN - 1)

sql = dbi_connect(host, user, pass, db, error_msg, LEN - 1) //server_print("dbi_connect = %d", sql) if (sql < SQL_OK && dbi_check_error(sql)) { log_amx("[%s] ERROR - Can't connect to SQL db: %s", PLUGINNAME, error_msg)

return false } else { //log_amx("[%s] Successfully connected to SQL db.", PLUGINNAME) //server_print("[%s] Successfully connected to SQL db.", PLUGINNAME) }

return true }

dbi_check_error(&Sql:sql) { new error[256] = "" dbi_error(sql, error, 255) if (error[0] && !equal(error, "Not an error")) { log_amx("[%s] SQL error: %s", PLUGINNAME, error)

return true }

return false }

disconnect(&Sql:sql) { if (sql > SQL_FAILED) { dbi_close(sql) sql = SQL_FAILED } }

public listnames(id, level, cid) { if (!cmd_access(id, level, cid, 2)) return PLUGIN_HANDLED

new plname[64] read_argv(1, plname, 32)

new player = cmd_target(id, plname, 2) // 2 = allow yourself if (!player) return PLUGIN_HANDLED else if (is_user_bot(player)) { console_print(id, "[%s] Nahh, bots don't count.", PLUGINNAME) return PLUGIN_HANDLED }

const SIZE = 1023 new names[SIZE + 1] getnames(id, player, names, SIZE)

new title[40] get_user_authid(player, title, 39) format(title, 39, "Names used by %s", title) if (id == 0) { console_print(id, title) console_print_byline(id, names) } else { console_print(id, "Close the console to view the names as they are displayed in a MOTD window.") show_motd(id, names, title) }

return PLUGIN_HANDLED }

console_print_byline(id, text[]) { new line[256], starti = 0 new const TEXTLENGTH = strlen(text)

for (new i = 0; i < TEXTLENGTH; i++) { if (text[i] != '^n') line[i - starti] = text[i] //linelen += format(line[linelen], 127 - linelen, "%c", text[i]) else { line[i - starti] = 0 console_print(id, line) line[0] = 0 starti = i + 1 } } console_print(id, line) }

getnames(id, player, nameshere[], const LEN) { if (g_dbids[player] == 0) { format(nameshere, LEN, "Couldn't retrieve user's db id at login.") return } new Sql:sql connect(sql)

format(g_query, QSIZE, "SELECT name, counter, timestamp FROM names WHERE id = %d ORDER BY counter DESC, timestamp DESC LIMIT 10", g_dbids[player]) new Result:result = dbi_query(sql, g_query) if (result < RESULT_OK && dbi_check_error(sql)) { console_print(id, "[%s] Oops, db operation failed.", PLUGINNAME) } else { new name[64], counter, timestamp, time_[64] new len = 0

if (id == 0) { len = format(nameshere, LEN, "%31s%11s%20s^n", "Name", "Times used", "Last time used") while (dbi_nextrow(result) && len < LEN) { dbi_field(result, 1, name, 31) counter = dbi_field(result, 2) timestamp = dbi_field(result, 3) format_time(time_, 31, "%y%m%d - %H:%M:%S", timestamp) len += format(nameshere[len], LEN - len, "%31s%11d%20s^n", name, counter, time_) }

//len += format(nameshere[len], LEN - len, "", name)

} else {

len = format(nameshere, LEN, "

")

while (dbi_nextrow(result) && len < LEN) { dbi_field(result, 1, name, 31) counter = dbi_field(result, 2) timestamp = dbi_field(result, 3) format_time(time_, 31, "%y%m%d - %H:%M:%S", timestamp)

len += format(nameshere[len], LEN - len, "", name, counter, time_)

}

len += format(nameshere[len], LEN - len, "
NameTimes usedLast time used
%s%d%s

", name)

}

jghg_free_result(result) }

disconnect(sql) }

public client_infochanged(id) { if (is_user_bot(id) || g_dbids[id] == 0) return PLUGIN_CONTINUE

set_task(0.1, "checkname", id)

return PLUGIN_CONTINUE }

public checkname(id) { if (!is_user_connected(id) || is_user_bot(id) || g_dbids[id] == 0) return

new name[64] get_user_name(id, name, 31) if (!equal(name, g_lastname[id])) { //client_print(id, print_chat, "your name changed, name: %s", name) name_to_db(id, name)

g_lastname[id] = name } }

/*stock bool:sqlite_table_exists(Sql:sql, table[]) { new bool:exists new query[128] format(query, 127, "SELECT name FROM sqlite_master WHERE type='table' AND name='%s' LIMIT 1;", table)

new Result:result = dbi_query(sql, query)

if (dbi_nextrow(result)) exists = true else exists = false

if (result > RESULT_NONE) dbi_free_result(result)

return exists }*/

bool:create_tables() { new Sql:sql if (!connect(sql)) { log_amx("[%s] Failed connecting to database. Pausing plugin.", PLUGINNAME) pause("a") return false }

new Result:result

if (!g_sqlite || (g_sqlite && !sqlite_table_exists(sql, "steamids"))) { format(g_query, QSIZE, "%s", g_sqlite ? CREATE_TABLE_STEAMIDS_SQLITE : CREATE_TABLE_STEAMIDS)

result = dbi_query(sql, g_query)

if (result <= RESULT_FAILED && dbi_check_error(sql)) { log_amx("[%s] Error while creating steamid table. Pausing plugin.", PLUGINNAME) disconnect(sql) pause("a") return false } jghg_free_result(result) }


if (!g_sqlite || (g_sqlite && !sqlite_table_exists(sql, "names"))) { format(g_query, QSIZE, "%s", g_sqlite ? CREATE_TABLE_NAMES_SQLITE : CREATE_TABLE_NAMES)

result = dbi_query(sql, g_query)

if (result <= RESULT_FAILED && dbi_check_error(sql)) { log_amx("[%s] Error while creating names table. Pausing plugin.", PLUGINNAME) disconnect(sql) pause("a") return false } jghg_free_result(result) }

disconnect(sql)

return true } /* stock jghg_is_user_admin(id, accessRequired = ADMIN_ADMIN) { return get_user_flags(id) & accessRequired }*/

public client_putinserver(id) { g_inServer[id] = true if (g_dbids[id] == 0 || is_user_bot(id) || (get_cvar_num(CVAR_NOADMINS) && is_user_admin(id))) { return PLUGIN_CONTINUE }

set_task(10.0, "delayed_printcommonnames", id)

return PLUGIN_CONTINUE }

public delayed_printcommonnames(id) { if (!is_user_connected(id)) return // Get three most common names from db. new commonnames[NROFCOMMONNAMES][64] new gotNames = get_common_names(commonnames, id) new currentName[64] get_user_name(id, currentName, 31) if (gotNames == 1 || (gotNames > 1 && equal(currentName, commonnames[0]))) { new msg[128] format(msg, 127, "We welcome %s", currentName) admin_print(ACCESS_WELCOMEMSG, print_chat, msg) //client_print(0, print_chat, "We welcome %s", currentName) server_print(msg) return }

new allNames[128], len = 0 for (new i = 0; i < gotNames && commonnames[i][0] != 0 && !equal(currentName, commonnames[i]); i++) { len += format(allNames[len], 31 - len, "%s, ", commonnames[i]) //server_print("commonnames[%d] is %s", i, commonnames[i]) } xs_strtrim(allNames, 2, false)

format(allNames, 127, "We welcome %s, aka: %s", currentName, allNames) admin_print(ACCESS_WELCOMEMSG, print_chat, allNames) //client_print(0, print_chat, allNames) server_print(allNames) }

// by JGHG, adapted // removes charstotrim number of charactes from stringtotrim's // - beginning if fromleft is true // - end if fromleft is false // tested stock xs_strtrim(stringtotrim[], charstotrim, bool:fromleft = true) { if (charstotrim <= 0)

   	return;

if (fromleft) { new maxlen = strlen(stringtotrim); if (charstotrim > maxlen) charstotrim = maxlen;

// In format, input and output regions can overlap format(stringtotrim, maxlen, "%s", stringtotrim[charstotrim]); } else { new maxlen = strlen(stringtotrim) - charstotrim; if (maxlen < 0) maxlen = 0;

// In format, input and output regions can overlap format(stringtotrim, maxlen, "%s", stringtotrim); } }

get_common_names(commonNames[NROFCOMMONNAMES][64], player) { new namesCollected = 0 if (g_dbids[player] == 0) { //format(nameshere, LEN, "Couldn't retrieve user's db id at login.") return namesCollected } new Sql:sql connect(sql)

format(g_query, QSIZE, "SELECT name FROM names WHERE id = %d ORDER BY counter DESC, timestamp DESC LIMIT %d", g_dbids[player], NROFCOMMONNAMES) //server_print("get_common_names: Sending query: %s", g_query) new Result:result = dbi_query(sql, g_query) if (result < RESULT_OK && dbi_check_error(sql)) { //console_print(id, "[%s] Oops, db operation failed.", PLUGINNAME) disconnect(sql) return namesCollected } //server_print("Done, rows gotten: %d", dbi_num_rows(result))

for (new i = 0; dbi_nextrow(result) && i < NROFCOMMONNAMES; i++) { dbi_field(result, 1, commonNames[i], 31) namesCollected++ }

jghg_free_result(result) disconnect(sql)

return namesCollected }

public plugin_init() { register_plugin(PLUGINNAME, VERSION, AUTHOR)

register_concmd("amx_names", "listnames", ACCESS_AMXNAMES, "<playername> - lists the ten most common names ever used by this player.")

new dbitype[16] dbi_type(dbitype, 15) server_print("[%s] Using database type %s.", PLUGINNAME, dbitype) if (equal(dbitype, "sqlite")) g_sqlite = true else g_sqlite = false

if (!g_sqlite) { register_cvar(CVAR_HOST, "127.0.0.1") register_cvar(CVAR_USER, "") register_cvar(CVAR_PASS, "") } register_cvar(CVAR_DB, "rememberthenames")

register_cvar(CVAR_NOADMINS, "0")


new sqlcfgpath[128] get_configsdir(sqlcfgpath, 127) format(sqlcfgpath, 127, "%s/sql.cfg", sqlcfgpath) server_cmd("exec %s", sqlcfgpath) server_exec() // To force execution of above cmd before progress? seems to do the trick...

if (create_tables()) server_print("[%s] Initialized successfully.", PLUGINNAME) }