GTA-Expert Forum: [GUIDA] zcmd e sscanf - GTA-Expert Forum

Salta al contenuto

Pagina 1 di 1
  • Non puoi iniziare una nuova discussione
  • Non puoi rispondere a questa discussione

[GUIDA] zcmd e sscanf

#1 L'utente è offline   Peppe951 

  • Tirapiedi
  • Gruppo: Utenti
  • Messaggi: 899
  • Iscritto il: 14/07/09
  • GTA Preferito:Sconosciuto

Inviato il 09 febbraio 2010 - 15:17

Questa guida vi insegnerà ad ottimizzare il vostro codice, rendendolo non solo più semplice ma anche molto più veloce nell'esecuzione!

zcmd

Questo include ha lo scopo di velocizzare l'esecuzione dei comandi, ancor di più del dcmd. Infatti usa il CallLocalFunction per eseguire un public che corrisponde a quello del comando...
Copiate il codice dell'include in un file "zcmd.inc" nella cartella include del pawno.
Il codice lo potete prendere da qui: http://zeex.pastebin.ca/1650602
Mettete "#include " in cima alla vostra gm o fs... se è un fs mettete anche "#define FILTERSCRIPT".
Aggiungere comandi è semplicissimo: basta aggiungere fuori da tutto:
COMMAND:nomecomando(playerid, params[])
{
    //cosa deve fare il comando
    return 1;
}

params sarebbe quello che scrivete dopo il comando.

sscanf

