Jump to content

Recommended Posts

Posted

Dependențe necesare:
Pawn.CMD
MySQL R-41
sscanf2

Structura tabelului MySQL (SQL)

CREATE TABLE IF NOT EXISTS `server_reports` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sender_name` varchar(24) NOT NULL,
  `reason` varchar(128) NOT NULL,
  `date_added` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Codul sursă pawn
 

#include <a_samp>
#include <pawncmd>
#include <sscanf2>
#include <a_mysql> // Include pluginul MySQL R41+

// ---- Configurații ----
#define MAX_REPORTS         (50)       
#define DIALOG_REPORT_MAIN  (9981)     
#define DIALOG_REPORT_TEXT  (9982)     
#define DIALOG_REP_LIST     (9983)     

#define REASON_LENGTH       (128)
#define COLOR_RED           0xFF0000FF
#define COLOR_GREEN         0x00FF00FF
#define COLOR_YELLOW        0xFFFF00FF
#define COLOR_WHITE         0xFFFFFFFF
#define COLOR_LIGHTBLUE     0x33CCFFFF

// Înlocuiește "MySQL_Handle" cu variabila ta de conexiune MySQL dacă ai una existentă în GM
new MySQL:SQL_Handle; 

// ---- Structuri de date ----
enum E_REPORT_DATA {
    repDatabaseID,      // ID-ul unic din baza de date (MySQL Auto_Increment)
    repSenderID,        // ID-ul jucătorului pe server (-1 dacă e offline dar raportul e încă în coadă)
    repSenderName[MAX_PLAYER_NAME], // Numele jucătorului (salvat pentru când e offline)
    repReason[REASON_LENGTH], 
    bool:repActive      
}
new ReportQueue[MAX_REPORTS][E_REPORT_DATA];
new TotalReports = 0;   

new bool:HasActiveReport[MAX_PLAYERS]; 
new PlayerUnderReport[MAX_PLAYERS];    

// ---- Verificare Admin ----
stock IsPlayerAdminEx(playerid) {
    if(IsPlayerAdmin(playerid)) return 1; 
    // Înlocuiește linia de mai jos cu variabila ta de admin (ex: if(PlayerInfo[playerid][pAdmin] >= 1) return 1;)
    return 0; 
}

// ---- Forward-uri pentru MySQL ----
forward OnUnansweredReportsLoad();
forward OnReportInserted(queue_index, playerid);

public OnGameModeInit()
{
    // Inițializare coadă golită pe server
    for(new i = 0; i < MAX_REPORTS; i++) {
        ResetReportSlot(i);
    }
    
    // ATENȚIE: Dacă ai deja logica de conectare MySQL în GM, șterge liniile mysql_connect de mai jos!
    SQL_Handle = mysql_connect("127.0.0.1", "root", "", "server_db");
    if(mysql_errno(SQL_Handle) != 0) {
        printf("[MySQL] Conexiunea a eșuat în sistemul de reporturi.");
    } else {
        printf("[MySQL] Conexiune reușită. Încărcăm rapoartele nerezolvate...");
        // Încărcăm rapoartele nerezolvate salvate în baza de date
        mysql_tquery(SQL_Handle, "SELECT * FROM `server_reports` ORDER BY `id` ASC LIMIT 50", "OnUnansweredReportsLoad");
    }

    return 1;
}

public OnPlayerConnect(playerid)
{
    HasActiveReport[playerid] = false;
    PlayerUnderReport[playerid] = INVALID_PLAYER_ID;
    
    // Verificăm dacă jucătorul care s-a conectat are un raport rămas în coadă din sesiunea trecută
    new pName[MAX_PLAYER_NAME];
    GetPlayerName(playerid, pName, sizeof(pName));
    
    for(new i = 0; i < MAX_REPORTS; i++) {
        if(ReportQueue[i][repActive] && !strcmp(ReportQueue[i][repSenderName], pName, true)) {
            ReportQueue[i][repSenderID] = playerid; // Îi reasociem ID-ul curent de server
            HasActiveReport[playerid] = true;
            
            new str[128];
            format(str, sizeof(str), "{FFFFFF}[REPORT] Raportul tău din sesiunea anterioară este încă în coadă pe poziția {FFFF00}%d{FFFFFF}.", i + 1);
            SendClientMessage(playerid, COLOR_GREEN, str);
            break;
        }
    }
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    // Când un jucător iese, NU mai ștergem raportul din baza de date și nici din coadă!
    // Doar marcăm ID-ul ca invalid pe server, dar adminii îl vor vedea în continuare în listă după nume.
    if(HasActiveReport[playerid]) {
        for(new i = 0; i < MAX_REPORTS; i++) {
            if(ReportQueue[i][repActive] && ReportQueue[i][repSenderID] == playerid) {
                ReportQueue[i][repSenderID] = INVALID_PLAYER_ID; 
                break;
            }
        }
    }
    
    if(PlayerUnderReport[playerid] != INVALID_PLAYER_ID) {
        new target = PlayerUnderReport[playerid];
        if(IsPlayerConnected(target)) {
            SendClientMessage(target, COLOR_RED, "Adminul care iți procesa raportul s-a deconectat.");
        }
        PlayerUnderReport[playerid] = INVALID_PLAYER_ID;
    }
    return 1;
}

// ---- Funcții Ajutătoare (Helperi) ----

stock ResetReportSlot(i) {
    ReportQueue[i][repDatabaseID] = 0;
    ReportQueue[i][repSenderID] = INVALID_PLAYER_ID;
    ReportQueue[i][repSenderName][0] = '\0';
    ReportQueue[i][repReason][0] = '\0';
    ReportQueue[i][repActive] = false;
}

stock MessageToAdmins(color, const message[])
{
    for(new i = 0; i < MAX_PLAYERS; i++) {
        if(IsPlayerConnected(i) && IsPlayerAdminEx(i)) {
            SendClientMessage(i, color, message);
        }
    }
}

// ---- Logica MySQL R41 ----

public OnUnansweredReportsLoad()
{
    new rows = cache_num_rows();
    if(rows == 0) return printf("[MySQL] Nu s-au găsit rapoarte nerezolvate în baza de date.");
    
    TotalReports = 0;
    for(new i = 0; i < rows && i < MAX_REPORTS; i++) {
        ReportQueue[i][repActive] = true;
        cache_get_value_name_int(i, "id", ReportQueue[i][repDatabaseID]);
        cache_get_value_name(i, "sender_name", ReportQueue[i][repSenderName], MAX_PLAYER_NAME);
        cache_get_value_name(i, "reason", ReportQueue[i][repReason], REASON_LENGTH);
        ReportQueue[i][repSenderID] = INVALID_PLAYER_ID; // Va deveni valid dacă jucătorul se conectează
        
        TotalReports++;
    }
    printf("[MySQL] S-au încărcat cu succes %d rapoarte nerezolvate în coadă.", TotalReports);
    return 1;
}

stock SendReportToQueue(playerid, const reason[])
{
    if(TotalReports >= MAX_REPORTS) {
        return SendClientMessage(playerid, COLOR_RED, "Coada de rapoarte este plină! Încearcă din nou mai târziu.");
    }
    
    // Găsim primul slot liber local pe server
    for(new i = 0; i < MAX_REPORTS; i++) {
        if(!ReportQueue[i][repActive]) {
            ReportQueue[i][repActive] = true;
            ReportQueue[i][repSenderID] = playerid;
            GetPlayerName(playerid, ReportQueue[i][repSenderName], MAX_PLAYER_NAME);
            format(ReportQueue[i][repReason], REASON_LENGTH, "%s", reason);
            
            TotalReports++;
            HasActiveReport[playerid] = true;
            
            // Salvare threaded în MySQL R41
            new query[256];
            mysql_format(SQL_Handle, query, sizeof(query), "INSERT INTO `server_reports` (`sender_name`, `reason`) VALUES ('%e', '%e')", ReportQueue[i][repSenderName], reason);
            mysql_tquery(SQL_Handle, query, "OnReportInserted", "dd", i, playerid);
            return 1;
        }
    }
    return 0;
}

public OnReportInserted(queue_index, playerid)
{
    // Salvăm ID-ul generat de baza de date (Primary Key) direct în slotul aferent din coadă
    ReportQueue[queue_index][repDatabaseID] = mysql_insert_id(SQL_Handle);
    
    if(IsPlayerConnected(playerid)) {
        new str[128];
        format(str, sizeof(str), "{FFFFFF}[REPORT] Raportul tău a fost salvat! Poziția în coadă: {FFFF00}%d{FFFFFF}.", TotalReports);
        SendClientMessage(playerid, COLOR_GREEN, str);
        
        new name[MAX_PLAYER_NAME];
        GetPlayerName(playerid, name, sizeof(name));
        format(str, sizeof(str), "{33CCFF}[Report nou] (%d) %s[%d]: %s", TotalReports, name, playerid, ReportQueue[queue_index][repReason]);
        MessageToAdmins(COLOR_LIGHTBLUE, str);
    }
    return 1;
}

stock DeleteReportFromDatabase(db_id)
{
    if(db_id == 0) return 0;
    new query[128];
    mysql_format(SQL_Handle, query, sizeof(query), "DELETE FROM `server_reports` WHERE `id` = '%d'", db_id);
    mysql_tquery(SQL_Handle, query);
    return 1;
}

stock RemoveReportFromQueue(queue_index)
{
    if(!ReportQueue[queue_index][repActive]) return 0;
    
    // Ștergem din baza de date
    DeleteReportFromDatabase(ReportQueue[queue_index][repDatabaseID]);
    
    // Resetăm variabila per jucător dacă este online
    new target = ReportQueue[queue_index][repSenderID];
    if(target != INVALID_PLAYER_ID && IsPlayerConnected(target)) {
        HasActiveReport[target] = false;
    }
    
    // Resetăm slotul și rearanjăm coada (FIFO)
    ResetReportSlot(queue_index);
    TotalReports--;
    ReorderQueue();
    return 1;
}

stock ReorderQueue()
{
    new tempQueue[MAX_REPORTS][E_REPORT_DATA];
    new count = 0;
    
    for(new i = 0; i < MAX_REPORTS; i++) {
        if(ReportQueue[i][repActive]) {
            tempQueue[count] = ReportQueue[i];
            count++;
        }
    }
    
    for(new i = 0; i < MAX_REPORTS; i++) {
        if(i < count) {
            ReportQueue[i] = tempQueue[i];
        } else {
            ResetReportSlot(i);
        }
    }
    TotalReports = count;
}

// ---- Comenzi Jucători (Pawn.CMD) ----

cmd:report(playerid, params[])
{
    if(HasActiveReport[playerid]) {
        return SendClientMessage(playerid, COLOR_RED, "Eroare: Ai deja un raport activ în coadă. Te rugăm să aștepți.");
    }
    
    ShowPlayerDialog(playerid, DIALOG_REPORT_MAIN, DIALOG_STYLE_LIST, 
        "{FFFFFF}Sistem de Raportare", 
        "1. Raportează un Codat / Hacker\n2. Raportează limbaj / jigniri\n3. Am blocat / Am nevoie de ajutor (Unstuck)\n4. Altă problemă (Scrie text manual)", 
        "Selectează", "Închide"
    );
    return 1;
}
alias:report("rep");

// ---- Comenzi Administratori (Pawn.CMD) ----

cmd:ar(playerid, params[]) 
{
    if(!IsPlayerAdminEx(playerid)) return SendClientMessage(playerid, COLOR_RED, "Nu ai permisiunea de a folosi această comandă.");
    if(PlayerUnderReport[playerid] != INVALID_PLAYER_ID) return SendClientMessage(playerid, COLOR_RED, "Eroare: Procesezi deja un raport! Folosește /cr pentru a-l închide.");
    if(TotalReports == 0) return SendClientMessage(playerid, COLOR_RED, "Nu există rapoarte active în coadă în acest moment.");
    
    new queueIndex = 0; 
    new inputIndex;

    if(!sscanf(params, "d", inputIndex)) {
        inputIndex = inputIndex - 1; 
        if(inputIndex >= 0 && inputIndex < TotalReports && ReportQueue[inputIndex][repActive]) {
            queueIndex = inputIndex;
        } else {
            return SendClientMessage(playerid, COLOR_RED, "Poziție invalidă în coadă. Folosește /reports pentru listă.");
        }
    }

    new targetid = ReportQueue[queueIndex][repSenderID];
    new reason[REASON_LENGTH];
    format(reason, sizeof(reason), "%s", ReportQueue[queueIndex][repReason]);
    
    new adminName[MAX_PLAYER_NAME], str[256];
    GetPlayerName(playerid, adminName, sizeof(adminName));
    
    // Verificăm dacă jucătorul mai este pe server
    if(targetid == INVALID_PLAYER_ID || !IsPlayerConnected(targetid)) {
        format(str, sizeof(str), "{FFFFFF}Ai preluat raportul lui {FFFF00}%s{FFFFFF} (offline). Motiv: %s.", ReportQueue[queueIndex][repSenderName], reason);
        SendClientMessage(playerid, COLOR_GREEN, str);
        
        format(str, sizeof(str), "{33CCFF}[Admin] %s a eliminat raportul de la offline al lui %s. Motiv: %s", adminName, ReportQueue[queueIndex][repSenderName], reason);
        MessageToAdmins(COLOR_LIGHTBLUE, str);
        
        // Din moment ce este offline, doar curățăm raportul din listă/bază de date direct
        RemoveReportFromQueue(queueIndex);
        return 1;
    }
    
    // Jucătorul este online, începem conversația asistată
    PlayerUnderReport[playerid] = targetid;
    
    format(str, sizeof(str), "{FFFFFF}[REPORT] Adminul {FFFF00}%s{FFFFFF} ți-a acceptat raportul. Acesta va discuta cu tine acum.", adminName);
    SendClientMessage(targetid, COLOR_GREEN, str);
    
    format(str, sizeof(str), "{33CCFF}[Admin] %s a preluat raportul lui %s[%d]. Motiv: %s", adminName, ReportQueue[queueIndex][repSenderName], targetid, reason);
    MessageToAdmins(COLOR_LIGHTBLUE, str);
    
    format(str, sizeof(str), "{FFFFFF}Ai preluat raportul lui %s. Motiv: %s. Folosește /cr când ai terminat.", ReportQueue[queueIndex][repSenderName], reason);
    SendClientMessage(playerid, COLOR_GREEN, str);
    
    // Îl eliminăm din MySQL și din coada de așteptare deoarece un admin se ocupă acum de el
    RemoveReportFromQueue(queueIndex);
    return 1;
}

cmd:cr(playerid, params[]) 
{
    if(!IsPlayerAdminEx(playerid)) return SendClientMessage(playerid, COLOR_RED, "Nu ai permisiunea de a folosi această comandă.");
    if(PlayerUnderReport[playerid] == INVALID_PLAYER_ID) return SendClientMessage(playerid, COLOR_RED, "Nu ai niciun raport activ în desfășurare.");
    
    new targetid = PlayerUnderReport[playerid];
    new adminName[MAX_PLAYER_NAME], userName[MAX_PLAYER_NAME], str[128];
    GetPlayerName(playerid, adminName, sizeof(adminName));
    
    if(IsPlayerConnected(targetid)) {
        GetPlayerName(targetid, userName, sizeof(userName));
        format(str, sizeof(str), "{FFFFFF}[REPORT] Adminul {FFFF00}%s{FFFFFF} ți-a închis raportul. Sperăm că te-am ajutat!", adminName);
        SendClientMessage(targetid, COLOR_YELLOW, str);
        
        format(str, sizeof(str), "{FFFFFF}Ai închis cu succes raportul lui %s.", userName);
        SendClientMessage(playerid, COLOR_GREEN, str);
    } else {
        SendClientMessage(playerid, COLOR_GREEN, "Ai închis raportul curent (jucătorul era deconectat).");
    }
    
    PlayerUnderReport[playerid] = INVALID_PLAYER_ID;
    return 1;
}

cmd:reports(playerid, params[]) 
{
    if(!IsPlayerAdminEx(playerid)) return SendClientMessage(playerid, COLOR_RED, "Nu ai permisiunea de a folosi această comandă.");
    if(TotalReports == 0) return SendClientMessage(playerid, COLOR_RED, "Nu există rapoarte active în coadă.");
    
    new dialogStr[1024], lineStr[150];
    format(dialogStr, sizeof(dialogStr), "Poziție\tJucător\tStare\tMotiv\n");
    
    for(new i = 0; i < MAX_REPORTS; i++) {
        if(ReportQueue[i][repActive]) {
            if(ReportQueue[i][repSenderID] != INVALID_PLAYER_ID && IsPlayerConnected(ReportQueue[i][repSenderID])) {
                format(lineStr, sizeof(lineStr), "#%d\t%s (%d)\t{00FF00}Online{FFFFFF}\t%s\n", i+1, ReportQueue[i][repSenderName], ReportQueue[i][repSenderID], ReportQueue[i][repReason]);
            } else {
                format(lineStr, sizeof(lineStr), "#%d\t%s\t{FF0000}Offline{FFFFFF}\t%s\n", i+1, ReportQueue[i][repSenderName], ReportQueue[i][repReason]);
            }
            strcat(dialogStr, lineStr);
        }
    }
    
    ShowPlayerDialog(playerid, DIALOG_REP_LIST, DIALOG_STYLE_TABLIST_HEADERS, "{FFFFFF}Listă Coadă Rapoarte (MySQL)", dialogStr, "Acceptă primul", "Închide");
    return 1;
}

// ---- Dialoguri ----

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    if(dialogid == DIALOG_REPORT_MAIN)
    {
        if(!response) return 1;
        
        switch(listitem)
        {
            case 0: SendReportToQueue(playerid, "Posibil codat / hacker (necesită spectate)");
            case 1: SendReportToQueue(playerid, "Limbaj vulgar / Jigniri / Spam");
            case 2: SendReportToQueue(playerid, "Am rămas blocat (solicit unstuck / flip)");
            case 3: {
                ShowPlayerDialog(playerid, DIALOG_REPORT_TEXT, DIALOG_STYLE_INPUT, 
                    "{FFFFFF}Raport - Detalii manuale", 
                    "Te rugăm să descrii problema ta cât mai detaliat posibil în căsuța de mai jos:", 
                    "Trimite", "Înapoi"
                );
            }
        }
        return 1;
    }
    
    if(dialogid == DIALOG_REPORT_TEXT)
    {
        if(!response) return PC_ExecuteCommand(playerid, "/report"); 
        
        if(strlen(inputtext) < 5 || strlen(inputtext) > 120) {
            SendClientMessage(playerid, COLOR_RED, "Eroare: Textul raportului trebuie să aibă între 5 și 120 de caractere.");
            return PC_ExecuteCommand(playerid, "/report");
        }
        
        SendReportToQueue(playerid, inputtext);
        return 1;
    }
    
    if(dialogid == DIALOG_REP_LIST)
    {
        if(response) {
            PC_ExecuteCommand(playerid, "/ar"); 
        }
        return 1;
    }

    return 0;
}

 

  • Upvote 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more details you can also review our Terms of Use and Privacy Policy.