Member
Join Date: Nov 2010
Location: North Texas
|
04-28-2012
, 17:54
Re: First Plugin, Need Guidance
|
#17
|
I did end up finishing this plugin last year, but since I didn't use threaded queries it became lag inducing after each player death (there is an SQL query in the Event_PlayerDeath event).
So I have been re-writing it as a threaded plugin! However I am having a bit of trouble dealing with the asynchronous nature of the beast and believe I may be creating some race conditions which are causing errors. I say that namely because I had this plugin working yesterday, but today I am getting errors as soon as the plugin loads.
Namely, I am getting the FailState in the OnMapStart function each time now.
Any ideas on how to get this done in a reliable way?
PHP Code:
#pragma semicolon 1 #include <sourcemod.inc> #include <sdktools.inc>
new Handle:viper_db_hndl;
new Handle:db = INVALID_HANDLE;
new Handle:viper_table_name_hndl;
new Handle:viper_matches_table_name_hndl; new Handle:viper_weapons_table_name_hndl; new Handle:viper_players_table_name_hndl;
new viper_event_id; new viper_event_match;
new Handle:viper_event_name_hndl;
new bool:viper_active_bool;
new bool:viper_stats_yet_recorded_bool;
new String:db_config[64];
new String:viper_table_name[64];
new String:viper_matches_table_name[64]; new String:viper_weapons_table_name[64]; new String:viper_players_table_name[64];
new String:eventname[128]; new String:eventnameescaped[196];
public Plugin:myinfo = { name = "Viper Tournament System", author = "Colt McCormack", description = "A tournament/event statistics plugin with MySQL upload and PHP interface", version = "0.5.2", url = "http://mccormackmediaonline.com" };
public OnPluginStart() { //Create Commands RegAdminCmd("sm_viperstart", Command_ViperStart, ADMFLAG_RCON, "sm_viperstart [starts Viper system]"); RegAdminCmd("sm_viperstop", Command_ViperStop, ADMFLAG_RCON, "sm_viperstop [stops Viper system]"); RegAdminCmd("sm_viperscores", Command_ViperScores, ADMFLAG_RCON, "sm_vipersscores [debug Viper system command to show scores]");
//Debug Commands RegAdminCmd("sm_viperscores_save", Command_ViperScoresSave, ADMFLAG_RCON, "sm_vipersscores_save [debug command to submit scores to database]");
//Hook End Events HookEvent("player_death", Event_PlayerDeath); HookEvent("gg_win", Event_GGWin); HookEvent("cs_win_panel_match", Event_CSWinPanelMatch);
//Create CVars viper_db_hndl = CreateConVar("viper_db_config", "default", "Database configuration to use for Viper Tournament System", FCVAR_PLUGIN); viper_table_name_hndl = CreateConVar("viper_table_config", "viper_events", "MySQL table to use for Viper Tournament System Events", FCVAR_PLUGIN); viper_matches_table_name_hndl = CreateConVar("viper_matches_table_config", "viper_event_matches", "MySQL table to use for Viper Tournament System Match Data. Don't change unless necessary.", FCVAR_PLUGIN); viper_weapons_table_name_hndl = CreateConVar("viper_weapons_table_config", "viper_event_weapons", "MySQL table to use for Viper Tournament System Weapons Data. Don't change unless necessary.", FCVAR_PLUGIN); viper_players_table_name_hndl = CreateConVar("viper_players_table_config", "viper_event_players", "MySQL table to use for Viper Tournament System Player Data. Don't change unless necessary.", FCVAR_PLUGIN); viper_event_name_hndl = CreateConVar("viper_event_name", "Viper Tournament", "The human readable name for the event to be used.", FCVAR_PLUGIN);
//Monitor CVar changes and execute accompanying functions HookConVarChange(viper_db_hndl, OnViperDBChange); HookConVarChange(viper_table_name_hndl, OnViperDBChange); HookConVarChange(viper_matches_table_name_hndl, OnViperDBChange); HookConVarChange(viper_weapons_table_name_hndl, OnViperDBChange); HookConVarChange(viper_players_table_name_hndl, OnViperDBChange); HookConVarChange(viper_event_name_hndl, OnViperEventNameChange);
//Execute config file, or create if it does not exist. AutoExecConfig(true, "viper");
//Load table names into global vars for use by functions GetConVarString(viper_db_hndl, db_config, sizeof(db_config)); GetConVarString(viper_table_name_hndl, viper_table_name, sizeof(viper_table_name)); GetConVarString(viper_matches_table_name_hndl, viper_matches_table_name, sizeof(viper_matches_table_name)); GetConVarString(viper_weapons_table_name_hndl, viper_weapons_table_name, sizeof(viper_weapons_table_name)); GetConVarString(viper_players_table_name_hndl, viper_players_table_name, sizeof(viper_players_table_name));
//Set stats to recordable viper_stats_yet_recorded_bool = false;
//Connect to database ConnectDB(); }
public ConnectDB() { // Verify that the configuration is defined in databases.cfg if (!SQL_CheckConfig(db_config)) { Viper_LogError("Database configuration \"%s\" does not exist", db_config); }
// Attempt to establish a connection SQL_TConnect(Callback_SQL_OnConnect, db_config); }
public Callback_SQL_OnConnect(Handle:owner, Handle:hndl, const String:error[], any:data) { //Since we are not guaranteed a connection, we make sure it actually worked if (hndl == INVALID_HANDLE) { //It didn't work, so we log the error Viper_LogError("Database failure: %s", error);
//Error if database may not be reached or caused error Viper_LogError("FATAL: An error occurred while connecting to the database."); SetFailState("An error occurred while connecting to the database."); } else { //It worked, so we set the global to the handle the callback provided for this connection Viper_LogMessage("Successfully connected to the database!"); db = hndl; PrepareDB(); } }
public PrepareDB() { //Make sure that the user is using mysql decl String:driver[32]; SQL_ReadDriver(db, driver, sizeof(driver));
if (strcmp(driver, "mysql")) { Viper_LogError("Error establishing database connection: Database driver is \"%s\" and should be \"mysql\".", driver); SetFailState("FATAL: Error establishing database connection: Database driver is \"%s\" and should be \"mysql\".", driver); return false; }
//Create SQL tables if needed decl String:query[256]; Format(query, sizeof(query), "CREATE TABLE IF NOT EXISTS %s (event_id INT(4) NOT NULL auto_increment, event_name VARCHAR(128), current_match INT(4) NOT NULL DEFAULT '1', start_time DATETIME, end_time DATETIME, is_active TINYINT(1), PRIMARY KEY (event_id))", viper_table_name); SQL_TQuery(db, Callback_SQLQueryFatal, query);
decl String:query2[256]; Format(query2, sizeof(query2), "CREATE TABLE IF NOT EXISTS %s (event_id INT(4), event_match INT(4), client_steam VARCHAR(24), client_kills INT(4), client_deaths INT(4), gg_win TINYINT(1), PRIMARY KEY (event_id, event_match, client_steam))", viper_matches_table_name); SQL_TQuery(db, Callback_SQLQueryFatal, query2);
decl String:query3[1300]; Format(query3, sizeof(query3), "CREATE TABLE IF NOT EXISTS %s (event_id INT(4), client_steam VARCHAR(24), client_tks INT(4) NOT NULL, client_suicides INT(4) NOT NULL, knife_kills INT(4) NOT NULL, usp_kills INT(4) NOT NULL, glock_kills INT(4) NOT NULL, p228_kills INT(4) NOT NULL, deagle_kills INT(4) NOT NULL, fiveseven_kills INT(4) NOT NULL, elite_kills INT(4) NOT NULL, m3_kills INT(4) NOT NULL, xm1014_kills INT(4) NOT NULL, mp5navy_kills INT(4) NOT NULL, tmp_kills INT(4) NOT NULL, p90_kills INT(4) NOT NULL, mac10_kills INT(4) NOT NULL, ump45_kills INT(4) NOT NULL, galil_kills INT(4) NOT NULL, famas_kills INT(4) NOT NULL, m4a1_kills INT(4) NOT NULL, ak47_kills INT(4) NOT NULL, aug_kills INT(4) NOT NULL, sg552_kills INT(4) NOT NULL, sg550_kills INT(4) NOT NULL, g3sg1_kills INT(4) NOT NULL, scout_kills INT(4) NOT NULL, awp_kills INT(4) NOT NULL, m249_kills INT(4) NOT NULL, hegrenade_kills INT(4) NOT NULL, PRIMARY KEY (client_steam))", viper_weapons_table_name); SQL_TQuery(db, Callback_SQLQueryFatal, query3);
decl String:query4[256]; Format(query4, sizeof(query4), "CREATE TABLE IF NOT EXISTS %s (client_steam VARCHAR(24), client_name VARCHAR(80), PRIMARY KEY (client_steam))", viper_players_table_name); SQL_TQuery(db, Callback_SQLQueryFatal, query4); IsEventActive(); return true; }
public Callback_SQLQueryFatal(Handle:owner, Handle:hndl, const String:error[], any:data) { if( hndl == INVALID_HANDLE ) { Viper_LogError("FATAL:[SQL] [ERROR] %s", error); SetFailState("[SQL] [ERROR] %s", error); } }
public OnMapStart() { if( db == INVALID_HANDLE ) { SetFailState("Invalid Handle in OnMapStart()"); } //Check for any live events and activate the system if found IsEventActive(); //Set stats to recordable again at every new map viper_stats_yet_recorded_bool = false; }
public IsEventActive() { if( db == INVALID_HANDLE ) { SetFailState("Invalid Handle in IsEventActive()"); } decl String:query[256]; Format(query, sizeof(query), "SELECT `event_id`, `current_match` FROM `%s` WHERE `is_active`=1", viper_table_name); SQL_TQuery(db, Callback_IsEventActive, query); }
public Callback_IsEventActive(Handle:owner, Handle:hndl, const String:error[], any:data) { new eventactiverows = SQL_GetRowCount(hndl); if (eventactiverows >= 2) { Viper_LogError("FATAL: Multiple events are set to active."); SetFailState("Multiple events are set to active."); return; } if (eventactiverows == 0){ Viper_LogMessage("No events are currently active."); viper_active_bool = false; return; } //Set ID for active event SQL_FetchRow(hndl); viper_event_id = SQL_FetchInt(hndl, 0); viper_event_match = SQL_FetchInt(hndl, 1); viper_active_bool = true; Viper_LogMessage("The event already exists and is now in use. The event id is: %d. The event is currently on match #%d.", viper_event_id, viper_event_match); }
|
|