• 28 Mars 2024, 22:49:35


Auteur Sujet: Trucs et astuces en Pawn  (Lu 11735 fois)

0 Membres et 1 Invité sur ce sujet

Hors ligne Gzsume

  • *
  • Compétent dans l'inutile
  • Messages: 2236
    • Voir le profil
Trucs et astuces en Pawn
« le: 21 Mai 2014, 05:05:00 »
Salut,

J'ai eu envie de créer un topic pour recenser les trucs et astuces à connaître lorsqu'on développe avec le langage Pawn. Certaines sont évidentes, d'autres un peu plus mystérieuses... L'objectif de ce topic est donc d'apprendre de nouvelles choses, que vous soyez un vétéran ou un débutant. N'hésitez pas à contribuer, ce serait cool de prolonger la liste avec vos connaissances.




Fonctions de type public

On peut déclarer une fonction de type public de la manière suivante :

Code: (pawn) [Sélectionner]
forward public Fonction();
L'intérêt n'est pas énorme, mais ça permet de mieux s'y retrouver si vous développez des scripts un peu longs.



Concaténation et arguments

Il est possible de concaténer des chaînes de caractères passées en arguments d'une fonction. Exemple avec un message envoyé aux joueurs :

Code: (pawn) [Sélectionner]
#define CLR_BLEU "{0000FF}"
SendClientMessageToAll(-1, "Cette phrase écrite en blanc" CLR_BLEU "devient bleue");



Index de boîtes de dialogue

Plutôt que d'utiliser le code suivant pour définir les index de vos boîtes de dialogue :

Code: (pawn) [Sélectionner]
#define DIALOG_INSCRIPTION (1)
#define DIALOG_CONNEXION (2)
#define DIALOG_CHOIXTEAM (3)
...

Vous pouvez utiliser un simple énumérateur, de cette façon :
Code: (pawn) [Sélectionner]
enum
{
    DIALOG_INSCRIPTION,
    DIALOG_CONNEXION,
    DIALOG_CHOIXTEAM
};

// Au moment de créer votre boîte de dialogue
ShowPlayerDialog(playerid, DIALOG_INSCRIPTION, ...);

