Portal SAMP
[Tutorial] Usando y_commands e sscanf - Versão de Impressão

+- Portal SAMP (https://portalsamp.com)
+-- Fórum: SA-MP (https://portalsamp.com/forumdisplay.php?fid=5)
+--- Fórum: Guias e Tutoriais (https://portalsamp.com/forumdisplay.php?fid=7)
+--- Tópico: [Tutorial] Usando y_commands e sscanf (/showthread.php?tid=4031)



Usando y_commands e sscanf - PT_Player - 07/10/2023

Y_Commands


O que é?
Bem y_commands e o processador de comandos mais rapido e flexivel existente ate ao momento e sscanf é a melhor alternativa para uso substituindo a velha Strtok, ambos foram criados por Y_Less

Requesitos e onde colocar
Bom primeiramente terá de fazer download da biblioteca YSI e da sscanf e sua plugin, aqui tem:
Download da YSI Server Includes.
Download da sscanf.

Após o download copie/corte a pasta "YSI" e coloque na pasta "..pawno/include" e a "sscanf2.inc" também copie/corte e coloque na pasta "..pawno/include".

Quanto ao plugin

No Windows
Tera de copiar ou cortar a "sscanf.dll" e colocar na pasta "plugins". Se nao existir esta pasta, tera de criar-la.
Depois abra o "server.cfg" e adicione "sscanf.dll" na linha "plugins", se nao tiver tera de criar-la assim:

Código:
plugins sscanf.dll

No Linux
Tera de copiar ou cortar a "sscanf.so" e colocar na pasta "plugins". Se nao existir esta pasta, tera de criar-la.
Depois abra o "server.cfg" e adicione "sscanf.so" na linha "plugins", se nao tiver tera de criar-la assim:

Código:
plugins sscanf.so


Adicionando ao GameMode
Bem agora temos de carregar o y_commands e a sscanf. Para isso no topo do seu script tera de os incluir (include).

Código:
#include <YSI\y_commands>
#include <sscanf2>
Isto ira carregar os Codes da pasta "..pawno/include/YSI/y_commands.inc" e "..pawno/include/sscanf2.inc" para o seu script.

Nota
Os comandos que criarem nao poderao estar dentro de qualquer Callback, tem de ser criados fora.
E ja agora uma Callback é uma função código que já existe no seu script ou seja e uma função nativa, exemplo;
Código:
public OnGameModeInit()
{
    return 1;
}
Se colocar os seus comandos dentro destas Callback's irão ocorrer erros, e com isso poderemos ficar aborrecidos e desistir de criar comandos.

Adicionando um comando
Para adicionar um comando basta estar fora de qualquer Callback e seguir as funçoes

Código:
YCMD:teste(playerid, params[], help)
{
    return 1;
}
params e o parametro string, playerid e o ID do player que executa o comando.
y_commands tem um sistema help imbutido.

Nota
Em vez de usar "params" podemos usar "o".
Ficara assim:
Código:
YCMD:teste(playerid, o[], help)
{
    return 1;
}

Sistema help do y_commands

Analise o comando abaixo:
Código:
YCMD:oi(playerid, params[], help)
{
    if(help)
        return SendClientMessage(playerid, -1, "fixe");
    SendClientMessage(playerid, -1, "oi");
    return 1;
}
Como podem verificar ele possui o parametro 'help' preenchido, agora como ler-lo?

Para ler-lo é preciso criar um comando que leia esses parametros, por exemplo esse abaixo:
Código:
YCMD:help(playerid, params[], help)
{
    if (isnull(params)) return SendClientMessage(playerid, -1, "uso: /help [comando]");
    Command_ReProcess(playerid, params, true);
    // isto ira ler o parametro 'help' do comando que colocarmos
    return 1;
}
Com o comando acima sempre que escrever /help [nome do comando] ele ira mostrar o que contem o paramentro 'help' desse comando que quer ver.
Nota: O y_commands nao traz o comando /help como nativo, tem de o criar para poder ler os parametros 'help'.

Criando comandos sem sscanf

Vamos comecar por um simples comando "/ola" sem recurrendo ao uso de sscanf.
Código:
YCMD:ola(playerid, params[], help)
{
    SendClientMessage(playerid, -1, "PT o comando funciona!");
    return 1;
}
O player recebera a simples mensagem , PT o comando funciona!

Mas se por acaso receberem estes warning's na compilaçao:
Código:
warning 203: symbol is never used "params"
warning 203: symbol is never used "help"

Esta e a forma de reparar e nao usar os parametros "params" e "help" no seu comando:
Podemos dizer ao script que nao queremos usar os paramentros "params" e "help" usando a diretiva "#pragma unused symbol" no comando, assim:
Código:
YCMD:ola(playerid, params[], help)
{
    #pragma unused params, help
    SendClientMessage(playerid, -1, "PT o comando funciona!");
    return 1;
}

Outro Exemplo

Vamos criar um comando para admin RCON usar.
Código:
YCMD:adm(playerid, params[], help)
{
    new string[ 128 ];
    new pname[ MAX_PLAYER_NAME ];
   
    if( !IsPlayerAdmin(playerid) ) return SendClientMessage(playerid, -1, "Este comando nao podes usar");
    if( help ) return SendClientMessage(playerid, -1, "Este e um comando de admin RCON");
    if( isnull( params ) ) return SendClientMessage(playerid, -1, "Erro: /adm [texto]");
    GetPlayerName( playerid, pname, sizeof( pname ) );
    format( string, sizeof( string ),"(RCON) %s: %s", pname, params);
    SendClientMessageToAll(-1, string);
    return 1;
}
String
  • new string[ 128 ]; Declaramos que a variavel "string" tem espaço para 127 caracteres.
pname
  • new pname[ MAX_PLAYER_NAME ]; Declaramos que a variavel "pname" ira ter todo o nome do player. A variavel armazena no maximo 24 carateres ("MAX_PLAYER_NAME") que e o tamanho maximo do nome que um player podera ter no SA-MP.
Nota
Em vez de:
Código:
new string[ 128 ];
new pname[ MAX_PLAYER_NAME ];
Pode fazer assim:
Código:
new string[ 128 ], pname[ MAX_PLAYER_NAME ];
so fiz daquela forma para ser mais facil explicar.

Sistema Help
Código:
if( help ) return SendClientMessage(playerid, -1, "Este e um comando de admin RCON");
Se o player quiser saber mais sobre o comando ( /ajudacomando adm).
Isnull
Código:
if( isnull( params ) ) return SendClientMessage(playerid, -1, "Erro: /adm [texto]");
Se o parametro estiver vazio (null) ou seja o player so escreveu "/adm" ira receber (return) a mensagem sobre como usar o comando.
Arrays
Uma array e uma variavel em que tu podes armazenar informaçao e aceder-lhe dinamicamente, exemplo: MAX_PLAYER_NAME
Obtendo o nome do player
Código:
GetPlayerName( playerid, pname, sizeof( pname ) );
O script ira obter o nome do player que executou o comando ( "sizeof( pname )" ) e colocar-lo em uma array na variavel chamada "pname" com o tamanho maximo de MAX_PLAYER_NAME (24) caracteres.
Format
Código:
format( string, sizeof( string ),"(RCON) %s: %s", pname, params);
Nos formatamos a nossa mensagem, e ira armazemar-la na variavel "string", e "sizeof( string )" ira obter o tamanho maximo da string, neste caso declaramos 128.
Placeholders
  • "%s" insere a string. O primeiro "%s" e um placeholder para o nome do player e o segundo para o texto que ele escrever. (/adm [Texto])
SendClientMessageToAll
  • SendClientMessageToAll(-1, string); Isto ira mandar o texto que ele escreveu para todos os players online.
Exemplo de uso
O adm rcon PT escreve "/adm testando"
resultado:
Código:
(RCON) PT: testando

Placeholders
Código:
% b Insere um numero nesta posiçao em base binária
% c Insere um unico caracter.
% d Insere um (inteiro) numero inteiro
% f Insere um numero de ponto flutuante (float).
% i Insere um numero inteiro.
% s Insere uma string. (usamos este antes)
% x Insere um numero em notaçao hexadecimal.
%% Insere o caracter '%'

Criando comandos com sscanf

Vamos comecar com o simples comando "/vida".
Código:
YCMD:vida(playerid, params[], help)
{
    new ID;
    if( help ) return SendClientMessage(playerid, -1, "Este comando dara vida a 1 player!");
    if( sscanf( params, "u", ID ) ) return SendClientMessage(playerid, -1, "Uso: /vida [PlayerName / ID]");
    if( PlayerID == INVALID_PLAYER_ID ) return SendClientMessage(playerid, -1, "[ERRO] Este playes esta OFFLINE");
    SetPlayerHealth(ID, 100);
    return 1;
}
Declarando
  • new ID; e a variavel que declara o id do player que vamos dar vida.
Sistema help
Código:
if( help ) return SendClientMessage(playerid, -1, "Este comando dara vida a 1 player!");
Como sempre se o paramentro "help" for usado, ira mostrar a mensagem que escrevemos ou seja a descricao do comando.
Sscanf
Código:
if( sscanf( params, "d", ID ) ) return SendClientMessage(playerid, -1, "Erro: /vida [ID]");
Usamos o parametro, "d" para especificar que e um numero ou seja o id do player, a sscanf ira verificar se colocarmos de forma incorreta os parametros do comando, que neste caso deveriam ser por exemplo: /vida 0 se nao colocar assim obtera a mensagem de erro.
INVALID_PLAYER_ID
Código:
if( ID == INVALID_PLAYER_ID ) return SendClientMessage(playerid, -1, "[ERRO] Este playes esta OFFLINE");
Isto ira verificar se o ID que colocamos e um ID online no servidor, se nao for obtem a mensagem de erro.
SetPlayerHealth
  • SetPlayerHealth(ID, 100);
Isto e para setar a vida do id a 100.
A formula da Sscanf no comando
  • A formula da sscanf e esta:
Código:
if(sscanf( params, "Especificacoes", Nossas variaveis ) )  // Se o player introduziu os parametros incorretos
{
// mensagem para avisar o player
}
Especificacoes

Usamos-las conforme o fim que queremos obter:
Código:
a - se for um caracter.
f - se for um numero de ponto flutuante (float).
i ou d - se for um numero inteiro.
s - se for uma string.
x ou h - Insere um numero em notaçao hexadecimal.
z - se for um texto opcional
px - se for um delimitador adicional, onde X em outro player.
'' - para localizar uma string ( texto ).
u - parte de um nome ou um id


Comandos
y_commands tem um sistema especial que deteta todos os comandos que tu tens no teu script assim nao precisas andar sempre atualizar a tua lista de "/comandos".
Código:
YCMD:comandos(playerid, params[], help)
{
    if ( help ) return SendClientMessage(playerid, -1, "Lista de todos os comandos.");
    new count = Command_GetPlayerCommandCount( playerid );
   
    for ( new i = 0; i != count; ++i) SendClientMessage( playerid, -1, Command_GetNext ( i, playerid ) );
    return 1;
}

Mensagem: UNKNOWN COMMAND
Quando um player escreve um comando que nao existe recebe a mensagem: "SERVER: Unknown Command." entao como alterar essa mensagem?
Basta colocar a CallBack OnPlayerCommandPerformed e usar por exemplo assim:
Código:
public OnPlayerCommandPerformed(playerid, cmdtext[], success)
{
    if( !success ) return false;
    return true;
}
Mas podemos colocar uma mensagem para ficar mais agradavel de ser ver, para isso usamos assim:
Código:
public OnPlayerCommandPerformed(playerid, cmdtext[], success)
{
    if( !success )
    {
        format( cmdtext, 128, " ERRO: O comando %s nгo existe veja em /comandos todos  ", cmdtext );
        SendClientMessage( playerid, -1, cmdtext );
       
    }
    return true;
}

Resultado final
Código:
#include <a_samp>
#include <YSI\y_commands>
#include <sscanf2>

main()
{
    print("\n----------------------------------");
    print(" Blank Gamemode by your name here");
    print("----------------------------------\n");
}

public OnGameModeInit()
{
    // Don't use these lines if it's a filterscript
    SetGameModeText("Blank Script");
    AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
    Command_AddAltNamed("information", "info");
    return 1;
}

public OnGameModeExit()
{
    return 1;
}

public OnPlayerRequestClass(playerid, classid)
{
    SetPlayerPos(playerid, 1958.3783, 1343.1572, 15.3746);
    SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
    SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);
    return 1;
}

public OnPlayerConnect(playerid)
{
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    return 1;
}

public OnPlayerSpawn(playerid)
{
    return 1;
}

public OnPlayerDeath(playerid, killerid, reason)
{
    return 1;
}

public OnVehicleSpawn(vehicleid)
{
    return 1;
}

public OnVehicleDeath(vehicleid, killerid)
{
    return 1;
}

public OnPlayerText(playerid, text[])
{
    return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
    if (strcmp("/mycommand", cmdtext, true, 10) == 0)
    {
        // Do something here
        return 1;
    }
    return 0;
}

public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
{
    return 1;
}

public OnPlayerExitVehicle(playerid, vehicleid)
{
    return 1;
}

public OnPlayerStateChange(playerid, newstate, oldstate)
{
    return 1;
}

public OnPlayerEnterCheckpoint(playerid)
{
    return 1;
}

public OnPlayerLeaveCheckpoint(playerid)
{
    return 1;
}

public OnPlayerEnterRaceCheckpoint(playerid)
{
    return 1;
}

public OnPlayerLeaveRaceCheckpoint(playerid)
{
    return 1;
}

public OnRconCommand(cmd[])
{
    return 1;
}

public OnPlayerRequestSpawn(playerid)
{
    return 1;
}

public OnObjectMoved(objectid)
{
    return 1;
}

public OnPlayerObjectMoved(playerid, objectid)
{
    return 1;
}

public OnPlayerPickUpPickup(playerid, pickupid)
{
    return 1;
}

public OnVehicleMod(playerid, vehicleid, componentid)
{
    return 1;
}

public OnVehiclePaintjob(playerid, vehicleid, paintjobid)
{
    return 1;
}

public OnVehicleRespray(playerid, vehicleid, color1, color2)
{
    return 1;
}

public OnPlayerSelectedMenuRow(playerid, row)
{
    return 1;
}

public OnPlayerExitedMenu(playerid)
{
    return 1;
}

public OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid)
{
    return 1;
}

public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
    return 1;
}