Il sscanf è un'ottima alternativa al sstrok, in quanto molto più veloce nell'esecuzione e più facile da usare e lo potete abbinare al zcmd o anche al dcmd...
Ecco il codice:
stock sscanf(string[], format[], {Float,_}:...)
{
	#if defined isnull
  if (isnull(string))
	#else
  if (string[0] == 0 || (string[0] == 1 && string[1] == 0))
	#endif
  {
  	return format[0];
  }
	#pragma tabsize 4
	new
  formatPos = 0,
  stringPos = 0,
  paramPos = 2,
  paramCount = numargs(),
  delim = ' ';
	while (string[stringPos] && string[stringPos] <= ' ')
	{
  stringPos++;
	}
	while (paramPos < paramCount && string[stringPos])
	{
  switch (format[formatPos++])
  {
  	case '\0':
  	{
    return 0;
  	}
  	case 'i', 'd':
  	{
    new
    	neg = 1,
    	num = 0,
    	ch = string[stringPos];
    if (ch == '-')
    {
    	neg = -1;
    	ch = string[++stringPos];
    }
    do
    {
    	stringPos++;
    	if ('0' <= ch <= '9')
    	{
      num = (num * 10) + (ch - '0');
    	}
    	else
    	{
      return -1;
    	}
    }
    while ((ch = string[stringPos]) > ' ' && ch != delim);
    setarg(paramPos, 0, num * neg);
  	}
  	case 'h', 'x':
  	{
    new
    	num = 0,
    	ch = string[stringPos];
    do
    {
    	stringPos++;
    	switch (ch)
    	{
      case 'x', 'X':
      {
      	num = 0;
      	continue;
      }
      case '0' .. '9':
      {
      	num = (num << 4) | (ch - '0');
      }
      case 'a' .. 'f':
      {
      	num = (num << 4) | (ch - ('a' - 10));
      }
      case 'A' .. 'F':
      {
      	num = (num << 4) | (ch - ('A' - 10));
      }
      default:
      {
      	return -1;
      }
    	}
    }
    while ((ch = string[stringPos]) > ' ' && ch != delim);
    setarg(paramPos, 0, num);
  	}
  	case 'c':
  	{
    setarg(paramPos, 0, string[stringPos++]);
  	}
  	case 'f':
  	{
 
    new changestr[16], changepos = 0, strpos = stringPos;     
    while(changepos < 16 && string[strpos] && string[strpos] != delim)
    {
    	changestr[changepos++] = string[strpos++];
        } 
    changestr[changepos] = '\0'; 
    setarg(paramPos,0,_:floatstr(changestr)); 
  	} 
  	case 'p':
  	{
    delim = format[formatPos++];
    continue;
  	}
  	case '\'':
  	{
    new
    	end = formatPos - 1,
    	ch;
    while ((ch = format[++end]) && ch != '\'') {}
    if (!ch)
    {
    	return -1;
    }
    format[end] = '\0';
    if ((ch = strfind(string, format[formatPos], false, stringPos)) == -1)
    {
    	if (format[end + 1])
    	{
      return -1;
    	}
    	return 0;
    }
    format[end] = '\'';
    stringPos = ch + (end - formatPos);
    formatPos = end + 1;
  	}
  	case 'u':
  	{
    new
    	end = stringPos - 1,
    	id = 0,
    	bool:num = true,
    	ch;
    while ((ch = string[++end]) && ch != delim)
    {
    	if (num)
    	{
      if ('0' <= ch <= '9')
      {
      	id = (id * 10) + (ch - '0');
      }
      else
      {
      	num = false;
      }
    	}
    }
    if (num && IsPlayerConnected(id))
    {
    	setarg(paramPos, 0, id);
    }
    else
    {
    	#if !defined foreach
      #define foreach(%1,%2) for (new %2 = 0; %2 < MAX_PLAYERS; %2++) if (IsPlayerConnected(%2))
      #define __SSCANF_FOREACH__
    	#endif
    	string[end] = '\0';
    	num = false;
    	new
      name[MAX_PLAYER_NAME];
    	id = end - stringPos;
    	foreach (Player, playerid)
    	{
      GetPlayerName(playerid, name, sizeof (name));
      if (!strcmp(name, string[stringPos], true, id))
      {
      	setarg(paramPos, 0, playerid);
      	num = true;
      	break;
      }
    	}
    	if (!num)
    	{
      setarg(paramPos, 0, INVALID_PLAYER_ID);
    	}
    	string[end] = ch;
    	#if defined __SSCANF_FOREACH__
      #undef foreach
      #undef __SSCANF_FOREACH__
    	#endif
    }
    stringPos = end;
  	}
  	case 's', 'z':
  	{
    new
    	i = 0,
    	ch;
    if (format[formatPos])
    {
    	while ((ch = string[stringPos++]) && ch != delim)
    	{
      setarg(paramPos, i++, ch);
    	}
    	if (!i)
    	{
      return -1;
    	}
    }
    else
    {
    	while ((ch = string[stringPos++]))
    	{
      setarg(paramPos, i++, ch);
    	}
    }
    stringPos--;
    setarg(paramPos, i, '\0');
  	}
  	default:
  	{
    continue;
  	}
  }
  while (string[stringPos] && string[stringPos] != delim && string[stringPos] > ' ')
  {
  	stringPos++;
  }
  while (string[stringPos] && (string[stringPos] == delim || string[stringPos] <= ' '))
  {
  	stringPos++;
  }
  paramPos++;
	}
	do
	{
  if ((delim = format[formatPos++]) > ' ')
  {
  	if (delim == '\'')
  	{
    while ((delim = format[formatPos++]) && delim != '\'') {}
  	}
  	else if (delim != 'z')
  	{
    return delim;
  	}
  }
	}
	while (delim > ' ');
	return 0;
}

PS: è uscita la versione tramite plugin che sembra essere più veloce, questa è la versione 1.0
Il sscanf è il contrario del format e serve a dividere una stringa in più variabili/stringhe... in questo caso lo useremo per analizzare il params, ovvero quello che scriviamo dopo un comando...
Ecco il codice di un comando (zcmd) con l'sstrok
COMMAND:goto(playerid, params[])
	{
     if(IsPlayerConnected(playerid))
     {
  	if(!strlen(params))
  	{
    SendClientMessage(playerid, COLOR_GRAD2, "USAGE: /goto [playerid/PartOfName]");
    return 1;
  	}
  	new Float:plocx,Float:plocy,Float:plocz;
  	new plo;
  	plo = ReturnUser(tmp);
  	if (IsPlayerConnected(plo))
  	{
       if(plo != INVALID_PLAYER_ID)
       {
                         GetPlayerPos(id, plocx, plocy, plocz);
                	SetPlayerPos(playerid,plocx,plocy+2, plocz);
    }
  	}
  	else
  	{
    format(string, sizeof(string), "  L'ID %d non è collegato.", plo);
    SendClientMessage(playerid, COLOR_GRAD1, string);
  	}
  }
  return 1;
	}