Par défaut, le premier élément d'un énumérateur portera l'index 0 et s'incrémentera de 1 pour chaque élément suivant. Les deux codes sont donc identiques, même si le premier ne consommera aucune place en mémoire (les directives de préprocesseurs n'étant pas présentes dans la version compilée). L'avantage, c'est que si vous supprimez une boîte de dialogue en cours de route, les index continueront de se suivre, puisque énumérateur les attribue dynamiquement (j'entends par là, à chaque compilation et ce de manière automatique).



OnGameModeExit()

Ce n'est pas une astuce mais un petit truc à savoir, la callback OnGameModeExit() n'est pas appelée lorsque vous fermez le processus du serveur (aka. la console) via la croix rouge. Par contre, il est correctement appelé lorsque vous tapez exit dans la console, comme c'est normalement attendu.




Erreurs de compilation personnalisées

Il est possible de créer ses propres erreurs de compilation avec le mot-clé de préprocesseur #error. Un petit exemple :

Code: (pawn) [Sélectionner]
main()
{
    #if !defined TEST
        #error Ceci est une erreur
    #endif
}

Affichage lors de la compilation :
Citer
C:\Users\...\tests.pwn(6) : fatal error 111: user error: Ceci est une erreur

Compilation aborted.Pawn compiler 3.2.3664           Copyright (c) 1997-2006, ITB CompuPhase

1 Error.



Fonctions de type public et gmx

Les fonctions de type public présentes dans des filterscripts sont toujours actives lorsque vous envoyez un gmx via le jeu ou la console. Ainsi, en utilisant OnPlayerText() par exemple, vous pouvez continuer d'utiliser la chatbox pendant que le gamemode redémarre.




Vérifier si une valeur est comprise entre deux autres

Jusqu'ici, il se peut que lorsque vous souhaitiez vérifier que la valeur numérique d'une variable (nommons-la var) était comprise entre deux autres valeurs, vous tapiez cette condition :

Code: (pawn) [Sélectionner]
if (var > 3 && var < 6)
Ça fonctionne, mais il y a une méthode bien plus simple permise avec le langage Pawn :
Code: (pawn) [Sélectionner]
if (3 < var < 6)
Les deux codes ont le même effet, le second est cependant plus agréable à lire et à écrire.



Incrémentation dans une boucle de type while

Vous pouvez incrémenter une variable numérique dans une boucle while (presque) de la même manière que vous le faîtes avec une boucle for. Un exemple avec ce code :

Code: (pawn) [Sélectionner]
new Line = 0;

while (Line++ < 10)
{
    printf("Line %d", Line);
}

Ce qui affiche en console :
Citer
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10

L'explication est toute simple : à la lecture de la condition de la boucle, la variable Line est incrémentée de 1, puis la condition est vérifiée.



Récupérer la taille d'un tableau multi-dimensionnel

Vous pouvez récupérer la taille (aka. le nombre de cases/lignes) d'un tableau multi-dimensionnel de la manière suivante :

Code: (pawn) [Sélectionner]
tab[5][10][20];

printf("%d %d %d", sizeof tab, sizeof tab[], sizeof tab[][]);

Ce qui affiche en console :
Citer
5 10 20



Retenir une ligne avec Pawno

C'est une petite astuce qui peut être utilisée sous l'IDE Pawno (celui par défaut). CTRL + SHIFT (MAJ) + <0...9> vous permet de retenir une ligne. Pour vous y rendre, utilisez CTRL + <0...9>. L'IDE va alors directement vous amener à la ligne marquée. Utiliser CTRL + SHIFT (MAJ) + <0...1> une seconde fois permet de retirer le marquage d'une ligne. C'est vraiment pratique lorsqu'on développe un long script.




Exemple avec une ligne marquée



Récupérer le nombre d'arguments passés à une fonction

Vous pouvez utiliser la fonction numargs() pour récupérer le nombre d'arguments passés à une fonction. De plus, la fonction getarg() permet de récupérer un argument, en précisant lequel (par ordre chronologique). Par exemple, dans le cas d'une fonction de type Fonction(5, 12, 37), getarg(1) retournera 12. Notez que l'index des arguments débute à 0 mais que le nombre d'arguments est bien valide. Exemple :

Code: (pawn) [Sélectionner]
main()
{
    Fonction(1, 12, 37);
}

stock Fonction(...)
{
    printf("Arguments : %d", numargs());
    printf("Argument 0 : %d", getarg(0));
    printf("Argument 1 : %d", getarg(1));
    printf("Argument 2 : %d", getarg(2));
    return 1;
}

Affichage en console :
Citer
Arguments : 3
Argument 0 : 1
Argument 1 : 12
Argument 2 : 37



Scroller plus vite sous Pawno

Une autre petite astuce avec l'IDE Pawno, vous pouvez scroller beaucoup plus vite en maintenant la touche CTRL pendant que vous scrollez. Pratique dans le cas de longs scripts.




Initialiser de gros tableaux

Plutôt que d'utiliser une boucle qui va initialiser vos tableaux, vous pouvez suivre cette méthode :

Code: (pawn) [Sélectionner]
main()
{
    new GrosTableau[1024] = {12, ...};

    printf("Case 0 : %d", GrosTableau[0]);
    printf("Case 1 : %d", GrosTableau[1]);
    printf("Case 5 : %d", GrosTableau[5]);
    printf("Case 500 : %d", GrosTableau[500]);
    printf("Case 1023 : %d", GrosTableau[1023]);
}

Les 1024 cases du tableaux seront initialisées avec la valeur 12. Affichage en console :
Citer
Case 0 : 12
Case 1 : 12
Case 5 : 12
Case 500 : 12
Case 1023 : 12



OnGameModeInit appelé deux fois

Ce n'est pas une astuce, mais un petit bug que j'ai découvert en développant il y a quelques jours. Si le point d'entrée d'un gamemode se présente sous cette forme (1) plutôt que sur la forme originale (2), la callback OnGameModeInit est appelée deux fois.

Code: (pawn) [Sélectionner]
main(); // (1) Forme qui cause le bug
main() {} // (2) Forme originale

Un exemple avec ce code et son affichage en console :
Code: (pawn) [Sélectionner]
#include <a_samp>

main();

public OnGameModeInit()
{
    print("OnGameModeInit has been called");

    return 1;
}}
Citer
OnGameModeInit has been called
OnGameModeInit has been called



Récupérer le texte d'un item dans une boîte de dialogue de type list

Bon, le titre est assez long, mais c'est tout bête. Lorsque, dans la callback OnDialogResponse(), vous recevez la réponse d'une boîte de dialogue de type list (DIALOG_STYLE_LIST), l'argument inputtext contient la chaîne de caractère de l'item sélectionné. Par exemple, avec une liste de cette forme :

Citer
- Blabla 1
- Tchutchu 2
- Tagada 3
Si le joueur sélectionne le second item, l'argument inputtext contiendra "Tchutchu 2" (sans les guillemets).



