Portal SAMP
[Tutorial] [Tutorial] Melhorando seus script's e seus gamemodes - 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] [Tutorial] Melhorando seus script's e seus gamemodes (/showthread.php?tid=4030)



[Tutorial] Melhorando seus script's e seus gamemodes - PT_Player - 03/10/2023

Ola, dado que o Forum SA-MP fechou decidi trazer os tutorais que tinha feito para o Forum SA-MP para aqui, com o objetivo de ver os utilizadores desta board com melhores scripts e com melhor raciocinio, isto apos ter visto muitos membros novos com codigos muito mal feitos, e se nao aprendem direito de novos, nunca ou tarde endireitam.


Problema do strtok
  • Bem, vejo ainda muitos membros desta board,a usar a "velhinha" strtok feita pelo DarcoBlue.
Código:
strtok(const string[], &index)
{
    new length = strlen(string);
    while ((index < length) && (string[index] <= ' '))
    {
        index++;
    }

    new offset = index;
    new result[20];
    while ((index < length) && (string[index] > ' ') && ((index - offset) < (sizeof(result) - 1)))
    {
        result[index - offset] = string[index];
        index++;
    }
    result[index - offset] = EOS;
    return result;
}

Mas, não sabem que ela além de ser velha é também lenta em relação a atuais comparadores de parámetros.

Bem, eu recomendo que usem sscanf criada pelo Y_Less, não só pela facilidade de uso, mas também pela velocidade desta;


Vejam a diferença do comando /kick [id]:
Em strtok;

Código:
public OnPlayerCommandText(playerid, cmdtext[])
{
    new cmd[128], idx;
    cmd = strtok(cmdtext, idx);

    if(strcmp(cmd, "/kick", true) == 0)
    {
        new tmp[128];
        tmp = strtok(cmdtext, idx);

        if(strlen(tmp) == 0)
            return SendClientMessage(playerid, 0xFFFFFFFF, "Uso: /kick [playerid]");

        Kick(strval(tmp));
        return 1;
    }
    return 0;
}


Em sscanf;
Código:
public OnPlayerCommandText(playerid, cmdtext[])
{
    if(strcmp(cmd, "/kick", true) == 0)
    {
        new id;
        if(sscanf(cmdtext, "u", id))
            return SendClientMessage(playerid, 0xFFFFFFFF, "Uso: /kick [playerid]");

        Kick(id);
        return 1;
    }
    return 0;
}

Viram? Os comandos acima fazem exatamente o mesmo, porém como podem ver, a sua elaboração é diferente, pessoalmente acho que é sem duvida o segundo, mais fácil que o primeiro.

Problema do uso de strcmp para criar comandos

Bem, ainda muito usam strcmp para criar comandos. Isto atualmente normalmente diz muito sobre o programador do GM, ou é preguiçoso e não quer atualizar os seus comandos para processador de comandos, ou, usa um gamemode da Internet e não faz a mínima ideia do que é um processador de comandos (embora atualmente tenha mais gamemodes na internet com processador de comandos). Antes de tudo strcmp tem como finalidade comparar string's e nao criar comandos.


Usar um processador de comandos tem enormes vantagens, como a maior simplicidade na criação de comandos, é prática, cómodo e sobretudo mais rápido de usar do que strcmp.
Analisem o comando /kick [id] abaixo:


Em strcmp (Não é processador de comandos)
Código:
public OnPlayerCommandText(playerid, cmdtext[])
{
    if(strcmp(cmd, "/kick", true) == 0)
    {
        new id;
        if(sscanf(cmdtext, "u", id))
            return SendClientMessage(playerid, 0xFFFFFFFF, "Uso: /kick [playerid]");

        Kick(id);
        return 1;
    }
    return 0;
}


Em zcmd (Processador de comandos)
Código:
CMD:kick(playerid, params[])
{
    new id;
    if(sscanf(params, "u", id))
        return SendClientMessage(playerid, 0xFFFFFFFF, "Uso: /kick [playerid]");
    Kick(id);
    return 1;
}

Em ycmd (Processador de comandos)
Código:
YCMD:kick(playerid, params[], help)
{
    #pragma unused help
    new id;
    if(sscanf(cmdtext, "u", id))
        return SendClientMessage(playerid, 0xFFFFFFFF, "Uso: /kick [playerid]");
    Kick(id);
    return 1;
}
Viram a diferenзa?

É muito melhor não é? Eu sei que sim...

E sim criar comandos com processadores de comandos nao precisa de colocar o comando dentro de qualquer callback.

Tambem muitas vezes nao precisam criar variaveis, assim:

Em zcmd
Código:
CMD:kick(playerid, params[])
{
    if(sscanf(params, "u", params[0]))
        return SendClientMessage(playerid, 0xFFFFFFFF, "Uso: /kick [playerid]");
    Kick(params[0]);
    return 1;
}
Em ycmd
Código:
YCMD:kick(playerid, params[], help)
{
    #pragma unused help
    if(sscanf(cmdtext, "u", params[0]))
        return SendClientMessage(playerid, 0xFFFFFFFF, "Uso: /kick [playerid]");
    Kick(params[0]);
    return 1;
}

Porque escolhi ycmd e zcmd?

Porque são os mais rápidos (apesar de ycmd ser o mais rápido), já criados em pawn atualmente e são os que a maioria dos programadores de sa-mp que usam processadores de comandos usam.

Sim, eu sei que ainda existem mais rápidos desenvolvidos em C++, porém são mais complexos o seu uso para quem ainda está a aprender, porque mexe com plugins, etc.
E se eu usar sscanf e um processador de comandos, estou a agir bem?
Bem isso é o ideal e sim está a agir corretamente, porém para quem não está a usar a e quer começar.

Deixo o link Github de cada processador e da SSCANF:

ZCMD: https://github.com/Southclaws/zcmd
YCMD: https://github.com/pawn-lang/YSI-Includes/blob/5.x/YSI_Visual/y_commands.md
SSCANF: https://github.com/Y-Less/sscanf

Loops

A maioria tem por norma fazer os loops assim:

Código:
for(new i = 0; i < MAX_PLAYERS; i++)

Não é que esteja errado, porém esquecem-se que o valor default de MAX_PLAYERS, se alterarem o valor para o valor real de slots máximo do seu servidor podem fazer com que os loops tenham um processamento (velocidade) maior, como?

Fazendo simplesmente isto:


Código:
#include <a_samp>
#undef MAX_PLAYERS
#define MAX_PLAYERS (50) // o 50 voce muda pelo numero de slots do seu servidor

Qual a diferença?

Se não alterarem o valor, MAX_PLAYERS assume um valor que para quem não sabe está definido por default pela SA-MP Team na include a_samp.inc como valor padrão 1000, ou seja, irá sempre realizar o loop de 1000, mas se alterarem o valor de MAX_PLAYERS ira assumir o valor máximo no loop a quantidade de slots do seu servidor, sendo que a maioria dos membros aqui na board portuguesa quase nunca tem um servidor com 1000 slots alterando o valor o loop é muito mais rápido.


Porem tem também quem insista em fazer o loop deste jeito:

Código:
for(new i = 0; i < GetMaxPlayers(); i++)
Este tipo de loop é errado e mais lento.

Apenas num caso especial poderá ser mais rápido, se voce tiver um servidor de 50 slots e não alterar o valor de MAX_PLAYERS usando o loop acima torna-se mais rápido é verdade, porem se alterarem o valor o valor de MAX_PLAYERS para o valor real dos seus slots o loop acima torna-se muito mais lento.


foreach

Com esta simples include (versão mais antiga, nas versoes mais recentes esta incorporada na YSI) feita pelo Y_Less voce pode melhorar e muito os seus loops sendo que quando são ligados a sistemas para players apenas corre o loop nos players conectados, mas também poderá nos veículos, entre outros.

Ou seja, códigos assim:

Código:
stock DarDinheiroTodos()
{
    for( new i = 0; i < MAX_PLAYERS; i++)
    {
        if(IsPlayerConnected(i))
        {
            GivePlayerMoney(i, 1000);
        }
    }
    return 1;
}

Tornam-se alem de mais fáceis, mais rápidos também na hora do processamento:

Código:
#include <foreach>

stock DarDinheiroTodos()
{
    foreach(new i : Player)
    {
        GivePlayerMoney(i, 1000);
    }
    return 1;
}

Fazem as duas formas exactamente o mesmo porem a segunda e muito mais rápida que a primeira na hora do processamento

Deixo abaixo o link do tópico da foreach para quem quiser saber mais sobre a mesma.
foreach: https://github.com/pawn-lang/YSI-Includes/blob/5.x/YSI_Data/y_iterate.md ou se preferirem sozinha a include https://github.com/karimcambridge/samp-foreach


"Lógicas, sem lógica"

Ao ler o título é engraçado, porem o assunto é sério por vezes, ve-se os códigos assim:

Código:
new bolacha[MAX_PLAYERS];

if(bolacha[playerid])
{
}
else
{
    SendClientMessage(playerid, -1, "Nao tens bolacha");
}

Quando me deparo com um código deste, embora ja tenha visto muito piores a nivel de logica, pergunto se não seria mais fácil faze-lo assim:

Código:
new bolacha[MAX_PLAYERS];

if(!bolacha[playerid])
    return SendClientMessage(playerid, -1, "Nao tens bolacha");

Com isto vejo que muitos membros ainda não sabem os operadores lógicos, se é que ao menos sabem que eles existem, por isso decidi deixar aqui alguns links de tutoriais de operadores lógicos, e tambem a nivel de otimizacoes, para quem quiser saber mais sobre este assunto.

https://portalsamp.com/showthread.php?tid=2486
https://portalsamp.com/showthread.php?tid=3406
https://portalsamp.com/showthread.php?tid=3560



Créditos
Emmet_ - Base da ideia para criacao do tutorial
PT_Player a.k.a PT - Criacao do tutorial

Espero que aprendam algo com este tutorial, se quiserem acrescentar algo ou melhorar o tutorial em algum aspeto, estejam á vontade.

Talvez no futuro, dependendo do vosso feedback, melhorarei ou farei mais tutoriais, deixem abaixo as suas opiniхes, tambem se tiverem em duvida acerca de algum assunto deste tutorial, estarei á disposiзгo para responder.

Sei que o tutorial é sobre de uma matéria simples, porém muitos ainda nunca se aperceberam ou nunca viram a vantagem de "evoluir" os seus scripts, talvez com isto aprendam algo.

Cumprimentos


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


RE: [Tutorial] Melhorando seus script's e seus gamemodes - João Pedro Alves - 03/10/2023

Fiz questão de acessar minha conta só para parabenizar essa excelente contribuição sua PT! É muito bacana ver o pessoal da geração inicial do SA-MP PT/BR demonstrar o carinho pela comunidade com contribuições como essa sua!

Espero ver mais conteúdo seu por aqui principalmente nesse momento que a comunidade precisa se unir para manter o game vivo!

Forte abraço!


RE: [Tutorial] Melhorando seus script's e seus gamemodes - White_Blue - 03/10/2023

Muito legal! Outra coisa que eu acho que seria interessante incluir nesse tópico é a questão de Salvamento, já que até hoje muita gente utiliza Dini que é extremamente ultrapassado e não recomendado. O ideal para hoje em dia sinceramente seria usar um banco de dados, como SQLITE ou MySQL, mais por questão de integração com outros sistemas e segurança, no entanto, usar DOF2 é aceitável mas está longe de ser o ideal para servidores modernos. Outra coisa também é que vejo muita gente usar algoritmos de hash "caseiros" para criptografia ou até mesmo usar absolutamente nenhuma criptografia em senhas e dados sensíveis, o que não é nada seguro.


RE: [Tutorial] Melhorando seus script's e seus gamemodes - PT_Player - 03/10/2023

(03/10/2023 15:12)João Pedro Alves Escreveu: Fiz questão de acessar minha conta só para parabenizar essa excelente contribuição sua PT! É muito bacana ver o pessoal da geração inicial do SA-MP PT/BR demonstrar o carinho pela comunidade com contribuições como essa sua!

Espero ver mais conteúdo seu por aqui principalmente nesse momento que a comunidade precisa se unir para manter o game vivo!

Forte abraço!
é uma honra voltar a verlo e saber que ainda esta por aqui.

deixo te o meu discord para trocarmos umas palavrinha: .pt_player

(03/10/2023 19:27)White_Blue Escreveu: Muito legal! Outra coisa que eu acho que seria interessante incluir nesse tópico é a questão de Salvamento, já que até hoje muita gente utiliza Dini que é extremamente ultrapassado e não recomendado. O ideal para hoje em dia sinceramente seria usar um banco de dados, como SQLITE ou MySQL, mais por questão de integração com outros sistemas e segurança, no entanto, usar DOF2 é aceitável mas está longe de ser o ideal para servidores modernos. Outra coisa também é que vejo muita gente usar algoritmos de hash "caseiros" para criptografia ou até mesmo usar absolutamente nenhuma criptografia em senhas e dados sensíveis, o que não é nada seguro.
Vlw 
Seria legal um tutorial sobre isso tbm.
Eu pessoalmente prefiro SQLite porque é nativo.


RE: [Tutorial] Melhorando seus script's e seus gamemodes - xbruno1000x - 06/10/2023

Tenho certeza que esse tutorial irá ajudar muitos interessados em aprender mais sobre a linguagem pawn. São coisas que parecem óbvias, mas que sempre aparecem nos códigos dos tópicos de dúvidas. Você disse ter feito o tutorial em 2014, mas me parece bastante atual ainda. +Rep