Ed ecco come diventerà con il sscanf:
COMMAND:goto(playerid, params[])
	{
     if(IsPlayerConnected(playerid))
     {
  	
  	new Float:plocx,Float:plocy,Float:plocz;
 
                       new id;
  	if (sscanf(params, "u", id)) SendClientMessage(playerid, 0xFF0000AA, "USARE: \"/goto <playerid/partname>\"");
	else if (id == INVALID_PLAYER_ID) SendClientMessage(playerid, 0xFF0000AA, "Giocatore non trovato.");
                        else
  	{
                            GetPlayerPos(id, plocx, plocy, plocz);
                     SetPlayerPos(playerid,plocx,plocy+2, plocz);
  	}

  }
  return 1;
	}


Quindi per usarlo prima di tutto dovete creare le variabili/stringhe:
new id;

Poi mettete un if con il sscanf così
if (sscanf(params, "u", id)) SendClientMessage(playerid, 0xFF0000AA, "USARE: \"/goto <playerid/partname>\"");


In questo modo se il parametro del comando non è del tipo "user" returna 1 e manda un messaggio che dice come si usa il comando.
Quindi dovete impostare il comando sscanf come se fosse un timerex, specificando le variabili e il tipo
sscanf(params, tipidivariabile, variabili...);
I tipi di variabili sono
c - carattere unico
d, i - Intero
h, x - Numero Hex (esempio: colore)
f - Float
s - Stringa
z - Stringa opzionale
pX - An additional delimiter where X is another character.
'' - Encloses a litteral string to locate.
u - User, può essere il nome dell'user o l'id, returna l'id e INVALID_PLAYER_ID se non è connesso

Quindi se ad esempio vogliamo settare l'angolo ad un player, per controllare se i parametri del comando sono stati fatti correttamente basta fare così:
new id, Float:angle;
if (sscanf(params, "uf", id, angle)) SendClientMessage(playerid, 0xFF0000AA, "USARE: \"/setangle <playerid/partname> <angle>\"");

In questo modo se il comando non è stato scritto correttamente manda un messaggio al player.
0

#2 L'utente è offline   Skiaffo 

  • Boss
  • Gruppo: Moderatori
  • Messaggi: 14732
  • Iscritto il: 08/12/05
  • Provenienza:Urbs Aeterna
  • GTA Preferito:GTA V

Inviato il 09 febbraio 2010 - 16:18

Bella guida, metto importante
"Audentes Fortuna iuvat"
0

#3 L'utente è offline   Angelo_95 

  • Cacciatore di taglie
  • Gruppo: Utenti
  • Messaggi: 1620
  • Iscritto il: 31/08/09
  • Provenienza:Area 51
  • GTA Preferito:GTA: San Andreas

Inviato il 09 febbraio 2010 - 16:30

bella guida :D però scusate l'up ma non ho ancora capito che cambia tra zcmd o cmdtext o dcmd o cmd potete spiegarmelo ? :D
Immagine Postata
0

#4 L'utente è offline   Peppe951 

  • Tirapiedi
  • Gruppo: Utenti
  • Messaggi: 899
  • Iscritto il: 14/07/09
  • GTA Preferito:Sconosciuto

Inviato il 09 febbraio 2010 - 16:35

il zcmd è facile come il dcmd da usare ma anche molto più veloce del dcmd o dei classici comandi con il cmdtext/cmd
0

Pagina 1 di 1
  • Non puoi iniziare una nuova discussione
  • Non puoi rispondere a questa discussione

1 utenti stanno leggendo questa discussione
0 utenti, 1 ospiti, 0 utenti anonimi