- Introducción
Esta guía les dará una pequeña idea de como empezar a escribir plugins en SourceMod. Toda la redacción es de mi autoría, saque la idea y ejemplos de como armar el post de la guía original en la wiki de SourceMod (aquí). Quiero recalcar que al leer esta guía tienen conocimiento del lenguaje pawn, caso negativo les recomiendo leer esta guía.
Para empezar a escribir plugins necesitarán un editor de texto (en lo personal les recomiendo Notepad++). Para compilar plugins pueden usar el compilador web, más adelante les dejaré un post para compilarlos ustedes mismos.
- Inicio
Para empezar, abriremos un nuevo documento en blanco en Notepad++ o en el editor que esten usando. Comenzaremos como todo plugin, definiendo las librerías. En AMX Mod X, la default era amxmodx, aquí sera sourcemod:
Esta es la más común. Hay varias más para usar, por ejemplo sdktools que tiene muchas funciones útiles.
Para seguir definiremos el autor del plugin, descripción, versión, etc.
Hasta ahora tenemos el cuerpo principal de todo plugin, que será este:
- Funciones y eventos más comunes
La función mas usada es cuando es inicia el plugin (OnPluginStart). En ella definiremos CVARS, comandos de consola, hookeo de eventos, etc. Esta función es igual a la de AMX Mod X plugin_init.
Su estructura es muy simple y es esta:
Por ejemplo, registraremos un simple comando para admins:
Si queremos usarla seguramente nos dará un "Unknown command" por el simple hecho que no hay nada definido en la función. Lo que tenemos que hacer es devolver algún valor al llamarla. Para eso simplemente haremos un return PLUGIN_HANDLED para que simplemente ignore el comando. No hará nada pero de esta forma no arrojará ningún error.
Para utilizar los eventos hay que llamarlos previamente en PluginStart. Por ejemplo nosotros llamaremos al evento cuando spawnea un player:
- Llamado de comandos/funciones
En esta parte explicaremos el llamado de comandos, leyendo sus argumentos y mostrandoles como obtener sus valores.
El modo de uso de nuestro comando es el siguiente:
El primer argumento es el nombre o el id del player, el segundo es el daño que le aplicaremos.
- Menues
Este es un ejemplo sencillo de un menú, con su resultado final:
Ahora paso por paso les explicaré cada linea.
Por lógica, CreateMenu es la función para crear nuestro menú. El único parámetro que necesita es el nombre para el handler.
El segundo parámetro es para definir el título de nuestro menú. En el primer parámetro pondremos la variable que tiene alojado el menu que hayamos creado, el segundo parámetro es para poner el título.
AddMenuItem agrega los item al menu. En el primer parámetro pondremos el nombre de la variable que tiene alojado nuestro menú, el segundo parámetro es el identificador para luego utilizarlo en el handler y el tercero es el nombre del item que se mostrará en el menú.
Sirve para agregar una opción para salir del menú. El primer parámetro ya esta explicado, el segundo indicará si agregamos o no un botón para salir (true para agregarlo, false para no agregarlo).
El último parámetro es para mostrar el menú. El primer parámetro es la variable del menú, el segundo el ID del player al que se lo queremos mostrar y el tercer parámetro es cuanto tiempo queremos que le aparezca el menú (en segundos). Si se quiere mostrar para siempre (hasta que salga), agregaremos: MENU_TIME_FOREVER.
El Handler posee 4 parámetros. El primero es la variable que contiene el menú, el segundo es lo que hizo el usuario. Los action pueden ser:
El tercer parámetro (param1) contiene el ID del player al que se le mostró el menú, y el último parámetro contiene el número del item que eligió (empieza desde el 0).
GetMenuItem obtiene el número del item que el player eligió. El primer parámetro ya lo conocemos, el segundo también, el 3 y el 4 es donde se va a guardar el identificador del item. El identificador (por si no se acuerdan) es el segundo parámetro de AddMenuItem (AddMenuItem(menu, "yes", "Yes")). Lo que esta subrayado y en negrita, es lo que se guardará en info, por eso mismo siempre se guarda en un string.
- Timers
Para crear un timer, se hace uso de la función:
En donde el primer parámetro (en este caso 5.0), es el intervalo de tiempo, y el segundo es el nombre de la función a ejecutar cuando pase el intervalo de tiempo que hayamos puesto.
Ejemplo:
Para hacer un timer repetitivo, simplemente se agrega 1 parámetro mas. Acá un demostración simple si queremos mandar un mensaje 5 veces:
Para pasar datos a un timer, simplemente se los agregamos después del nombre de la función a ejecutar
- TakeDamageHook
El problema de SourceMod es que muchos eventos o funciones, no estan hookeadas por defecto. Entonces tenemos que hacer uso de extensiones creadas por usuarios de AM inglés para poder hookearlas.
Las mas usadas (y las que sugiero que usen), son: SDKHooks y SDKTools.
Por ejemplo, para hookear TakeDamage con SDKHooks:
En construcción... tarda tiempo traducir y armar el post.
Esta guía les dará una pequeña idea de como empezar a escribir plugins en SourceMod. Toda la redacción es de mi autoría, saque la idea y ejemplos de como armar el post de la guía original en la wiki de SourceMod (aquí). Quiero recalcar que al leer esta guía tienen conocimiento del lenguaje pawn, caso negativo les recomiendo leer esta guía.
Para empezar a escribir plugins necesitarán un editor de texto (en lo personal les recomiendo Notepad++). Para compilar plugins pueden usar el compilador web, más adelante les dejaré un post para compilarlos ustedes mismos.
- Inicio
Para empezar, abriremos un nuevo documento en blanco en Notepad++ o en el editor que esten usando. Comenzaremos como todo plugin, definiendo las librerías. En AMX Mod X, la default era amxmodx, aquí sera sourcemod:
Código PHP:
#include <sourcemod>
Esta es la más común. Hay varias más para usar, por ejemplo sdktools que tiene muchas funciones útiles.
Para seguir definiremos el autor del plugin, descripción, versión, etc.
Código PHP:
public Plugin:myinfo =
{
name = "Mi primer plugin",
author = "Yo",
description = "Mi primer plugin",
version = "1.0",
url = "http://www.amxmodx-es.com/"
};
Hasta ahora tenemos el cuerpo principal de todo plugin, que será este:
- Funciones y eventos más comunes
La función mas usada es cuando es inicia el plugin (OnPluginStart). En ella definiremos CVARS, comandos de consola, hookeo de eventos, etc. Esta función es igual a la de AMX Mod X plugin_init.
Su estructura es muy simple y es esta:
Código PHP:
public OnPluginStart()
{
// Todo lo que querramos registrar
}
Por ejemplo, registraremos un simple comando para admins:
Código PHP:
public OnPluginStart()
{
RegAdminCmd("sm_myslap", Command_MySlap, ADMFLAG_SLAY);
}
public Action:Command_MySlap(client, args)
{
}
Si queremos usarla seguramente nos dará un "Unknown command" por el simple hecho que no hay nada definido en la función. Lo que tenemos que hacer es devolver algún valor al llamarla. Para eso simplemente haremos un return PLUGIN_HANDLED para que simplemente ignore el comando. No hará nada pero de esta forma no arrojará ningún error.
Código PHP:
public Action:Command_MySlap(client, args)
{
return Plugin_Handled;
}
Para utilizar los eventos hay que llamarlos previamente en PluginStart. Por ejemplo nosotros llamaremos al evento cuando spawnea un player:
- Llamado de comandos/funciones
En esta parte explicaremos el llamado de comandos, leyendo sus argumentos y mostrandoles como obtener sus valores.
El modo de uso de nuestro comando es el siguiente:
Código:
sm_myslap <nombre|#userid> [daño]
El primer argumento es el nombre o el id del player, el segundo es el daño que le aplicaremos.
- Menues
Este es un ejemplo sencillo de un menú, con su resultado final:
Ahora paso por paso les explicaré cada linea.
Código PHP:
new Handle:menu = CreateMenu(MenuHandler1);
Por lógica, CreateMenu es la función para crear nuestro menú. El único parámetro que necesita es el nombre para el handler.
Código PHP:
SetMenuTitle(menu, "Do you like apples?");
El segundo parámetro es para definir el título de nuestro menú. En el primer parámetro pondremos la variable que tiene alojado el menu que hayamos creado, el segundo parámetro es para poner el título.
Código PHP:
AddMenuItem(menu, "yes", "Yes");
AddMenuItem agrega los item al menu. En el primer parámetro pondremos el nombre de la variable que tiene alojado nuestro menú, el segundo parámetro es el identificador para luego utilizarlo en el handler y el tercero es el nombre del item que se mostrará en el menú.
Código PHP:
SetMenuExitButton(menu, false);
Sirve para agregar una opción para salir del menú. El primer parámetro ya esta explicado, el segundo indicará si agregamos o no un botón para salir (true para agregarlo, false para no agregarlo).
Código PHP:
DisplayMenu(menu, client, 20);
El último parámetro es para mostrar el menú. El primer parámetro es la variable del menú, el segundo el ID del player al que se lo queremos mostrar y el tercer parámetro es cuanto tiempo queremos que le aparezca el menú (en segundos). Si se quiere mostrar para siempre (hasta que salga), agregaremos: MENU_TIME_FOREVER.
Código PHP:
public MenuHandler1(Handle:menu, MenuAction:action, param1, param2)
El Handler posee 4 parámetros. El primero es la variable que contiene el menú, el segundo es lo que hizo el usuario. Los action pueden ser:
- MenuAction_Select - Si el usuario eligió una opción
- MenuAction_Cancel - Si el menu fue cancelado
- MenuAction_End - Si el menu finalizó
El tercer parámetro (param1) contiene el ID del player al que se le mostró el menú, y el último parámetro contiene el número del item que eligió (empieza desde el 0).
Código PHP:
GetMenuItem(menu, param2, info, sizeof(info));
GetMenuItem obtiene el número del item que el player eligió. El primer parámetro ya lo conocemos, el segundo también, el 3 y el 4 es donde se va a guardar el identificador del item. El identificador (por si no se acuerdan) es el segundo parámetro de AddMenuItem (AddMenuItem(menu, "yes", "Yes")). Lo que esta subrayado y en negrita, es lo que se guardará en info, por eso mismo siempre se guarda en un string.
- Timers
Para crear un timer, se hace uso de la función:
Código PHP:
CreateTimer(5.0, Nombre_de_la_funcion);
En donde el primer parámetro (en este caso 5.0), es el intervalo de tiempo, y el segundo es el nombre de la función a ejecutar cuando pase el intervalo de tiempo que hayamos puesto.
Ejemplo:
Para hacer un timer repetitivo, simplemente se agrega 1 parámetro mas. Acá un demostración simple si queremos mandar un mensaje 5 veces:
Código PHP:
// Variable local de control
int numPrinted
someFunction()
{
CreateTimer(3.0, Timer_PrintMessageFiveTimes, _, TIMER_REPEAT);
}
public Action:Timer_PrintMessageFiveTimes(Handle:timer)
{
if (numPrinted >= 5) {
numPrinted = 0;
return Plugin_Stop;
}
PrintToServer("Mensaje");
numPrinted++;
return Plugin_Continue;
}
Para pasar datos a un timer, simplemente se los agregamos después del nombre de la función a ejecutar
Código PHP:
public OnClientPutInServer(client)
{
CreateTimer(15.0, WelcomePlayer, client);
}
public Action:WelcomePlayer(Handle:timer, any:client)
{
PrintToConsole(client, "Bienvenido al servidor!");
}
- TakeDamageHook
El problema de SourceMod es que muchos eventos o funciones, no estan hookeadas por defecto. Entonces tenemos que hacer uso de extensiones creadas por usuarios de AM inglés para poder hookearlas.
Las mas usadas (y las que sugiero que usen), son: SDKHooks y SDKTools.
Por ejemplo, para hookear TakeDamage con SDKHooks:
Código PHP:
#include <sourcemod>
#include <sdkhooks>
public OnPluginStart()
{
for (new client = 1; client <= MaxClients; client++)
{
if (IsClientInGame(client))
{
SDKHook(client, SDKHook_OnTakeDamage, TakeDamageHook);
}
}
}
public OnClientPutInServer(client)
{
SDKHook(client, SDKHook_OnTakeDamage, TakeDamageHook);
}
public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom)
{
if ( (client>=1) && (client<=MaxClients) && (attacker>=1) && (attacker<=MaxClients) && (attacker==inflictor) )
{
// Obtenemos el arma del atacante
decl String:WeaponName[64];
GetClientWeapon(attacker, WeaponName, sizeof(WeaponName));
if(damagetype & CS_DMG_HEADSHOT)
{
// Detectamos el headshot...
}
}
// Retornamos "Plugin_Continue", para que el evento haga lo que tenga que hacer
return Plugin_Continue;
}
En construcción... tarda tiempo traducir y armar el post.