#pragma semicolon 1 #pragma newdecls required //#define DEBUG #define PLUGIN_VERSION "1.0" #define MAX_PLAYER_HISTORY 25 #include #include //#include public Plugin myinfo = { name = "Noob DB", author = "jackzmc", description = "", version = PLUGIN_VERSION, url = "https://github.com/Jackzmc/sourcemod-plugins" }; static Database DB; static char query[1024]; static char reason[256]; static int WaitingForNotePlayer; static char menuNoteTarget[32]; enum struct PlayerData { char id[32]; char name[32]; } static ArrayList lastPlayers; public void OnPluginStart() { if(!SQL_CheckConfig("stats")) { SetFailState("No database entry for 'stats'; no database to connect to."); } if(!ConnectDB()) { SetFailState("Failed to connect to database."); } lastPlayers = new ArrayList(sizeof(PlayerData)); HookEvent("player_disconnect", Event_PlayerDisconnect); HookEvent("player_first_spawn", Event_FirstSpawn); RegAdminCmd("sm_note", Command_AddNote, ADMFLAG_KICK, "Add a note to a player"); RegAdminCmd("sm_notes", Command_ListNotes, ADMFLAG_KICK, "List notes for a player"); RegAdminCmd("sm_notedisconnected", Command_AddNoteDisconnected, ADMFLAG_KICK, "Add a note to any disconnected players"); } public Action Command_AddNoteDisconnected(int client, int args) { if(lastPlayers.Length == 0) { ReplyToCommand(client, "No disconnected players recorded."); return Plugin_Handled; } Menu menu = new Menu(Menu_Disconnected); menu.SetTitle("Add Note For Disconnected"); for(int i = lastPlayers.Length - 1; i >= 0; i--) { PlayerData data; lastPlayers.GetArray(i, data, sizeof(data)); menu.AddItem(data.id, data.name); } menu.Display(client, 0); return Plugin_Handled; } public int Menu_Disconnected(Menu menu, MenuAction action, int client, int item) { if (action == MenuAction_Select) { menu.GetItem(item, menuNoteTarget, sizeof(menuNoteTarget)); PrintToChat(client, "Enter a note in the chat for %s: (or 'cancel' to cancel)", menuNoteTarget); WaitingForNotePlayer = client; } else if (action == MenuAction_End) delete menu; return 0; } public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) { if(client > 0 && WaitingForNotePlayer == client) { WaitingForNotePlayer = 0; if(StrEqual(sArgs, "cancel", false)) { PrintToChat(client, "Note cancelled."); } else { static char buffer[32]; GetClientAuthId(client, AuthId_Steam2, buffer, sizeof(buffer)); DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", menuNoteTarget, buffer, sArgs); DB.Query(DB_AddNote, query); LogAction(client, -1, "\"%L\" added note for \"%s\": \"%s\"", client, menuNoteTarget, sArgs); Format(buffer, sizeof(buffer), "%N: ", client); ShowActivity2(client, buffer, "added a note for %s: \"%s\"", menuNoteTarget, sArgs); } return Plugin_Stop; } return Plugin_Continue; } public Action Command_AddNote(int client, int args) { if(args < 2) { ReplyToCommand(client, "Syntax: sm_note \"note in quotes\" or if they left, use sm_notedisconnected"); } else { static char target_name[MAX_TARGET_LENGTH]; GetCmdArg(1, target_name, sizeof(target_name)); GetCmdArg(2, reason, sizeof(reason)); int target_list[1], target_count; bool tn_is_ml; if ((target_count = ProcessTargetString( target_name, client, target_list, 1, COMMAND_FILTER_NO_MULTI, target_name, sizeof(target_name), tn_is_ml)) <= 0 ) { ReplyToTargetError(client, target_count); return Plugin_Handled; } static char auth[32]; GetClientAuthId(target_list[0], AuthId_Steam2, auth, sizeof(auth)); static char authMarker[32]; if(client > 0) GetClientAuthId(client, AuthId_Steam2, authMarker, sizeof(authMarker)); DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", auth, authMarker, reason); DB.Query(DB_AddNote, query); LogAction(client, target_list[0], "\"%L\" added note for \"%L\": \"%s\"", client, target_list[0], reason); ShowActivity(client, "added a note for \"%N\": \"%s\"", target_list[0], reason); } return Plugin_Handled; } public Action Command_ListNotes(int client, int args) { if(args < 1) { ReplyToCommand(client, "Syntax: sm_notes "); } else { static char target_name[MAX_TARGET_LENGTH]; GetCmdArg(1, target_name, sizeof(target_name)); GetCmdArg(2, reason, sizeof(reason)); int target_list[MAXPLAYERS], target_count; bool tn_is_ml; if ((target_count = ProcessTargetString( target_name, client, target_list, 1, COMMAND_FILTER_NO_MULTI, target_name, sizeof(target_name), tn_is_ml)) <= 0 ) { ReplyToTargetError(client, target_count); return Plugin_Handled; } static char auth[32]; GetClientAuthId(target_list[0], AuthId_Steam2, auth, sizeof(auth)); DB.Format(query, sizeof(query), "SELECT notes.content, stats_users.last_alias FROM `notes` JOIN stats_users ON markedBy = stats_users.steamid WHERE notes.`steamid` = '%s'", auth); ReplyToCommand(client, "Fetching notes..."); DataPack pack = new DataPack(); pack.WriteCell(GetClientUserId(client)); pack.WriteCell(GetClientUserId(target_list[0])); pack.WriteString(auth); DB.Query(DB_ListNotesForPlayer, query, pack); } return Plugin_Handled; } bool ConnectDB() { static char error[255]; DB = SQL_Connect("stats", true, error, sizeof(error)); if (DB== null) { LogError("Database error %s", error); delete DB; return false; } else { PrintToServer("Connected to database stats"); SQL_LockDatabase(DB); SQL_FastQuery(DB, "SET NAMES \"UTF8mb4\""); SQL_UnlockDatabase(DB); DB.SetCharset("utf8mb4"); return true; } } public void Event_FirstSpawn(Event event, const char[] name, bool dontBroadcast) { int client = GetClientOfUserId(event.GetInt("userid")); if(client > 0 && client <= MaxClients && !IsFakeClient(client)) { static char auth[32]; GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth)); DB.Format(query, sizeof(query), "SELECT notes.content, stats_users.last_alias FROM `notes` JOIN stats_users ON markedBy = stats_users.steamid WHERE notes.`steamid` = '%s'", auth); DB.Query(DB_FindNotes, query, GetClientUserId(client)); } } public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) { if(!event.GetBool("bot")) { PlayerData data; event.GetString("networkid", data.id, sizeof(data.id)); if(!StrEqual(data.id, "BOT")) { if(!IsPlayerInHistory(data.id)) { event.GetString("name", data.name, sizeof(data.name)); lastPlayers.PushArray(data); if(lastPlayers.Length > MAX_PLAYER_HISTORY) { lastPlayers.Erase(0); } } } } } bool IsPlayerInHistory(const char[] id) { static PlayerData data; for(int i = 0; i < lastPlayers.Length; i++) { lastPlayers.GetArray(i, data, sizeof(data)); if(StrEqual(data.id, id)) return true; } return false; } public void DB_FindNotes(Database db, DBResultSet results, const char[] error, any data) { if(db == null || results == null) { LogError("DB_FindNotes returned error: %s", error); return; } //initialize variables int client = GetClientOfUserId(data); if(client > 0 && results.RowCount > 0) { static char noteCreator[32]; PrintChatToAdmins("Notes for %N", client); while(results.FetchRow()) { results.FetchString(0, reason, sizeof(reason)); results.FetchString(1, noteCreator, sizeof(noteCreator)); PrintChatToAdmins("%s: %s", noteCreator, reason); } } } public void DB_ListNotesForPlayer(Database db, DBResultSet results, const char[] error, DataPack pack) { if(db == null || results == null) { LogError("DB_ListNotesForPlayer returned error: %s", error); return; } //initialize variables static char auth[32]; pack.Reset(); int client = GetClientOfUserId(pack.ReadCell()); int target = GetClientOfUserId(pack.ReadCell()); pack.ReadString(auth, sizeof(auth)); delete pack; if(client > 0) { if(results.RowCount > 0) { if(target > 0) { PrintToChat(client, "Notes for %N:", target); } else { PrintToChat(client, "Notes for %s:", auth); } char noteCreator[32]; while(results.FetchRow()) { results.FetchString(0, reason, sizeof(reason)); results.FetchString(1, noteCreator, sizeof(noteCreator)); PrintToChat(client, "%s: %s", noteCreator, reason); } } else { if(target > 0) PrintToChat(client, "No notes found for %N", target); else PrintToChat(client, "No notes found for %s", auth); } } } public void DB_AddNote(Database db, DBResultSet results, const char[] error, any data) { if(db == null || results == null) { LogError("DB_AddNote returned error: %s", error); return; } } stock void PrintChatToAdmins(const char[] format, any ...) { char buffer[254]; VFormat(buffer, sizeof(buffer), format, 2); for(int i = 1; i < MaxClients; i++) { if(IsClientConnected(i) && IsClientInGame(i)) { AdminId admin = GetUserAdmin(i); if(admin != INVALID_ADMIN_ID) { PrintToChat(i, "%s", buffer); } } } PrintToServer("%s", buffer); }