[Tutorial] Temporizaзгo.
#1

Temporizaзгo.
Por rjjj ou Ken




Temporizaзгo й a programaзгo da execuзгo de determinado cуdigo para um momento situado apуs um certo intervalo de tempo .



Em Pawn, hб vбrias tйcnicas que podem ser usadas para a aplicaзгo da temporizaзгo, dentre elas, a mais conhecida й a do SetTimer .





1 - A funзгo sleep.



O sleep foi produzido para ser capaz de fazer com que o servidor, antes de ler qualquer outro cуdigo do GM, tenha que aguardar um certo tempo, que й especificado em seu ъnico parвmetro .



pawn Код:
sleep(/*Tempo em milissegundo.*/);  //Obs: 1 segundo (s) й equivalente a 1000 milissegundos (ms).


Essa funзгo sу deve ser usada no main() do GameMode .


Exemplo de uso:



pawn Код:
main()
{
    print("Aguarde 2 segundos...");  //Mostra uma mensagem no console do samp-server.exe.
    sleep(2000); //Faz o GameMode esperar 2 segundos.
    print("GameMode carregado :D !"); //Passados 2 segundos, й mostrada uma nova mensagem.
}



Em alguns GameModes cheguei a presenciar execuзхes infinitas de funзхes e erros do tipo Run Time causados pela utilizaзгo do sleep, por isso recomendo que apуs a inserзгo dele em um cуdigo, um teste seja feito para que se tenha certeza de que tudo funciona sem problemas.






2 - Loops demorados.



Й possнvel gerar o mesmo efeito do sleep usando loops demorados, veja um exemplo :



pawn Код:
main()
{
    print("Aguarde 2 segundos...");  //Mostra uma mensagem no console do samp-server.exe.
    for(new x; x != 100000000;) x++; //Faz o GameMode esperar aproximadamente 2 segundos.
    print("GameMode carregado :D !"); //Passados 2 segundos, й mostrada uma nova mensagem.
}


Contudo, esse mйtodo pode ser utilizado em qualquer callback, inclusive de Filterscripts.


Ele tambйm, ao contrбrio do sleep, funciona no jogo propriamente dito, parando para os players coisas como o chat, como se fosse um tipo de "Lag" passageiro .


Para tornar esse cуdigo mais prбtico, montei a seguinte macro:



pawn Код:
#define sleep2(%0);  for(new _@%0; _@%0 != (%0*50000000);) (_@%0++);



Exemplo de como usб-la:



pawn Код:
SendClientMessageToAll(0x33CCFFAA, "O servidor ficarб travado durante 3 segundos por motivos tйcnicos.");
sleep2(3);  //O tempo direcionado ao parвmetro deve estar em segundos.
SendClientMessageToAll(0xFFFFFFAA, "Concluнdo.");




3 - SetTimer.



A funзгo SetTimer serve para adiar a leitura de um cуdigo, mas sem fazer com que outros parem .


Й obrigatуrio que esse cуdigo seja uma callback, isto й, seja criado com as estruturas public e forward .


A callback por sua vez nгo pode ter parвmetros, devendo ser criada com os parкnteses () que seguem seu nome, vazios:


Exemplo de callback:



pawn Код:
forward GenkiDama();      //Escolhe-se o nome da callback e escreve-se  "forward NomedaCallback();" ou apenas "NomedaCallback();".  Veja que os parкnteses () estгo vazios, o que й correto.
public GenkiDama()        //Em seguida escreve-se "public NomedaCallback" (sem o ponto e vнrgula) e chaves {}, com o cуdigo a ser executado dentro delas.   Veja que os parкnteses () estгo novamente vazios, o que й correto.
{  
    SendClientMessageToAll(0x33CCFFAA, "Deem um pouco de sua energia !");  //Cуdigo interno.
    return true;
}


Bem, estes sгo os parвmetros da funзгo SetTimer:



pawn Код:
SetTimer("NomeDaCallback", /*Tempo em milissegundos.*/, /*Repetir sempre.*/);


No ъltimo parвmetro (onde estб "Repetir sempre", acima) coloca-se true para que a callback seja executada sempre que se passar um tempo equivalente aos milissegundos especificados, e false para que ela seja lida apenas 1 vez .



Exemplo 1:



pawn Код:
//Dentro de algum comando ou funзгo:

SetTimer("IniciarCorrida", 5000, false);   //Programa a exibiзгo de uma mensagem para daqui a 5 segundos. Como no terceiro parвmetro estб o sнmbolo "false", a callback IniciarCorrida serб executada apenas 1 vez, consequentemente, a mensagem serб mandada apenas 1 vez tambйm.



//No Final do GM, fora de qualquer outro cуdigo:

forward IniciarCorrida();
public IniciarCorrida()    //Passados 5 segundos, a mensagem й enviada.
{
    SendClientMessageToAll(0xFFFFFFAA, "A corrida comeзou !");  //Mensagem.
    return true;
}


Exemplo 2:



pawn Код:
//No OnGameModeInit:

SetTimer("SkinWoozie", 1000, true);   //Programa uma verificaзгo de todos os jogadores, a fim de saber quem estб com com a skin do Woozie, para daqui a 1 segundo. Como no terceiro parвmetro estб o sнmbolo "true", sempre que 1 segundo se passar a callback "SkinWoozie" serб executada, consequentemente, a verificaзгo serб efetuada.



//No Final do GM, fora de qualquer outro cуdigo:

forward SkinWoozie();
public SkinWoozie()    //Passado 1 segundo, os jogadores sгo checados.
{
    for(new x = 0; x != MAX_PLAYERS; x++)  //Este loop permite que a verificaзгo analise todos os jogadores.
    {
        if(GetPlayerSkin(x) == 294)  //Se a skin for detectada em um jogador.
        {
            SendClientMessage(x, 0x33CCFFAA, "Vocк estб com a skin do Woozie !");//...Uma mensagem й enviada ao mesmo.
        }
    }
    return true;
}



Vale ressaltar que o perнodo do Temporizador (ou Timer), a entidade criada pelo SetTimer para cuidar de determinada callback, serб sempre relativo ao momento no qual ele foi gerado.






4 - SetTimerEx.



A diferenзa entre o SetTimer e o SetTimerEx й que este ъltimo funciona sem problemas com callbacks que possuem parвmetros, isto й, que sгo criadas com variбveis/constantes dentro de seus parкnteses () .


Exemplo de callback com parвmetros:



pawn Код:
forward lol(playerid);
public lol(playerid);   //Essa callback tem 1 parвmetro, a variбvel "playerid".
{
    SendClientMessage(playerid, 0xFFFFFFAA, "Oi !");
    return true;
}



Mas como se usaria esse cуdigo de modo que playerid fosse igual a 4 e assim a mensagem fosse enviada ao jogador de ID 4 apуs um certo tempo ?


Bem, vejamos os parвmetros da funзгo SetTimerEx:



pawn Код:
SetTimerEx("NomeDaCallback", /*Tempo em milissegundos.*/, /*Repetir sempre*/, /*Caracteres para a identificaзгo dos tipos de valores nos parвmetros da callback.*/, /*Valores passados aos parвmetros.*/);


Os 3 primeiros parвmetros trabalham de maneira idкntica aos correspondentes a eles no SetTimer .


Quanto aos 2 ъltimos:


O quarto (onde estб escrito "Caracteres para a identificaзгo dos tipos valores nos parвmetros da callback.", acima) deve conter, entre aspas e um ao lado do outro, sнmbolos que identifiquem a natureza dos elementos que serгo colocados nos parвmetros da callback (string, nъmero inteiro, entre outros).


Os principais sгo:



pawn Код:
"d" ou "i" para nъmeiros inteiros (integers).
"f" para nъmeros floating-point (floats, nъmeros racionais com um ponto ".").
"s" para strings (textos).



Jб o quinto (onde estб escrito "Valores passados aos parвmetros", acima) deve conter, entre vнrgulas, os prуprios elementos que serгo direcionados aos parвmetros da callback .



Por exemplo, se eu quisesse fazer com que, passados 9 segundos, a callback lol que citei anteriormente (lembra dela ? ) fosse executada a fim de que a mensagem "Oi !" fosse enviada ao jogador de ID 4 :



pawn Код:
SetTimerEx("lol", 9000, false, "i", 4);  // 4 por que queremos que o "playerid" da callback seja igual a esse nъmero e "i" por que 4 й um nъmero inteiro.



Outro exemplo, mais complexo:



pawn Код:
//Dentro de algum comando ou funзгo:
new id_jogador= 12;
SetTimerEx("AvisoRegras", 4000, false, "ds", id_jogador, "Cuidado com as regras !");  //  "ds" por que a variбvel "id_jogador" e o texto "Cuidado com as regras" podem ser considerados, respectivamente, um nъmero inteiro e uma string.  O motivo de "d" (vendo da esquerda para a direita) vir primeiro que "s" em "ds" й o fato de "id_jogador" vir primeiro que o texto "Cuidado com as regras !" na linha do SetTimerEx.



//No Final do GM, fora de qualquer outro cуdigo:


forward AvisoRegras(playerid, texto[]);
public AvisoRegras(playerid, texto[]);   //Como o SetTimerEx enviou os seguintes valores, nesta ordem:  a variбvel "id_jogador" e a string "Cuidado com as regras !", nesse cуdigo de callback, as variбveis "playerid" e "texto" serгo, respectivamente, iguais a eles.
{
    SendClientMessage(playerid, 0xFFFFFFAA, texto);  //Mandarб a mensagem "Cuidado com as regras !" ao jogador de ID 12.
    return true;
}




5 - KillTimer.



Uma vez criado um Timer, й possнvel parб-lo por meio da funзгo KillTimer .


Os parвmetros dela sгo:



pawn Код:
KillTimer(/*ID do Temporizador*/);


Mas como saber o ID de um Timer responsбvel por certa callback a fim de bloquear sua execuзгo ? .


Basta criar uma variбvel e, na hora de usar o SetTimer/SetTimerEx, igualб-la a ele.


Assim essa variбvel irб armazenar o ID do Timer e serб possнvel usб-la para chegar atй ele.


Exemplo:



pawn Код:
//Dentro de algum comando ou funзгo:

new TimerID;
TimerID = SetTimer("ServerGMX", 5000, false); //Programa um GMX para daqui a 5 segundos.
KillTimer(TimerID); //Destrуi o Timer da callback ServerGMX, com isso, o GMX que seria feito й cancelado.


//No Final do GM, fora de qualquer outro cуdigo:

forward ServerGMX();
public ServerGMX()
{
    SendRconCommand("gmx");
    return true;
}





6 - Outros.



Hб tambйm as funзхes gettime, getdate, GetTickCount e tickcount, que capturam dados de um momento especнfico no tempo, e por isso, podem ser usadas para gerar uma temporizaзгo por meio da criaзгo de sistemas de referкncia entre dados antigos e dados recentes .


Exemplo:



pawn Код:
//No Topo do GM:

new ComandoBloqueado;


//Em um comando:

if((gettime() - ComandoBloqueado) < 30) return SendClientMessage(playerid, 0xFFFFFFAA, "Comando bloqueado !");
ComandoBloqueado = gettime();


No caso acima, o comando em questгo seria bloqueado se o nъmero de segundos (essa unidade de medida devido ao gettime) passados desde a ъltima vez que ele foi usado fosse menor que 30.



E й isso .



Espero ter ajudado .
Reply
#2

Bom tutorial, mais esqueceu de citar que o GetTickCount e TickCount comeзam a contar quando o servidor й iniciado..
Reply
#3

Muito bom! Concordo com a Caroline.

@EDIT
Hб algum tipo de tutorial que ensine essas coisas:
pawn Код:
_@%0
Jб vi scripts impressionantes que tкm essas coisa, e nunca consegui compreender. E como elas se chamam?
Reply
#4

muito bom tuto.
Reply
#5

Quote:
Originally Posted by Adrian Fahrenheit Tepes
Посмотреть сообщение
Muito bom! Concordo com a Caroline.

@EDIT
Hб algum tipo de tutorial que ensine essas coisas:
pawn Код:
_@%0
Jб vi scripts impressionantes que tкm essas coisa, e nunca consegui compreender. E como elas se chamam?
Isto nгo й nenhum truque.
agore pense comigo:
temos a funзгo "Sleep2"
pawn Код:
#define sleep2(%0);  for(new _@%0; _@%0 != (%0*50000000);) (_@%0++); //

public OnGameModeInit()
{
     sleep2(20); // 20 Segundos.
     return 1;
}
Agora imaginamos que %0 й igual o valor dado a funзгo, no nosso caso, 20 segundos.
o nosso amigo Rjj colocou _@ para criar uma variavel, ficando _@20
nгo hб segredos algum, porque _@ sгo somente sнmbolos.

Outro exemplo:
pawn Код:
SetTimer("@Tempo", 100, 1);

forward @Tempo();
public @Tempo() return 1;
Agora, se vocк estб falando de operadores avanзados:
Код:
~=
^=
|=
etc ...
terбs que aprender nъmeros binбrios primeiro.
Reply
#6

AH! Entendi, obrigado.
Reply
#7

Quote:
Originally Posted by [O.z]Caroline
Посмотреть сообщение
Bom tutorial, mais esqueceu de citar que o GetTickCount e TickCount comeзam a contar quando o servidor й iniciado..
Quote:
Originally Posted by Adrian Fahrenheit Tepes
Посмотреть сообщение
Muito bom! Concordo com a Caroline.
Atй pensei em detalhar as funзхes que citei na ъltima parte do tуpico, mas acabei nгo fazendo isso por que alйm de eu ter ultrapassado o limite de imagens permitido: .


Eu estaria meio que desviando do assunto central do tуpico, por isso ensinei o raciocнnio que й normalmente usado e deixei que o leitor do tutorial descobrisse sozinho as particularidades de cada uma .




Quote:
Originally Posted by Adrian Fahrenheit Tepes
Посмотреть сообщение
@EDIT
Hб algum tipo de tutorial que ensine essas coisas:
pawn Код:
_@%0
Jб vi scripts impressionantes que tкm essas coisa, e nunca consegui compreender. E como elas se chamam?
Nгo sei se hб, mas como a Caroline disse, utilizei os caracteres: _ e @ por que sгo aceitos como parte do nome de uma variбvel .


No caso desse cуdigo, usб-los diminui a probabilidade da variбvel do loop ter o mesmo nome de outra do GM/FS .



Espero ter ajudado .
Reply
#8

Quote:
Originally Posted by rjjj
Посмотреть сообщение
Atй pensei em detalhar as funзхes que citei na ъltima parte do tуpico, mas acabei nгo fazendo isso por que alйm de eu ter ultrapassado o limite de imagens permitido: .


Eu estaria meio que desviando do assunto central do tуpico, por isso ensinei a tйcnica que й normalmente usada e deixei que o leitor do tutorial descobrisse sozinho as particularidades de cada uma .







Nгo sei se hб, mas como o Garfield disse, utilizei os caracteres: _ e @ por que sгo aceitos como parte do nome de uma variбvel .


No caso desse cуdigo, usб-lo diminui a probabilidade da variбvel do loop ter o mesmo nome de outra do GM/FS .



Espero ter ajudado .
nomes de loop, nгo hб possibilidade de erros!.

pawn Код:
for(new i; i != 500; ++i) { printf("%d", i); }
for(new i; i != 500; ++i) { printf("%d", i); }
for(new i; i != 500; ++i) { printf("%d", i); }
Ha nгo ser que um loop seja dentro do outro:
pawn Код:
for(new i; i != 500; ++i)
{
for(new i; i != 500; ++i)
{ printf("%d", i);
}
printf("%d", i);
}
Reply
#9

Quote:
Originally Posted by [O.z]Caroline
Посмотреть сообщение
nomes de loop, nгo hб possibilidade de erros!.

pawn Код:
for(new i; i != 500; ++i) { printf("%d", i); }
for(new i; i != 500; ++i) { printf("%d", i); }
for(new i; i != 500; ++i) { printf("%d", i); }
Ha nгo ser que um loop seja dentro do outro:
pawn Код:
for(new i; i != 500; ++i)
{
for(new i; i != 500; ++i)
{ printf("%d", i);
}
printf("%d", i);
}

Eu quis dizer que diminui a probabilidade de um fato deste tipo ocorrer :


pawn Код:
//No Topo do GM:

new Contador;


//Em alguma public:

for(new Contador = 0; Contador != MAX_PLAYERS; Contador++)
{
    if(IsPlayerConnected(Contador)) printf("%i", Contador);
}

pawn Код:
warning 219: local variable "Contador" shadows a variable at a preceding level.

Por exemplo, se eu tivesse declarado a variбvel do loop com o nome "x" no cуdigo do sleep2 e o GM de quem o usasse tivesse uma variбvel com este nome tambйm, problemas aconteceriam .


E desculpe Caroline, percebi que me referi a vocк por outro nome sem querer no meu ъltimo post, mas jб editei o mesmo .



Qualquer dъvida sobre o assunto do tуpico, perguntem !



Espero ter ajudado .
Reply
#10

tu ainda nгo morreu
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)