C'est tout pour le moment, mais comme je l'ai précisé en entête de ce message, n'hésitez pas à poster vos petits trucs pour faire s'allonger la liste. Je suis sûr que certaines de ces astuces pourront servir aux gens qui débarquent dans le Pawn. :smile:

Hors ligne Infu

  • *
  • Modo LS - Admin FnF
  • Messages: 3550
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #1 le: 21 Mai 2014, 17:26:28 »
Certains débutants ne connaissent pas strcat().

Lorsque vous faîtes une boîte de dialogue qui contient un long texte ; il se peut que Pawno vous retourne une erreur. Voici comment arranger ceci.

Code: (pawn) [Sélectionner]
new str[500];

strcat(str, "Règles\n", sizeof(str));
strcat(str, "Les insultes sont interdites, ainsi que le flood.\n", sizeof(str));
strcat(str, "Les bugs armes (cbug/switch) ne sont pas tolérés.\n", sizeof(str));
strcat(str, "Le spawn kill est interdit.\n", sizeof(str));
strcat(str, "Le NOF(No Fair Play) est sanctionné quand il est appliqué de façon abusive.\n", sizeof(str));
strcat(str, "L'abus de majuscules n'est pas toléré.\n", sizeof(str));
strcat(str, " \n", sizeof(str)); // Un saut de ligne.

ShowPlayerDialog(playerid, DIALOG_ID, DIALOG_STYLE_LIST, "Ma boîte de dialogue", str, "Ok", "");
Ne surtout pas oublier \n qui fait en sorte que le texte qui suit se retrouve à la ligne.

PS: @Gzsume pour ton exemple "Retenir une ligne avec Pawno", je tiens juste à préciser que ce n'est pas le pavé numérique qu'il faut utiliser  :tongue:
« Modifié: 21 Mai 2014, 17:31:47 par Infu »


Adju ♥
(-_-)



Hors ligne Ssk

  • *
  • Lulu's Stunt - Le serveur stunt de Lulu !
  • Messages: 8154
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #2 le: 21 Mai 2014, 19:37:46 »
Dans le même genre, on peut faire ça

Code: (pawn) [Sélectionner]
new str[500] =
"Règles\n" \
"Les insultes sont interdites, ainsi que le flood.\n" \
"Les bugs armes (cbug/switch) ne sont pas tolérés.\n" \
"Le spawn kill est interdit.\n" \
"Le NOF(No Fair Play) est sanctionné quand il est appliqué de façon abusive.\n" \
"L'abus de majuscules n'est pas toléré.\n";

ShowPlayerDialog(playerid, DIALOG_ID, DIALOG_STYLE_LIST, "Ma boîte de dialogue", str, "Ok", "");

On peut même mettre directement dans le ShowPlayerDialog



Derrière tout programme se cache un programmeur, je considère le monde comme un programme.
Mon blog

Hors ligne Infu

  • *
  • Modo LS - Admin FnF
  • Messages: 3550
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #3 le: 21 Mai 2014, 20:16:13 »
Ah ouais, je ne pensais pas que c'était possible... Comme quoi on en apprend tous le temps x)


Adju ♥
(-_-)



Hors ligne Kiloutre

  • Nolife, nerd et geek passionné d'Ordinatique ! ^^
  • *
  • Grand Banditisme
  • Messages: 567
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #4 le: 27 Mai 2014, 16:46:28 »
On peut aussi faire des trucs comme ça
Code: (pawn) [Sélectionner]
new index;
if((index = strfind("Are you in here?", "you")) != -1)
{
    printf("Position: %d", index);
}
C'est plutôt utile, ça permet d'économiser une ligne ^^
« Modifié: 27 Mai 2014, 19:10:28 par Kiloutre »

[/url]

Hors ligne Gzsume

  • *
  • Compétent dans l'inutile
  • Messages: 2236
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #5 le: 27 Mai 2014, 18:50:48 »
Économiser une ligne en perdant en confort de lecture, ce n'est pas toujours très intéressant. De plus, la variable index est inutile dans ton cas, puisque on peut directement comparer ce que va retourner la fonction en prenant en compte la possibilité d'un index à zéro. Petit exemple :

Code: (pawn) [Sélectionner]
if (strfind("Are you in here?", "you", true) + 1)
{

}

  • Si la fonction retourne -1, la condition passe à 0 (en raison du +1), et est donc ignorée ;
  • Si la fonction retourne 0 ou un nombre supérieur, la condition passe au minimum à 1 (en raison du +1), et est donc lue ;

Tout en sachant que ce qui vaut 0 ou moins vaut false, et que ce qui vaut 1 ou plus vaut true. On pourrait même utiliser un ternaire (je sais que tu adores ça) :