public OnRconLoginAttempt(ip[], password[], success)
{
    return 1;
}

public OnPlayerUpdate(playerid)
{
    return 1;
}

public OnPlayerStreamIn(playerid, forplayerid)
{
    return 1;
}

public OnPlayerStreamOut(playerid, forplayerid)
{
    return 1;
}

public OnVehicleStreamIn(vehicleid, forplayerid)
{
    return 1;
}

public OnVehicleStreamOut(vehicleid, forplayerid)
{
    return 1;
}

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    return 1;
}

public OnPlayerClickPlayer(playerid, clickedplayerid, source)
{
    return 1;
}
public OnPlayerCommandPerformed(playerid, cmdtext[], success)
{
    if( !success )
    {
        format( cmdtext, 128, " ERRO: O comando %s nгo existe veja em /comandos todos os comandos disponiveis ", cmdtext );
        SendClientMessage( playerid, -1, cmdtext );
       
    }
    return true;
}
/*                                          COMANDOS                                            */
YCMD:ajudacomando(playerid, params[], help)
{
    if (isnull(params)) return SendClientMessage(playerid, -1, "uso: /ajudacomando [comando]");
    Command_ReProcess(playerid, params, true);
    // isto ira ler o parametro 'help' do comando que colocarmos
    return 1;
}
YCMD:comandos(playerid, params[], help)
{
    if ( help ) return SendClientMessage(playerid, -1, "Lista de todos os comandos.");
    new count = Command_GetPlayerCommandCount( playerid );
   
    for ( new i = 0; i != count; ++i) SendClientMessage( playerid, -1, Command_GetNext ( i, playerid ) );
    return 1;
}
YCMD:ola(playerid, params[], help)
{
    #pragma unused params, help
    SendClientMessage(playerid, -1, "PT o comando funciona!");
    return 1;
}
YCMD:testando(playerid, params[], help)
{
    if (help) return SendClientMessage(playerid, -1, "comando lindo.");
    SendClientMessage(playerid, -1, "funciona");
    return 1;
}

YCMD:testando2(playerid, params[], help)
{
    if (help) return SendClientMessage(playerid, -1, "comando feio.");
    SendClientMessage(playerid, -1, "funciona2");
    return 1;
}
YCMD:vida(playerid, params[], help)
{
    new ID;
    if( help ) return SendClientMessage(playerid, -1, "Este comando dara vida a 1 player!");
    if( sscanf( params, "u", ID ) ) return SendClientMessage(playerid, -1, "Uso: /vida [PlayerName / ID]");
    if( PlayerID == INVALID_PLAYER_ID ) return SendClientMessage(playerid, -1, "[ERRO] Este playes esta OFFLINE");
    SetPlayerHealth(ID, 100);
    return 1;
}
YCMD:adm(playerid, params[], help)
{
    new string[ 128 ];
    new pname[ MAX_PLAYER_NAME ];
   
    if( !IsPlayerAdmin(playerid) ) return SendClientMessage(playerid, -1, "Este comando nao podes usar");
    if( help ) return SendClientMessage(playerid, -1, "Este e um comando de admin RCON");
    if( isnull( params ) ) return SendClientMessage(playerid, -1, "Erro: /adm [texto]");
    GetPlayerName( playerid, pname, sizeof( pname ) );
    format( string, sizeof( string ),"(RCON) %s: %s", pname, params);
    SendClientMessageToAll(-1, string);
    return 1;
}
Se eu me esqueçi de algo ou me expliquei mal em algo, por favor digam. Tentei o meu melhor para explicar direito para voces.

Creditos
Y_Less - pelo processador de comandos e pela sscanf
SA:MP Wiki - pelas referencias
PT_Player a.k.a PT e Schocc - Pelo tutorial

P.S: Relembro que isto é um tutorial feito e postado em 2013 no Forum SA-MP.