[Guía] Hacer un sistema de cuentas SQLite
#1
Buenas tardes, esta es mi primera guía, les voy a explicar como hacer un sistema de cuentas con autologueo por IP, guardar / cargar datos, etc.

PD: Si hay alguna función que está mal echa, por favor comentarla.

• Módulos requeridos:
Código PHP:
#include <sqlx>
#include <amxmisc> 

• Definimos la base de datos & la tabla:
Código PHP:
// TABLA Y BASE DE DATOS
#define SQL_TABLE "SQL_MyTable"
#define SQL_DATABASE "SQL_DBTest" 

• Variables que serán utilizadas:
Código PHP:
new g_user_name[33][32]; // NOMBRE DEL USUARIO - SERÁ UNA CADENA DE 32 DÍGITOS.
new g_user_password[33][32]; // CONTRASEÑA DEL USUARIO - SERÁ UNA CADENA DE 32 DÍGITOS.
new g_user_register[33]; // ESTADO DEL USUARIO (SI ESTÁ REGISTRADO O NO).
new g_user_logged[33]; // ESTADO DEL USUARIO (SI ESTÁ LOGUEADO O NO).
new g_user_auto_logged[33]; // ESTADO DEL USUARIO (SI ESTÁ AUTOLOGUEADO O NO).
new g_user_id[33]; // ID DEL USUARIO.
new g_user_date_register[33][32]; // FECHA DE REGISTRO.
new g_user_last_date[33][32]; // ÚLTIMO INGRESO DEL USUARIO AL SERVIDOR.
new g_frags[33]; // FRAGS DEL USUARIO.
new g_death[33]; // MUERTES DEL USUARIO.

new Handle:g_sql_connection// Variable que abrirá conexión con la base de datos.
new Handle:g_sql_htuple// Variable que almacenará información de la conexión (No se conecta a la base de datos). 

• Funciones al comienzo del plugin plugin_init():
Código PHP:
public plugin_init()
{
    
register_plugin("[GUÍA] System Account""1.0""Cristian'");
    
    
register_clcmd("chooseteam""clcmd_changeteam");
    
register_clcmd("jointeam""clcmd_changeteam");
    
register_clcmd("REGISTRAR_PASSWORD""clcmd_messagemode");
    
register_clcmd("CONFIRMAR_PASSWORD""clcmd_messagemode");
    
register_clcmd("INGRESAR_PASSWORD""clcmd_messagemode");
    
    
register_clcmd("say /frags""clcmd_frags");
    
    
register_forward(FM_ClientUserInfoChanged"fm_ClientUserInfoChanged"); // Evitamos que el usuario se cambie de nombre.
    
    
register_event("HLTV""event_HLTV""a""1=0""2=0");
    
register_event("DeathMsg""event_DeathMsg""a");
    
    
g_maxplayers get_maxplayers(); // Obtenemos en la variable g_maxplayers la cantidad de clientes que hay en el servidor
    
    
sqlx_init(); // Llamamos a la función que conectará la base de datos y creará la tabla.


• Función cuando el usuario se conecta al servidor client_putinserver():
Código PHP:
public client_putinserver(id)
{
    
// Reseteamos sus valores
    
get_user_name(idg_user_name[id], 31);
    
    
g_user_register[id] = 0;
    
g_user_logged[id] = 0;
    
g_user_auto_logged[id] = 0;
    
g_frags[id] = 0;
    
g_death[id] = 0;
    
    
g_user_password[id][0] = EOS;
    
g_user_date_register[id][0] = EOS;
    
g_user_last_date[id][0] = EOS;
        
    
set_task(0.1"user_check"id); // Llamamos a la función "user_check" en un lapso de 0.1 segundos para seleccionar los datos del usuario que ingresó al servidor.


• Función cuando el usuario se desconecta del servidor client_disconnect():
Código PHP:
public client_disconnect(id)
{
    
// Si el usuario logueado se desconecta del servidor, llamamos a la función que ejecutará la consulta para guardar sus datos.
    
if (g_user_logged[id])
    {
        
save_data(id);
        
g_user_logged[id] = 0;
    }    


• Evento registrado del HLTV register_event("HLTV", "event_HLTV", "a", "1=0", "2=0")():
Código PHP:
public event_HLTV()
{
    new 
id;
    
    for (
id 1id <= g_maxplayersid++)
    {
        if (
g_user_logged[id]) // Si el usuario está logueado, le  guardamos sus datos.
            
save_data(id); // Si es una nueva ronda, llamamos a la función que ejecutará la consulta para guardar sus datos.
    
}


• Llamamos a la función registada en client_putinserver user_check(id):
Código PHP:
/*
    * Lógica de la consulta: SELECCIONAR id, password, ip, date_register, last_date DE 'tabla' DONDE name = 'mi_name';
    * El ";" es utilizado para separar las consultas.
    
*/

public user_check(id)
{
    if (!
is_user_connected(id)) // Si no está conectado detenemos el complemento.
        
return PLUGIN_HANDLED;
    
    
// Preparamos la consulta
    
new Handle:query;
    
query SQL_PrepareQuery(g_sql_connection"SELECT id, password, ip, date_register, last_date FROM '%s' WHERE name = ^"%s^";"SQL_TABLEg_user_name[id]);
    
    
// Ejecutamos la consulta que anteriormente preparamos (SQL_PrepareQuery).
    
if (!SQL_Execute(query)) // Si la consulta no es válida 
    
{
        
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
        
sql_query_error(idquery);
    }
    else if (
SQL_NumResults(query)) // Si la consulta arroja resultados
    
{
        
/*
            * Si seleccionamos los datos individualmente y no todos (*) el SQL_ReadResult comenzaría en 0.
            * Ejemplo: SELECT id, password, ip, date_register, last_date (0, 1, 2, 3, 4).
        */
        
        
g_user_register[id] = 1// Ponemos que el usuario está registrado.
        
        
new ip[21], dbip[21];
        
get_user_ip(idip201); // Obtenemos la IP del usuario.
        
        
g_user_id[id] = SQL_ReadResult(query0); // Obtenemos el ID del usuario de la base de datos.
        
SQL_ReadResult(query1g_user_password[id], 31);  // Obtenemos la CONTRASEÑA de la base de datos que luego será verificada al ingresar la contraseña en una nueva cadena.
        
SQL_ReadResult(query2dbip20); // Obtenemos la IP de la base de datos.
        
SQL_ReadResult(query3g_user_date_register[id], 31); // Obtenemos la fecha de registro de la base de datos.
        
SQL_ReadResult(query4g_user_last_date[id], 31); // Obtenemos la última vez que ingresó de la base de datos.
        
        
if (equali(ipdbip)) // Si la IP del USUARIO es igual a la IP de la BASE DE DATOS.
            
g_user_auto_logged[id] = 1// Ponemos que está auto logueado.
        
        
        
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
    
}
    else 
        
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
    
    
clcmd_changeteam(id);
    return 
PLUGIN_HANDLED;


• Llamamos a la función de selección de equipos chooseteam / jointeam:
Código PHP:
public clcmd_changeteam(id)
{
    
/* ========================= */
    // SI EL USUARIO ESTÁ LOGUEADO, HACEMOS QUE EL COMPLEMENTO DE LA FUNCIÓN DE ELECCIÓN DE EQUIPO CONTINÚE CON NORMALIDAD.
    
if (g_user_logged[id])
        return 
PLUGIN_CONTINUE;
    
/* ========================= */
    
    /* ========================= */
    /*
        * COMO HEMOS DICHO ANTERIORMENTE, SI EL USUARIO ESTABA LOGUEADO (VER ARRIBA) CONTINUAMOS EL VALOR DE LA FUNCIÓN CON NORMALIDAD.
        * SI NO LO ESTÁ, LE MOSTRAMOS EL REGISTRO Y DETENEMOS EL COMPLEMENTO DE DICHA FUNCIÓN.
    */
    
    
show_menu_register(id); // Función que tendrá el registro del usuario.
    
return PLUGIN_HANDLED// Detiene le complemento de la función.


• Función de registro:
Código PHP:
show_menu_register(id)
{
    static 
menusztext[128];
    
menu menu_create("\yMENÚ DE REGISTRO""handled_show_menu_register");
    
    if (!
g_user_auto_logged[id]) // Si el usuario no está auto logueado, le mostramos el registro
    
{
        
menu_additem(menu"REGISTRARSE""1"_menu_makecallback("menu_makecallback_register"));
        
menu_additem(menu"LOGUEARME""2"_menu_makecallback("menu_makecallback_login"));
    }
    else
        
menu_additem(menu"INGRESAR AL SERVIDOR""1");
        
    
    if (
g_user_register[id]) // Si el usuario está registrado le mostramos el número de #REGISTRO de su cuenta, la fecha de registro y el último ingreso.
    
{
        
format(sztext127"^n\wCuenta número: \y#%d^n^n\wFecha de registro: \y%s^n\wÚltimo ingreso al servidor: \y%s"
        
g_user_id[id], g_user_date_register[id], (g_user_last_date[id][0]) ? g_user_last_date[id] : "-");
        
menu_addtext(menusztext);
    }
    
    
menu_setprop(menuMPROP_EXIT, -1);
    
    
menu_display(idmenu, .page 0, .time = -1);
}

public 
menu_makecallback_register(idmenuitem)
    return (
g_user_register[id]) ? ITEM_DISABLED ITEM_ENABLED;

public 
menu_makecallback_login(idmenuitem)
    return (
g_user_register[id]) ? ITEM_ENABLED ITEM_DISABLED;    
    
public 
handled_show_menu_register(idmenuitem)
{
    switch(
item)
    {
        case 
MENU_EXIT
        {
            
menu_destroy(menu); 
            return 
PLUGIN_HANDLED;
        }
        case 
0
        {
            if (
g_user_auto_logged[id])
            {
                
enter_user(id);
                return 
PLUGIN_HANDLED;
            }
            
            
client_cmd(id"messagemode REGISTRAR_PASSWORD"), g_messagemode[id] = REGISTRAR_PASSWORD;
        }
        case 
1client_cmd(id"messagemode INGRESAR_PASSWORD"), g_messagemode[id] = INGRESAR_PASSWORD;
    }
    
    
menu_destroy(menu);
    return 
PLUGIN_HANDLED;


• Función de los messagemodes registrados en plugin_init que interactúan con la registro / logueo:
Código PHP:
public clcmd_messagemode(id)
{
    
/* ================================================= */
        /*
            VERIFICAMOS QUE EL USUARIO ESTÉ LOGUEADO 
            PARA EVITAR QUE PUEDA BUGUEAR LOS MESSAGEMODES 
            (REGISTRARSE / LOGUEARSE) A TRAVÉS DE CONSOLA.
            EN CASO DE ESTARLO, DETENEMOS EL COMPLEMENTO 
            DE LA FUNCIÓN.
        */
    /* ================================================= */
    
    
if (g_user_logged[id])
        return 
PLUGIN_HANDLED;
    
    static 
args[28];
    
read_args(args27); // Obtenemos la cadena que puso en consola. 
    
remove_quotes(args); // Removemos las comillas "".
    
trim(args); // Eliminamos los espacios en blanco del principio a final de la cadena.
    
    
switch(g_messagemode[id])
    {
        case 
REGISTRAR_PASSWORD:
        {
            
// Verificamos que el usuario esté registrado para detener el complemento de la función.
            
if (g_user_register[id])
                return 
PLUGIN_HANDLED;
            
            
// Calculamos la longitud de la cadena introducda, en este caso si la cadena posee menos de 4 dígitos
            // detenemos el complemento.
            
if (strlen(args) < 4)
            {
                
client_print(idprint_center"LA CONTRASEÑA DEBE CONTENER MÁS DE 4 DÍGITOS");
                return 
PLUGIN_HANDLED;
            }
            
            
// Si puso más de 4 dígitos, hacemos que confirme su contraseña.
            
g_messagemode[id] = CONFIRMAR_PASSWORD;
            
client_cmd(id"messagemode CONFIRMAR_PASSWORD");
            
copy(g_user_password[id], 31args);
        }
        case 
CONFIRMAR_PASSWORD:
        {
            
// Verificamos que el usuario esté registrado para detener el complemento de la función.
            
if (g_user_register[id])
                return 
PLUGIN_HANDLED;
            
            
// Verificamos si la contraseña que introdujo sea igual a la que puso al REGISTRAR_PASSWORD.
            // Si no es igual, detenemos el complemento de la función.
            
if (!equali(g_user_password[id], args))
            {
                
client_print(idprint_center"La contraseña introducia no coincide");
                return 
PLUGIN_HANDLED;
            }
            
            
// Si no se detuvo el complemento anteriormente (LA CONTRASEÑA ES IGUAL), insertamos sus datos en la base de datos.
            
            /*
                * INSERT INTO: Se utiliza para insertar un nuevo registro en la tabla.
                * Quedaría de esta manera la lógica: INSERTAR EN 'tabla' (columna1, column2, column3) VALORES (valor1, valor2, valor3); 
            */
            
            // Preparamos la consulta, que contendrá el nombre, la contraseña, y la fecha de registro
            
new Handle:querytime[32];
            
get_time("%d/%m/%Y - %H:%M:%S"time31); // Obtenemos la fecha %days/%month/%year - %hour:%minutes/%seconds
            
            
query SQL_PrepareQuery(g_sql_connection"INSERT INTO '%s' (name, password, date_register) VALUES (^"%s^", ^"%s^", ^"%s^")"
            
SQL_TABLEg_user_name[id], g_user_password[id], time);
        
            
// Ejecutamos la consulta que anteriormente preparamos (SQL_PrepareQuery).
            
            
if (!SQL_Execute(query)) // Si la consulta ejecutada no es válida.
            
{
                
sql_query_error(idquery);
                
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
            
}
            else 
// Si es válida
            
{
                
SQL_FreeHandle(query); // Liberamos el identificador de la consulta para realizar otra.
                
                // Preparamos la consulta para seleccionar el ID del usuario.
                
query SQL_PrepareQuery(g_sql_connection"SELECT id FROM '%s' WHERE name = ^"%s^""SQL_TABLEg_user_name[id]);
                
                if (!
SQL_Execute(query)) // Si la consulta no es válida.
                
{
                    
sql_query_error(idquery);
                    
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
                
}
                else if (
SQL_NumResults(query)) // Si la consulta arroja resultados
                
{
                    
// Obtenemos en la variable g_user_id el #ID del usuario para que se autoincremente 
                    // y no se buguee al guardar sus datos ya que estamos guardando sus datos por el #ID
                    // y por defecto la variable del #ID del usuario es 0.
                    
                    
g_user_id[id] = SQL_ReadResult(query0);
                    
                    
g_user_register[id] = 1// Si el usuario se registró con éxito, ponemos que está registrado.
                    
g_user_logged[id] = 1// Si el usuario se registró con éxito, ponemos que está logueado.
                    
                    
chat_color(id"%s !yBienvenido !t%s!y, sos la cuenta registrada número !g#%d!y."SZPREFIXg_user_name[id], g_user_id[id]);
                    
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
                
}
                else
                    
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
            
}
        }
        case 
INGRESAR_PASSWORD:
        {
            
// Verificamos que el usuario no esté registrado para detener el complemento de la función.
            
if (!g_user_register[id])
                return 
PLUGIN_HANDLED;
            
            
// Si la contraseña que puso no es igual a la contraseña cargada, detenemos el complemento
            
if (!equali(g_user_password[id], args))
            {
                
chat_color(id"%s !yTu contraseña no coincide."SZPREFIX);
                return 
PLUGIN_HANDLED;
            }
            
            
enter_user(id); // Función que lo hará ingresar al servidor.
        
}
    }
    
    
    
client_cmd(id"chooseteam");
    return 
PLUGIN_HANDLED;


• Llamamos a la función enter_user registrada cuando el usuario puso correctamente su contraseña:
Código PHP:
enter_user(id)
{
    
// Preparamos la consulta.
    
new Handle:queryip[21], time[32];
    
    
get_time("%d/%m/%Y - %H:%M:%S"time31); // Obtenemos la fecha %days/%month/%year - %hour:%minutes/%seconds
    
get_user_ip(idip211); // Obtenemos la ip del usuario
    
    // Preparamos la consulta para guardar su ip y la fecha de ingreso.
    
query SQL_PrepareQuery(g_sql_connection"UPDATE '%s' SET last_date = ^"%s^", ip = ^"%s^" WHERE id = '%d';"SQL_TABLEtimeipg_user_id[id]);
    
    if (!
SQL_Execute(query)) // Si la consulta no es válida.
    
{
        
sql_query_error(idquery);
        
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
    
}
    else 
// Si es válida, liberamos el identificador de la consulta.
        
SQL_FreeHandle(query);
        
    
g_user_logged[id] = 1// Si el usuario puso su contraseña correctamente, ponemos que está logueado y le cargamos sus datos.
    
chat_color(id"%s !yBienvenido !g%s!y."SZPREFIXg_user_name[id]);
    
load_data(id); // Llamamos a la función que ejecutará la consulta y cargará sus datos.
    
    
client_cmd(id"chooseteam");


• Función que guardarán / cargarán sus datos :
• Función de guardar:
Código PHP:
save_data(id)
{
    
/*
        * UTILIZAMOS ThreadQuery PARA GUARDAR SUS DATOS
        * YA QUE PrepareQuery CORRE CON EL MISMO PROCESO 
        * DEL SERVIDOR Y PUEDE GENERAR QUE SE CONGELE.
    */
    
    
    /*
        * PREPARAMOS LA CONSULTA, UTILIZAMOS LA TUPLA QUE NOS DEVOLVIÓ SQL_MakeDbTuple().
        SQL_ThreadQuery(Handle:Tupla, "función", "consulta", index);
    */
    
    
    
static save[128], data[2];
    
data[0] = id
    
data[1] = 1;

    
/*
        * Lógica de la consulta: ACTUALIZAR 'mi_tabla' CONJUNTO frags = '%d', deaths = '%d' DONDE id = '%d';
        * El ";" es utilizado para separar consultas.
    
    */
    
    
format(save127"UPDATE '%s' SET frags = '%d', deaths = '%d' WHERE id = '%d';"SQL_TABLEg_frags[id], g_death[id], g_user_id[id]);
    
    
SQL_ThreadQuery(g_sql_htuple"SQL_DataHandled"savedata2);
}


public 
SQL_DataHandled(failstateHandle:queryerror[], errnumdata[], sizeFloat:queutime)
{
    
/* 
        * failstate: Una de las 3 consultas lo define.
            - TQUERY_CONNECT_FAILED.
            - TQUERY_QUERY_FAILED.
            - TQUERY_SUCCESS.
        
        * Handle:query: Maneja la consulta, no debe ser liberada.
        * const error[]: Devuelve un mensaje de error si es que lo hay.
        * errnum: Devuelve un código de error si es lo que hay.
        * const data[]: matriz de datos ingresados.
        * size: tamaño de la matriz ingresada,
        * queutime: El tiempo que pasó mientras la consulta era ejecutada.
    */
    
    
    
if (failstate == TQUERY_CONNECT_FAILED || failstate == TQUERY_QUERY_FAILED)
    {
        
sql_query_error(data[0], query);
        return 
PLUGIN_HANDLED;
    }
    
    if (
data[1])
    {
        if (
failstate != TQUERY_SUCCESS// Si el failstate no es igual 0 (TQUERY_SUCCESS) detenemos el complemento.
            
return PLUGIN_HANDLED;
        
        
chat_color(data[0], "%s !yTus datos fueron almacenados."SZPREFIX);
    }
    
    return 
PLUGIN_HANDLED;

• Función de cargar:
Código PHP:
load_data(id)
{
    
/*
        * Lógica de la consulta: SELECCIONAR * (TODO) DE 'tabla' DONDE id = 'mi_id';
        * El ";" es utilizado para separar las consultas.
    
    */
    
    // Preparamos la consulta y cargamos sus datos por el ID del usuario
    
new Handle:query;
    
query SQL_PrepareQuery(g_sql_connection"SELECT * FROM '%s' WHERE id = '%d';"SQL_TABLEg_user_id[id]);
    
    
// Ejecutamos la consulta que anteriormente preparamos (SQL_PrepareQuery).
    
if (!SQL_Execute(query)) // Si la consulta no es válida 
    
{
        
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
        
sql_query_error(idquery);
    }
    else if (
SQL_NumResults(query)) // Si la consulta arroja resultados 
    
{
        
/*
            NOTA: Al seleccionar todos los datos (*), si solamente queremos obtener los frags y muertes del usuario.
            deberíamos tener en cuenta las columnas anteriores, Un pequeño ejemplo numérico de nuestra tabla:
            
            ID = 0,
            NOMBRE = 1
            PASSWORD = 2
            DATE_REGISTER = 3
            LAST_DATE = 4
            IP = 5
            FRAGS = 6
            DEATHS = 7
        */
        
        // Cargamos sus datos
        
g_frags[id] = SQL_ReadResult(query6); // Recuperamos en la variable g_frags el resultado actual de la columna Nº 6.
        
g_death[id] = SQL_ReadResult(query7); // Recuperamos en la variable g_death el resultado actual de la columna Nº 7.
        
        
SQL_FreeHandle(query); // Liberamos el identificador de la consulta.
    
}    
    else 
// Si no arroja resultados, liberamos el identificador de la consulta.
        
SQL_FreeHandle(query);


• Llamamos a la función registrada en plugin_init() - sqlx_init:
Código PHP:
sqlx_init()
{
    new 
errorerrorcode[128];
    
    
// Si el módulo sqlite no está cargado, detenemos el complemento.
    
if (!module_exists("sqlite"))
    {
        
log_to_file("SQL_Module.txt""El módulo ^"sqlite^" es necesario."SZPREFIX);
        return 
PLUGIN_HANDLED;
    }
    
    
/* SQL_MakeDbTuple
    (
        "", | Base de datos host.
        "", | Usuario de la base de datos.
        "", | Contraseña de la base de datos.
        SQL_DATABASE, | Nombre de la base de datos.
        TIMEOUT | Tiempo de espera de la conexión antes de cerrarse.
    );
        
    */
    
g_sql_htuple SQL_MakeDbTuple(""""""SQL_DATABASE, .timeout 0); // Creamos una tupla de información de conexión.
    
    
    /* SQL_Connect
    (
        Handle:tupla, | INFORMACIÓN DE CONEXIÓN DEVUELTA POR SQL_MakeDbTuple
        error, | Cadena donde se almacenará la cadena error.
        errorcode, | Código del error.
        127, | Longitud de la cadena.
    )
    */
    
g_sql_connection SQL_Connect(g_sql_htupleerrorerrorcode127); // Abrimos una conexión  con la base de datos.
    
    
if (g_sql_htuple == Empty_Handle)
    {
        
log_to_file("SQL_Htuple.txt""Error en la tupla");
        return 
PLUGIN_HANDLED;
    }
    
    if (
g_sql_connection == Empty_Handle)
    {
        
log_to_file("SQL_Connection.txt""Error al conectar base de datos %s (%s)"errorerrorcode);
        return 
PLUGIN_HANDLED;
    }
    
    
/*
        Preparamos la consulta que creará nuestra tabla (No es recomendable hacerlo dentro del plugin, para eso existen varios programas).
        
        * INTEGER: Permite números enteros.
        * PRIMARY KEY: Identifica de forma única cada registro en una tabla de base de datos.
        * AUTOINCREMENT: Permite que se genere automáticamente un número  cuando se inserta un registro, en este caso se genera el campo #ID.
        * UNIQUE: Asegura que todos los valores de una columna sean diferentes, al igual que la restricción PRIMARY KEY, en este caso el NOMBRE.
        * VARCHAR: Permite una cadena de carácteres.
    */
    
    
new Handle:query;
    
query SQL_PrepareQuery
    
(
        
g_sql_connection
        
"CREATE TABLE IF NOT EXISTS '%s'  \
        ( \
            id INTEGER PRIMARY KEY AUTOINCREMENT, \
            name VARCHAR(32) NOT NULL UNIQUE, \
            password VARCHAR(32) NOT NULL, \
            date_register VARCHAR(32) NOT NULL DEFAULT '', \
            last_date VARCHAR(32) NOT NULL NOT NULL DEFAULT '', \
            ip VARCHAR(21) NOT NULL DEFAULT '', \
            frags INTEGER NOT NULL DEFAULT '0', \
            deaths INTEGER NOT NULL DEFAULT '0' \
        )"
SQL_TABLE
    
);
    
    if (!
SQL_Execute(query))
    {
        
sql_query_error(0query);
        
SQL_FreeHandle(query);
    }
    else
        
SQL_FreeHandle(query);
    
    return 
PLUGIN_HANDLED;

[spoiler]

• Liberamos la conexión y la información obtenida por la tupla:
[spoiler]
Código PHP:
public plugin_end()
{
    
SQL_FreeHandle(g_sql_connection); // Liberamos la conexión.
    
SQL_FreeHandle(g_sql_htuple); // Liberamos la información obtenida.



Archivos adjuntos
.sma   Descargar AMXX / tut_system_account.sma (Tamaño: 21.78 KB / Descargas: 40)
Responder
#2
Bonita guía. Crab
No contesto mensajes de soporte. Pregunta en los foros.
Si buscas algún trabajo privado (Pago), envíame un MP.
Responder
#3
Muy buena guía Proud

Hay una linea que me tira error al compilarlo sin modificaciones, nose si es por la versión del amx o le falta algo..

Cita:Error: Undefined symbol "time" on line 220

Código PHP:
menu_display(idmenu, .page 0, .time = -1); 
Responder
#4
tengo dos dudas.

public plugin_end()
{
SQL_FreeHandle(g_sql_connection); // Liberamos la conexión.
SQL_FreeHandle(g_sql_htuple); // Liberamos la información obtenida.
}

no te trae problemas al cambiar de mapa en un servidor?

SQL_SetAffinity por que no lo usas?
futuro ingeniero agrónomo.

tutoriales-allied
buscas un zp?

"La imitación es la forma más sincera de admiración con la que puede pagar la mediocridad a la grandeza"

volví a vender plugins, contactame
Responder
#5
Rainbow Buen tutorial.

Proud Esta bueno para aquellos que quieren saber como usar el sistema de guardado SQlite.
[Imagen: jrXxqRT.png]
*Maper Del Cstrike* - *Estudiante De Sistema*
(03/09/2018, 08:32 PM)Skylar escribió: Obviamente, no va a hablar con super pro para que le mueva el thread
(04/01/2019, 05:12 PM)Pan Bimbo (? escribió: QUE HICISTE QUE??????? YO QUERIA LA PLACA DE VIDEO PORQUE LA TIRASTE CTM
(15/01/2019, 04:08 AM)FreDDy escribió:
(15/01/2019, 03:45 AM)Hernandez escribió: Qué más dan las palabras si a donde vayas están en tetas protestando sin sentido

No todas salen en tetas y no todas protestan sin sentido. Estás generalizando algo que sólo unas pocas lo hacen a diferencia de las muchas que realmente tienen un motivo para protestar.
(17/01/2019, 12:34 PM)totopizza escribió: el orden de los factores no altera el producto xD
(23/01/2019, 01:10 AM)GoldenCosta escribió:
Cita:E visto que este ZP , ESTA AQUI EN EL FORO PERO NO ES EL ORIGINAL POR QUE? , LE FALTAN MILES DE COSAS ESTA BUGEADO , LE FALTAN CÓDIGOS NI SE IMAGINAN , BUENO EL MOD ESTE SE VENDE POR 70 DOLARES , ACEPTO PAYPAL Y EN PESOS CHILENOS $42.584
ya esta publicado.... y 70 us en arg son 2625,35 pesos... estas loco con esa guita neel mantiene el foro por 2 años
(23/01/2019, 01:17 AM)Skylar escribió:
(22/01/2019, 10:30 PM)el_juan_fail escribió:
(22/01/2019, 10:03 AM)Neeeeeeeeeel.- escribió: Por favor subir las cosas al foro y no links a blogs externos. Solamente en caso de que haya recursos que no se pudiesen subir por un tema de tamaño, poenr un link de descarga directo (tipo mega) de los recursos y subir los plugins y demás archivos livianos al foro.

deberia ponerle en un link mediante el mediafire o mega o link externo lo que sea pero no es bueno dejar cosa agregada sin descargar solo por el blog no se puede se puede bajar el recurso o que haya sido creado disculpa neeeeel. estaba leyendose las reglas u.uMario

Dijiste lo mismo que dijo Neeel!
(27/02/2019, 08:00 PM)Sugisaki escribió:
(27/02/2019, 05:37 PM)Pan Bimbo (? escribió:
(27/02/2019, 12:06 AM)luxor xD escribió: Hola, si precacheo algo en un plugin, no es necesario precachearlo en otro plugin?

Si yo cargo una caja en un camion, mi amigo puede cargar la MISMA caja en el camion?, y no porque ya esta cargada.
[R]ak escribió: Mis conocimientos aumentaron un 500% con este post
(14/03/2019, 10:26 PM)KrR10VnZl escribió: en Venezuela aprendes a ser desde bombas molotov hasta velas, es algo así como supervivencia al desnudo jaja
(18/04/2019, 11:04 PM)Jose88 escribió:
(18/04/2019, 09:55 PM)Hypnotize escribió: arriba marica

papa me va perdonar pero aquí no sale ningún download. solo sale esto

Código PHP:
PDNiños Ratas eviten sacar el autor jaja.
REMOVIDO POR TUTOR Y SLOWHACK
(21/04/2019, 09:38 AM)SHENK! =D escribió: ASDASD

Si nos organizamos cojemos todos.
(11/08/2019, 05:11 PM)Cr3470r escribió: Todo Software es crackeable ... No importa cuantas validaciones hagan, la ventaja siempre la tenemos nosotros ...
(28/07/2015, 09:34 PM)Nazi.- escribió: :ohgodwhy buen aporte

PD: situación sentimental: Sin internetOh god why

Sigue así Proud

(28/02/2020, 12:23 AM)Skylar escribió:
(27/02/2020, 11:28 PM)4evergaming escribió: Ya me puse como autor y lo subi a mi empresa


Abrazos

FIX
Responder
#6
(20/07/2018, 06:28 PM)warrior escribió: Muy buena guía Proud

Hay una linea que me tira error al compilarlo sin modificaciones, nose si es por la versión del amx o le falta algo..

Cita:Error: Undefined symbol "time" on line 220

Código PHP:
menu_display(idmenu, .page 0, .time = -1); 

Código PHP:
menu_display(idmenu, .page 0, .time = -1); 

------>

Código PHP:
menu_display(idmenu, .page 0); 

(20/07/2018, 06:35 PM)roccoxx escribió: tengo dos dudas.

public plugin_end()
{
SQL_FreeHandle(g_sql_connection); // Liberamos la conexión.
SQL_FreeHandle(g_sql_htuple); // Liberamos la información obtenida.
}

no te trae problemas al cambiar de mapa en un servidor?

SQL_SetAffinity por que no lo usas?

No me trae problemas al cambiar de mapa.

Código:
SQL_SetAffinity por que no lo usas?

El SQL_SetAffinity se utiliza para forzar un módulo en particular, en este caso el sqlite y cambiar automáticamente todos sus complementos para que estén "vinculados" a ese módulo. Por otro lado, solo es para seleccionar el módulo y cambiarlo.
Responder
#7
¿Por qué usas SQL_PrepareQuery y no SQL_ThreadQuery?
Responder
#8
Buena guia MarioMarioMario
[Imagen: giphy.gif]

[Imagen: 76561198874394515.png]
Responder
#9
(21/07/2018, 12:05 PM)Niper.-. escribió: ¿Por qué usas SQL_PrepareQuery y no SQL_ThreadQuery?

Usa ambos.
Pd https://amxmodx-es.com/Thread-Duda-Prepa...hreadQuery

Buen tuto
Responder
#10
(21/07/2018, 12:05 PM)Niper.-. escribió: ¿Por qué usas SQL_PrepareQuery y no SQL_ThreadQuery?

Utilizo PrepareQuery solamente para cargar, por que simplemente es obtener datos y no modificar la base de datos, en cambio al guardar varios datos estás almacenando datos nuevos en la base de datos cosa que si algo falla al guardarlos, si utilizas PrepareQuery, puede generar que se congele, ya que el servidor esperaría a que el SQL responda. Con ThreadQuery simplemente no te importaría el resultado. Esa sería mi opinión, no sé si estaré en lo cierto.

Por otro lado, actualicé el post por algunos cambios, errores de tipeos y spoiler. También resubí el archivo.
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)