Code: (pawn) [Sélectionner]
if (strfind("Are you in here?", "you", true) < 0 ? false : true)
{

}

Si la chaîne n'est pas trouvée, ça passe à false, sinon ça passe à true.

Hors ligne Kiloutre

  • Nolife, nerd et geek passionné d'Ordinatique ! ^^
  • *
  • Grand Banditisme
  • Messages: 567
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #6 le: 27 Mai 2014, 19:08:55 »
T'as pas l'air de comprendre que c'est un exemple pour montrer qu'on peut attribuer une valeur à une variable dans une condition ._.
Code: (pawn) [Sélectionner]
if (strfind("Are you in here?", "you", true) + 1)c'est plus coûteux en ressource à cause de l'addition (ok légèrement)
strfind ne retourne pas de booléen, ton code serait fonctionnel mais serait difficile à comprendre pour des personnes qui ne savent pas que true est égal à tout au dessus de 0

Ici tu peux pas contrecarrer mon exemple car ça peut être très utile de récupérer ce que retourne une fonction, et ce dans une condition, nah.
(ça t'apprendra à vouloir faire le fanfaron :angry:)

J'vais prendre un exemple en C++ (j'en ai pas sous la main en pawn)
Ceci
Code: (c++) [Sélectionner]
dir = opendir (osudirectory);
if(dir != NULL) //Blabla
se transforme en
Code: (c++) [Sélectionner]
if ((dir = opendir (osudirectory)) != NULL)
    //blabla
(la variable dir est utilisée plus tard dans le code)
« Modifié: 27 Mai 2014, 19:29:20 par Kiloutre »

[/url]

Hors ligne Gzsume

  • *
  • Compétent dans l'inutile
  • Messages: 2236
    • Voir le profil
Re : Re : Trucs et astuces en Pawn
« Réponse #7 le: 27 Mai 2014, 19:21:47 »
T'as pas l'air de comprendre que c'est un exemple pour montrer qu'on peut attribuer une valeur à une variable dans une condition ._.

Ton exemple peut être interprété de deux façons différentes.
  • Si tu n'as pas besoin de récupérer le retour dans ta condition, alors attribuer une valeur à une variable dans cette dernière est inutile puisque la condition sera lue avec ou sans (et tu utilises de la mémoire pour rien, même si la quantité est infime) ;
  • Si tu as besoin de récupérer le retour dans ta condition, alors ça devient utile mais ça reste dangereux puisqu'un oubli de parenthèses peut transformer ta variable en booléen ;

Code: (pawn) [Sélectionner]
if (strfind("Are you in here?", "you", true) + 1)c'est plus coûteux en ressource à cause de l'addition (ok légèrement)

Je demande un benchmark pour te croire. Réserver un emplacement en mémoire, y attribuer une valeur retournée par une fonction et vérifier une condition, ça me semble plus long que de récupérer une valeur retournée par une fonction et d'y ajouter 1.

Hors ligne Kiloutre

  • Nolife, nerd et geek passionné d'Ordinatique ! ^^
  • *
  • Grand Banditisme
  • Messages: 567
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #8 le: 27 Mai 2014, 20:10:26 »
Je demande
Citer
un benchmark pour te croire. Réserver un emplacement en mémoire, y attribuer une valeur retournée par une fonction et vérifier une condition, ça me semble plus long que de récupérer une valeur retournée par une fonction et d'y ajouter 1.
Pas besoin de benchmark, entre
Code: (pawn) [Sélectionner]
if (strfind("Are you in here?", "you", true) != -1)
//et
if (strfind("Are you in here?", "you", true) + 1 != 0)
Pour comparer, il faut que les situations soient les mêmes, alors soit on utilise des variables avec le deux, soit on n'en utilise pas avec les deux
Citer
Si tu n'as pas besoin de récupérer le retour dans ta condition, alors attribuer une valeur à une variable dans cette dernière est inutile puisque la condition sera lue avec ou sans (et tu utilises de la mémoire pour rien, même si la quantité est infime) ;
Euh, merci, mais tu m'apprends rien ._.

[/url]

Hors ligne Gzsume

  • *
  • Compétent dans l'inutile
  • Messages: 2236
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #9 le: 27 Mai 2014, 21:26:40 »
Mon but n'est pas de t'apprendre quoi que ce soit, mais de corriger une erreur en expliquant ce qui me semble le plus rapide et le plus simple. De plus, lorsque tu reprends mon code tel que ci-dessous :

