Portal SAMP
[Tutorial] SetTimer e SetTimerEx - Básico - 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] SetTimer e SetTimerEx - Básico (/showthread.php?tid=821)

Páginas: 1 2


SetTimer e SetTimerEx - Básico - Levi.M - 28/02/2021


SetTimer & SetTimerEx




Como vejo muitas dificuldades nas diferenças entre SetTimer e SetTimerEx, venho aqui trazer um tutorial simples para vocês.


1. De certeza você já ouviu falar daquela expressão: "SetTimer é para todos os jogadores e SetTimerEx é para cada um." Isso está meio que errado. Não é pra isso que foi criado o SetTimer e SetTimerEx.

2. Usamos SetTimer e SetTimerEx quando queremos chamar uma função com atraso, ou seja, por um determinado tempo depois.

3. SetTimer: Sem parametros.    SetTimerEx: Com parâmetros.



Explicação:

SetTimer:
Código PHP:
SetTimer(NomeFuncaoTempoRepetição); 
NomeFuncao: Será o nome de sua função pública.
Tempo: O tempo de duração que você quer chamar ela.
Repetição: true = repetir sempre, false = apenas uma vez.


SetTimerEx:
Código PHP:
SetTimerEx(NomeFuncaoTempoRepeticaoformato, {Float,_}:...) 
NomeFuncao: Será o nome de sua função pública.
Tempo: O tempo de duração que você quer chamar ela.
Repetição: true = repetir sempre, false = apenas uma vez.
formato: tipos de valores.
{Float,_}:... : parâmetros (seguindo o formato definido anteriormente).




Até agora, se você é iniciante, você provavelmente está pensando: Eu não entendi nada! Enfim, para isso estou aqui, vou explicar na sua experiência dia-dia.

Vamos imaginar na sua casa: O Microondas, você coloca algo apenas para esquentar, programa ele pra 1 minuto e a contagem começa a descer até chegar ao 0... ( porém o SetTimer(Ex) é incrementando(subindo), e não descendo.

Outro exemplo: você está brincando de esconde-esconde e tem que contar até 10. Quando chegar ao 10, você já pode procurar eles..
Isso é o SetTimer(Ex). Você faz um SetTimer que 'conte' até 10, e quando chegar no 10, irá executar a função de procurar eles.

Agora digamos que você tenha roubado e parou de contar antes dos 10 segundos. Nesse caso, utilizamos o KillTimer parando o SetTimer(Ex)!
Esse é o conceito de SetTimer(Ex)... Ele vai até onde você mandar! Vamos a uns exemplos práticos para entendermos melhor!


Diminuindo tempo pensando em milissegundos.

O tempo do SetTimer(Ex) é feito em milissegundos. Ou Seja:
Código PHP:
1 segundo 1000
60 segundos 
60000
// [...] 



Se você precisa de 2 minutos e 27 segundos por exemplo, sem gerador ou algo do tipo você teria que bater muita cabeça até conseguir. Para facilitar seu trabalho, iniciante, você bota isso no topo do seu GM/FS. Não me lembro do criador do code, mas vou deixar aqui os créditos pro Y_Less. Se alguem souber de quem criou isso, coloca nos comentários
Código PHP:
#define minutos(%0) (1000 * %0 * 60)
#define horas(%0) (1000 * %0 * 60 * 60)
#define segundos(%0) (1000 * %0)
#define dias(%0) (1000 * %0 * 60 * 60  * 24)
#define semanas(%0) (1000 * %0 * 60 * 60  * 24 * 7)
#define meses(%0) (1000 * %0 * 60 * 60  * 24 * 30)
#define anos(%0) (1000 * %0 * 60 * 60  * 24 * 30 * 12)
#define decadas(%0) (1000 * %0 * 60 * 60  * 24 * 30 * 12 * 10)
#define seculos(%0) (1000 * %0 * 60 * 60  * 24 * 30 * 12 * 10 * 10) 

É claro que você não usaria pra dias, semanas, meses, anos, década e muito menos seculos. Para isso usamos GetTimer, mas fica pra outra explicação.
Agora sim! Com esse código definido, fica muito mais fácil trabalharmos! Vamos ver na prática.

Como ficaria o exemplo: "Você está brincando de esconde-esconde e tem que contar até 10. Quando chegar ao 10, você já pode procurar eles.." na prática?


SetTimer
Código PHP:
SetTimer("Contando"segundos(10), false);
// Veja como ficou mais fácil definir o tempo. Mas você também pode optar pelo normal:
SetTimer("Contando"10000false);
// Ele cria uma função contando 10 segundos sem repetição!

// Como SetTimer não tem parametro, nunca passamos valor para ela. Sempre utilizaremos ( ).

forward Contando();
public 
Contando()  // Quando completar os 10 segundos, funciona a callback.
{
    print("Contei até 10 segundos ! Agora posso começar a procurar!");
    return true;


Outro exemplo muito conhecido, o sistema de payday:
Código PHP:
public OnGameModeInit()
{
    SetTimer("PayDay"horas(1), true);
/* Criamos um Timer com o nome da função PayDay
Ele irá contar até 1 hora.
/ true = ele irá se repetir depois de terminar. ( voltará a funcionar sozinho ).*/
    return true;
}

forward PayDay();
public 
PayDay() // Quando completar as 1 hora, funciona a Callback:
{
    for(new iMAX_PLAYERS; ++i// Loop - Todos os Players
    {
        // Mensagem para todos os players.
        SendClientMessage(i, -1"Você recebeu o PayDay!");
    }
    return true;


Realmente, SetTimer poderia ser para todos os players(usando loop). Mas não é isso o conceito dela. Ela vai muito além disso, como utilizar pra sistema de salvamentos ou outras coisas.
Código PHP:
for(new iMAX_PLAYERS; ++i)
{
    SendClientMessage(i, -1"Você recebeu o PayDay!");


Para quem não entendeu isso, procure por tutoriais de Loop.
MAX_PLAYERS definido por padrão é 500... Ou seja vai pegar 500 números que são os slots. Até aqui tudo bem. Mas porque trocou no meu SendClientMessage playerid por i ?

playerid = ID DO PLAYER! LEMBREM-SE DISSO!

O Loop, portanto, vai dar 500 voltas... e vai mandar para todos os ID's.
O ID 0 que é o Fulano com Nick A...
Pro ID 1 que é o Fulano com Nick B...
Assim vai até os 500 players(slots).


SetTimerEx

Existem vários exemplos. Mais vou dar apenas dois. Esse, é um simples bloqueio de comando. Depois de usar, ele permitirá que você utilize o comando de novo só depois de 15 segundos.
Código PHP:
new bool:BloquearComando[MAX_PLAYERS char];

get_cmd_noparams(bloquearcomando// ICMD ( mesma coisa que /bloquearcomando )
{
    if(BloquearComando{playerid} == true)
        return SendClientMessage(playerid, -1"Você já utilizou o comando! Aguarde 15 segundos para utlizar de novo.");

    BloquearComando{playerid} = true;
    SetTimerEx("BloqComando"segundos(15), false"i"playerid);
    // Ele irá criar uma função de 15 segundos e não vai ficar se repetindo.
    // Como eu falei no meu BIZU: playerid carrega o ID do Player. Ele vai levar o ID do player para a função.
    SendClientMessage(playerid, -1"Você Utilizou o Comando: /BloquearComando");
     return true;
}

forward BloqComando(playerid);
public 
BloqComando(playerid// playerid CARREGA O ID DO PLAYER !
{
    BloquearComando{playerid} = false;
    SendClientMessage(playerid, -1"Já se passou 15 segundos! Agora você já pode utilizar o comando!");
    return true;



Agora que tal um sistema de carregar suas informações simples?
Código PHP:
get_cmd_noparams(minhasinfo// ICMD ( mesma coisa que /minhasinfo )
{
    new Idade 18;
    new Float:PontosNaEscola 9.0;
    // playerid = seu ID
     SetTimerEx("CarregInfo"5000true"iif"playeridIdadePontosNaEscola);
    return true;
}

forward CarregInfo(playeridIdadePontosNaEscola);
public 
CarregInfo(playeridIdadePontosNaEscola
{
    static StringJFS[70];
    format(StringJFSsizeof(StringJFS), "ID: %d | Idade: %d | PontosNaEscola %f"playerid IdadePontosNaEscola);
    SendClientMessage(playerid, -1StringJFS);
    return true;



Lembretes e informações importantes:

Temporizadores não são 100% precisos e sim 75%;
Uso de muitos temporizadores aumentará o uso de Memória/CPU.
Lembrando daqueles "i", "iif", etc.. Sugiro ver melhor os tutoriais de Format.


Código:
i    Integer.
d    Integer.
a    Array. The next parameter must be an integer ("i") with the array's size. [CURRENTLY UNUSABLE]
s    String. [CURRENTLY UNUSABLE]
f    Float.
b    Boolean (true/false).


Créditos ao Jonathan Feitosa.


RE: SetTimer e SetTimerEx - Básico - ewertonsoarez106 - 07/03/2022

Eu estou criando um sistema de cadeia, e estou usando o PlayerInfo[playerid][Preso] pra fazer a prisão, eu queria saber como faço uma contagem decrescente na pasta pra quando chegar em 0 ele ser solto


RE: SetTimer e SetTimerEx - Básico - xbruno1000x - 08/03/2022

Boa contribuição compartilhando o tutorial.

Vale ressaltar que não é aconselhável o uso de timers dessa forma:

Código:
public PayDay() // Quando completar as 1 hora, funciona a Callback:
{
    for(new i; i < MAX_PLAYERS; ++i) // Loop - Todos os Players
    {

Esse looping todo gera um alto consumo de processamento, pois ele irá verificar 1000 vezes, mesmo que não tenham 1000 conectados. Uma alternativa para loopings que usam variáveis, seria o SetTimerEx na OnPlayerConnect, pois ela fará a função ser ativada apenas para quem está conectado e em momentos distintos, assim evitando picos de processamento. Outra alternativa é otimizar o looping de 1 único timer, impedindo ele de fazer todas essas 1000 verificações, sempre com if's verificando se não é NPC, por exemplo.


RE: SetTimer e SetTimerEx - Básico - Dr Editor - 08/03/2022

Tá aí um ponto que fico curioso. Fez este teste mesmo? É aconselhável criar 1000 timers ao invés de um timer único com um loop de 1000 voltas?


RE: SetTimer e SetTimerEx - Básico - xbruno1000x - 08/03/2022

(08/03/2022 08:28)Dr Editor Escreveu: Tá aí um ponto que fico curioso. Fez este teste mesmo? É aconselhável criar 1000 timers ao invés de um timer único com um loop de 1000 voltas?

Sua questão é extremamente válida.
Com 1000 timers simultâneos não tive a oportunidade de realizar o teste, mas fiz em menor escala. Os timer's com looping faziam o servidor em questão bater 100% de uso de CPU e ele desligava. Decidi fazer essa substituição para diluir em momentos diferentes o processamento da informação, e de fato o problema não voltou a ocorrer.

Mas é importante ressaltar que é uma tese baseada na minha experiência, portanto não é uma verdade absoluta. Visto isso, fiz a correção do meu comentário anterior.


RE: SetTimer e SetTimerEx - Básico - ProKillerPa - 15/03/2022

(08/03/2022 01:28)xbruno1000x Escreveu: Boa contribuição compartilhando o tutorial.

Vale ressaltar que não é aconselhável o uso de timers dessa forma:

Código:
public PayDay() // Quando completar as 1 hora, funciona a Callback:
{
    for(new i; i < MAX_PLAYERS; ++i) // Loop - Todos os Players
    {

Esse looping todo gera um alto consumo de processamento, pois ele irá verificar 1000 vezes, mesmo que não tenham 1000 conectados. Uma alternativa para loopings que usam variáveis, seria o SetTimerEx na OnPlayerConnect, pois ela fará a função ser ativada apenas para quem está conectado e em momentos distintos, assim evitando picos de processamento. Outra alternativa é otimizar o looping de 1 único timer, impedindo ele de fazer todas essas 1000 verificações, sempre com if's verificando se não é NPC, por exemplo.
Bem observado, porém para diminuir drasticamente esse problema é possivel fazer um #undef e definir MAX_PLAYERS para um valor mais baixo, até por que muitos servidores tem host com planos de slots mais baixos (100, por exemplo).


Acrescentando ao tutorial, caso você use parâmetros de Float no timer, você precisará definir na public como Float também, caso contrário buga o valor do Float.

Abraços


RE: SetTimer e SetTimerEx - Básico - MisteriumBr - 23/11/2022

Amigos queria usar um timer para poder executar o comando novamente, mas queria que mesmo que os players saissem do server, o timer parasse e só voltasse quando o player estivesse online alguma sugestão de código?


RE: SetTimer e SetTimerEx - Básico - White_Blue - 23/11/2022

(23/11/2022 19:20)MisteriumBr Escreveu: Amigos queria usar um timer para poder executar o comando novamente, mas queria que mesmo que os players saissem do server, o timer parasse e só voltasse quando o player estivesse online alguma sugestão de código?

Para isto existe a função KillTimer.

Código PHP:
new timer[MAX_PLAYERS];

public 
OnPlayerConnect(playerid) {
           
Timer[playerid] = SetTimerEx("StartTimer"10000true"i"playerid); // Inicia o timer quando o player entra no servidor
      
return 1;
}

public 
OnPlayerDisconnect(playeridreason) {
       
KillTimer(Timer[playerid]); // Executamos a KillTimer, que para o timer.
       
return 1;
}

forward StartTimer(playerid);
public 
StartTimer(playerid) {
     
GivePlayerMoney(playerid1000); // Neste exemplo, o timer dará $1,000 para o player a cada 10 segundos enquanto ele estiver desconectado
     
return 1;




RE: SetTimer e SetTimerEx - Básico - MisteriumBr - 24/11/2022

Para isto existe a função KillTimer.

Código PHP:
new timer[MAX_PLAYERS];

public 
OnPlayerConnect(playerid) {
           Timer[playerid] = SetTimerEx("StartTimer"10000true"i"playerid); // Inicia o timer quando o player entra no servidor
      return 1;
}

public 
OnPlayerDisconnect(playeridreason) {
       KillTimer(Timer[playerid]); // Executamos a KillTimer, que para o timer.
       return 1;
}

forward StartTimer(playerid);
public 
StartTimer(playerid) {
     GivePlayerMoney(playerid1000); // Neste exemplo, o timer dará $1,000 para o player a cada 10 segundos enquanto ele estiver desconectado
     return 1;



Me tira uma dúvida para ver se estou fazendo certo, estou querendo colocar um anti farm na hora de vender veiculos, para o player não ficar comprando e vendendo o veículo o tempo todo, então pensei em colocar um SetTimer para limitar o uso do comando caso ele seja executado de novo. E seja liberado depois de 1 hora por exemplo. O uso do SetTimeEx serve para fazer isso, se puder me dar uma luz de código alternativo mais simples, valeu irmão


RE: SetTimer e SetTimerEx - Básico - Levi.M - 24/11/2022

Você vai ter que criar algo pra salvar o tempo que você quer, porque se o jogador deslogar e logar novamente não vai funcionar corretamente. SetTimerEx é apenas para jogador, SetTimer para uso global.