Code: (pawn) [Sélectionner]
if (strfind("Are you in here?", "you", true) + 1 != 0)
Tu commets une erreur puisque la condition ne va pas vérifier le != 0. Soit ça vaut true et c'est exécuté, soit ça vaut false et c'est ignoré. Dans aucun cas la comparaison ne se fait avec un false. C'est d'ailleurs assez logique, puisqu'il est inutile d'un point de vue algorithmique de tester une condition de la forme true != false. Si on faisait ça, ça vaudrait toujours true. Je peux sans-doute te filer le passage d'une documentation qui explique cela (c'est le même principe pour la plupart des langages de programmation), il faudrait juste que je retrouve ça (et fouiller dans un document de plusieurs centaines de pages pour prouver que j'ai raison, ça me demanderait beaucoup de temps pour un résultat assez inutile). :smile:

Par contre, si tu veux prendre un peu de temps pour mettre au point un benchmark entre ma technique et la tienne, ça m'intéresse. Je pourrais faire ça dans les prochains jours et t'envoyer le résultat, si t'as la flemme. :wink:

Hors ligne CarCrasher

  • *
  • Tueur en série
  • Messages: 144
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #10 le: 11 Juin 2014, 09:53:39 »
Stock

Lors de la déclaration d'une fonction, le "stock" n'est pas obligatoire, il sert à ne pas prendre en compte les warnings de cette fonction comme si vous utilisez une include mais pas toutes ses fonctions par exemple.
Par conséquent, il vaut mieux l'utiliser le moins possible pour ne pas avoir certaines "surprises"


Couleurs

Les couleurs peuvent aussi être exprimées en décimal au lieu de l'hexadécimal, par exemple
0xCC0000 == 13369344, ça n'a pas vraiment d'utilité vu que tous les color pickers et tout ça donnent des résultats en hex, mais bon !


MAX_PLAYERS

MAX_PLAYERS vaut 500, mais si comme la plupart des serveurs vous n'avez pas autant de slots, vous créez des tableaux inutilement grands !

Donc si vous n'avez que 50 slots par exemple, vous gaspillez 9 fois la mémoire que vous utilisez vraiment (Si votre serveur est rempli)

Donc, dé-définissez MAX_PLAYERS, et redéfinissez le comme votre nombre de slots :

Code: (pawn) [Sélectionner]
#undef MAX_PLAYERS
#define MAX_PLAYERS 50


Hors ligne Gzsume

  • *
  • Compétent dans l'inutile
  • Messages: 2236
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #11 le: 11 Juin 2014, 16:11:44 »
Je me permet de préciser certains petits détails avec ce que tu viens de dire.

  • Le mot-clé stock sert simplement à dire, comme son nom l'indique, que la fonction est présente en stock mais qu'elle n'est pas obligatoirement utilisée. C'est comme dire « j'ai un marteau en stock, mais si tu as juste besoin de visser un écrou, ne le prends pas en compte ». Ces fonctions ne sont accessibles que dans le fichier source où elles sont présentes, au contraire des fonctions de type public.
  • Concernant le bind en préprocesseur, il est recommandé d'entourer les nombres de parenthèses et les chaînes de caractère de guillemets droites, tel que sur cet exemple :

Code: (pawn) [Sélectionner]
#define SERVEUR_HOSTNAME "Mon super serveur"
#define NOMBRE_NPCS      (10)

Ce n'est qu'un détail, mais ça fait partie des conventions du langage, et les conventions, ça aide à mieux comprendre un code source lorsqu'on le passe à quelqu'un d'autre. Ça évite également les erreurs stupides auxquelles on peut faire face lors de la compilation. :smile:

Hors ligne CarCrasher

  • *
  • Tueur en série
  • Messages: 144
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #12 le: 12 Juin 2014, 06:49:14 »
Donc encore une fois, j'ai perdu une occasion de ne pas dire à moitié des conneries :mellow:

Hors ligne Gzsume

  • *
  • Compétent dans l'inutile
  • Messages: 2236
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #13 le: 12 Juin 2014, 14:20:13 »
C'est pas des conneries, ce que tu as posté. D'ailleurs pour le coup de la redéfinition de MAX_PLAYERS, je le fais toujours pour économiser du temps d'exécution de mes boucles, et j'avais complètement oublié de poster l'astuce. C'est cool que tu y aies pensé ! Pour les couleurs également, c'est quelque-chose que je ne savais pas. :)

Hors ligne CarCrasher

  • *
  • Tueur en série
  • Messages: 144
    • Voir le profil
Re : Trucs et astuces en Pawn
« Réponse #14 le: 14 Juin 2014, 07:44:22 »
Vui, mais j'ai dit à moitié pour justement dire que j'ai raconté des trucs qui sont pas totalement exacts, comme le coup du stock ! :tongue: