Worldedit
  Worldedit
Le site sur l'éditeur de warcraft 3 !
 
  FAQFAQ   RechercherRechercher   Liste des MembresListe des Membres    Groupes d'utilisateursGroupes d'utilisateurs   medals.php?sid=71ef33d062d158f02d2b3b3bfd7c37d3Médailles   S'enregistrerS'enregistrer 
 ProfilProfil   Se connecter pour vérifier ses messages privésSe connecter pour vérifier ses messages privés   ConnexionConnexion 
  FAQFAQ World Editor   UploadUploader une map ou une image    UploadAjouter sa map à l'annuaire   UploadConsulter l'annuaire

Tirer parti des hashtables
Aller à la page 1, 2  Suivante
 
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Tutoriels
Voir le sujet précédent :: Voir le sujet suivant  
Auteur Message
 Bantas
Anomalie floodiforme


Inscrit le: 21 Aoû 2007
Messages: 1524
Sujets: 37

Médailles: 1 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 17/09/09 04:08    Sujet du message: Tirer parti des hashtables Citer

L'objectif de ce tutoriel est d'apprendre au lecteur à se servir des hashtables à son avantage; quels sont les moyens communs pour y arriver ?
Il doit aussi servir de remplaçant à feu le tutoriel "Rustinage au Game Cache", qui lui avait besoin de bien plus qu'un petit rustinage.
Les liens utiles se trouvent en fin de topic. Notez qu'on utilisera dans l'exemple des notions de vJass ainsi que TimerUtils, parce que le recyclage, c'est le bien.

I/ Ce que sont les hashtables

a) Définition et explications
Une hashtable est un nouveau type d'objet introduit dans la mise à jour 1.23b, en même temps que la suppression (supposée) du return bug. Pour information, celui-ci permettait de faire du transtypage facilement, et a été retiré car il permettait d'éxécuter du code agissant à un niveau supérieur au JASS, donc pouvant installer un virus sur votre ordinateur par exemple. Nous y avons donc également perdu la fameuse fonction H2I, qui trouve son remplaçant dans la fonction GetHandleId que nous verrons dans un instant.
La hashtable permet de stocker une valeur (qu'elle soit entière, réelle, booléenne, ou une extension de handle) sous deux chiffres, que l'on apellera dossier et sous-dossier pour relier ça à la gestion de fichier de certains OS. Contrairement au Game Cache, dont les hashtables sont les remplaçantes, le dossier et le sous-dossier sont définis par un entier chacune, et non par une chaîne de texte. Cela signifie donc moins de conversions et donc une vitesse supérieure (il faut y ajouter le fait que le GC est juste plus lent dans son éxécution). Considérez les hashtables comme un moyen de créer des variables de façon dynamique.

b) Comment s'en servir
On a donc plusieurs possibilités :
  • Sauvegarder une donnée dans une hashtable, via une fonction telle que celle qui suit :
    Jass:
    native SaveInteger   takes hashtable table, integer parentKey, integer childKey, integer value returns nothing

  • Récupérer une donnée précedemment sauvegardée, avec une fonction comme celle-ci :
    Jass:
    native LoadInteger   takes hashtable table, integer parentKey, integer childKey returns integer

  • Nettoyer une donnée précise; ceci est essentiel puisque sinon il vous reste des données inutilisées (leak) :
    Jass:
    native RemoveSavedInteger   takes hashtable table, integer parentKey, integer childKey returns nothing

  • Nettoyer un dossier complet. Tout ce qui utilise parentKey est supprimé de la hashtable :
    Jass:
    native FlushChildHashtable   takes hashtable table, integer parentKey returns nothing

  • Vérifier qu'une valeur est stockée; je ne vois personnellement pas d'utilité personnellement, puisque que, comme nous l'indique le GUI, si il n'y a pas de donnée, alors la valeur renvoyée est null/0. EDIT : C'est plus propre pour s'en servir dans des if etc. PPS : TB tient à ce que je fasse remarquer que évidemment si vous avez stocké la valeur par défaut, ça peut servir. Par ailleurs, ceci est légèrement plus lent que de charger la valeur pour la vérifier.
    Jass:
    native HaveSavedInteger   takes hashtable table, integer parentKey, integer childKey returns boolean


Bien sûr, ces fonctions existent pour d'autres types que des entiers; cependant, puisque les structs du vJass sont des entiers, on se servira le plus souvent d'entiers dans ce qui sera expliqué plus loin.

II/ Tirer parti des hashtables

a) Quelques explications
Comme vous le savez probablement si vous faites du JASS, TriggerSleepAction et son petit frère PolledWait partagent imprécision, impossibilité d'utilisation dans des conditions, risque de corruption de déclencheur. Pour compenser cela, la solution trouvée est d'utiliser les timers, qui sont bien plus précis. Cependant, comment stocker des données à réutiliser plus tard ?
C'est là que les hashtables interviennent : En stockant des données dans le dossier / sous-dossier GetHandleId(votreTimer), vous pouvez les récupérer plus tard en vous référant à ce timer. Par exemple avec GetHandleId(GetExpiredTimer()). Un handle étant par définition unique, ce que renverra la fonction GetHandleId le sera aussi; pas de risques que le timer a se retrouve à utiliser les données du timer b.
Un des autres éléments qui a souvent besoin d'avoir des données associées est le trigger. De la même façon, vous pouvez utiliser GetHandleId(votreDeclencheur).
A savoir : Les hashtables ne se plantent pas quand elles récupèrent les données, si vous chargez un joueur à un endroit donné et que c'est une unité qui s'y trouve, alors vous ne verrez que l'ombre d'un null. Cela implique également que l'on ne peut stocker deux données étendant le même type de base (entier, réel, booléen, handle) sur le même emplacement (source : Blizzard).

Pour ce tutorial, nous tenterons de créer la fonction TriggerApplyTimedLife. Comme son nom l'indique, il s'agît de provoquer la destruction d'un trigger après un temps donné.

b) Un exemple : TriggerApplyTimedLife
Créons donc cette fonction. Nous avons besoin de savoir de quel déclencheur on parle, ainsi que la durée restante à ce timer pour s'éxécuter.
Jass:
library TriggerApplyTimedLife requires TimerUtils

function TriggerApplyTimedLife takes trigger trig, real timeout returns nothing
endfunction

endlibrary

Première chose : Nous avons besoin d'une hashtable. Etant donné qu'il s'agît d'un code qui sera exposé au public, nous utiliserons une hashtable spécialement pour cette library, qui sera donc (presque) autonome. Pour ce que j'en sais, il n'y a pas eu de benchmarking pour comparer l'efficacité d'une grande et unique hashtable face à plusieurs hashtables contenant moins de données. Ceci étant dit, il n'y a pas de limite connue au nombre de hashtables que vous pouvez initialiser en même temps, contrairement au game cache ne pouvant exister en plus de 256 exemplaires. EDIT : Le nombre de hashtables pouvant exister en même temps sur une même carte est de 256 également. Evitez donc de les créer de façon dynamique.
Faisons donc cela : Nous allons l'initialiser dans un initializer séparé grâce à la fonction InitHashTable; je n'ai pas encore fait de test pour savoir si initialiser une hashtable dans sa déclaration en tant que globale fonctionne ou non. EDIT : Je l'ai fait, ça marche.
Jass:
library TriggerApplyTimedLife initializer Init requires TimerUtils

globals
   private hashtable hasht //La hashtable dont nous allons nous servir
endglobals

function TriggerApplyTimedLife takes trigger trig, real timeout returns nothing
endfunction

private function Init takes nothing returns nothing
    set hasht = InitHashTable() //Initialise la hashtable et la met à la bonne valeur
endfunction

endlibrary

Une fois que cela est fait, nous pouvons donc passer au codage lui-même. Nous avons besoin de créer un timer (que nous apellerons tim ici), de lui associer la valeur de trig dans la hashtable hasht et de lancer le timer pour qu'il expire dans timeout secondes et active la fonction TimeExpired.
Jass:
library TriggerApplyTimedLife initializer Init requires TimerUtils

globals
   private hashtable hasht //La hashtable dont nous allons nous servir
endglobals

private function TimeExpired takes nothing returns nothing
endfunction

function TriggerApplyTimedLife takes trigger trig, real timeout returns nothing
    local timer tim = NewTimer() //On crée un nouveau timer via TimerUtils
    call SaveTriggerHandle(hasht, 0, GetHandleId(tim), trig) //On sauve le déclencheur dans un endroit où on pourra le retrouver en ayant le timer
    call TimerStart(tim, timeout, false, function TimeExpired) //On démarre le timer
endfunction

private function Init takes nothing returns nothing
    set hasht = InitHashTable() //Initialise la hashtable et la met à la bonne valeur
endfunction

endlibrary

Parfait, maintenant nous pourrons retrouver le trigger associé. Codons donc la fonction TimeExpired, apellée à l'expiration de tim.
On en profitera pour ajouter une sécurité, afin d'éviter que l'utilisateur fasse n'importe quoi avec la fonction.
Jass:
library TriggerApplyTimedLife initializer Init requires TimerUtils

globals
   private hashtable hasht //La hashtable dont nous allons nous servir
   constant real TRIGGER_TIMED_LIFE_DEFAULT_TIMEOUT = 3. //Si l'utilisateur donne une valeur incorrecte, voilà la valeur donnée
endglobals

private function TimeExpired takes nothing returns nothing
    local timer tim = GetExpiredTimer() //On récupère tim
    local trigger trig = LoadTriggerHandle(hasht, 0, GetHandleId(tim)) //On récupère trig là où on l'a stocké
    call RemoveSavedHandle(hasht, 0, GetHandleId(tim)) //Puisque l'on a plus besoin d'avoir la valeur stockée, on nettoie pour éviter un leak
    call ReleaseTimer(tim) //Plus besoin du timer, on le relâche, toujours avec TimerUtils
    call DestroyTrigger(trig) //On fait enfin ce que l'on voulait faire
    set trig = null //Anti-leak tout ça
endfunction

function TriggerApplyTimedLife takes trigger trig, real timeout returns timer
    local timer tim

    if (trig == null) then //S'active si le déclencheur donné est nul
        debug call BJDebugMsg("Warning: TriggerApplyTimedLife was given an incorrect trigger. Operation cancelled.")
        return null
    endif
    if (timeout <= 0.) then //S'active si le temps est mal réglé
        set timeout = TRIGGER_TIMED_LIFE_DEFAULT_TIMEOUT
    endif

    set tim = NewTimer() //On crée un nouveau timer via TimerUtils
    call SaveTriggerHandle(hasht, 0, GetHandleId(tim), trig) //On sauve le déclencheur dans un endroit où on pourra le retrouver en ayant le timer
    call TimerStart(tim, timeout, false, function TimeExpired) //On démarre le timer

    return tim //On renvoie le timer pour qu'il soit détruit en même temps que le trigger par l'utilisateur
endfunction

private function Init takes nothing returns nothing
    set hasht = InitHashTable() //Initialise la hashtable et la met à la bonne valeur
endfunction

endlibrary

Et voilà votre fonction TriggerApplyTimedLife toute prête Wink Il y a peut-être des risques d'échec à cause de la façon dont sont allouées les handles, que je n'ai pas étudiée. Grossièrement, en l'état actuel de la fonction, si le trigger est détruit avant que sa "timed life" se termine, il me semble qu'il est possible que son handle soit réalloué à un autre déclencheur qui risquerait alors une mort prématurée. PS :J'ai ajouté un renvoi de tim. Il suffit de le relâcher en même temps que la destruction du déclencheur pour éviter le bug sus-mentionné.
Bien sûr, cela aurait pu s'appliquer à bien d'autre situations. Vous auriez par exemple pu stocker une struct avec toutes vos données. A ce sujet, TimerUtils, dont on s'est servi dans l'exemple, possède des fonctions SetTimerData et GetTimerData. Si vous utilisez la version bleue de TimerUtils (plus lente mais plus flexible), il s'agît d'utilisation des hashtables. Si vous utilisez la version rouge ou orange, les fonctions sus-citées sont plus rapides que l'utilisation des hashtables. En plus vous n'avez pas besoin de nettoyer ensuite.

III/ Liens et références
V1.23b Map Maker Transition Guide
JassNewGenPack v5d
TimerUtils par Vexorian
_________________


Dernière édition par Bantas le 08/04/10 00:27; édité 8 fois
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Brissou de Mourièssou
Créateur de sorts, depuis 1936.


Inscrit le: 30 Aoû 2007
Messages: 1511
Sujets: 26
Spécialité en worldedit: Développer des jeux vidéos pour le fun, donc world edit c'est comme faire une addition.
Médailles: 2 (En savoir plus...)
Concours de sorts amusants (Quantité : 1) Créateur de héros (Quantité : 1)

MessagePosté le: 17/09/09 08:01    Sujet du message: Citer

Faudrait également faire un chapitre pour nos amis du GUI, avec un exemple. C'est surtout eux qui ne comprennent pas du tout à quoi ça sert ni comment s'en servir, les pauvres n'ont jamais connu les "joies" du gamecache.

Faudrait mettre à jour la colorisation syntaxique pour les nouvelles fonctions.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé Visiter le site web du posteur MSN Messenger
 jk2pach
Invité








MessagePosté le: 17/09/09 10:11    Sujet du message: Citer

Tuto intéressant (à titre personnel pour moi qui suit directement passé du Gui au VJass et aux struct sans me servir du gamecache).

Question de mappeur: en gros les Hasthables permettent d'éviter de se servir des tables de Vexorian?

Demande d'édition du tutorial:

-Préciser que ce tutorial demande des connaissances en Jass, en VJass et le JNPG le plus récent Smile ou alors donner des exemples en Gui.

-Donner des définitions (Qu'est-ce qu'un Handle par exemple; pour un débutant qui ne programme pas ailleurs que sur l'éditeur, je peux te garantir que c'est une notion bizarre au début)

-Mettre les liens des prérequis au début du tuto.

-Une carte d'exemple(s) serait appréciée Smile
_________________
Revenir en haut
 Bantas
Anomalie floodiforme


Inscrit le: 21 Aoû 2007
Messages: 1524
Sujets: 37

Médailles: 1 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 17/09/09 11:54    Sujet du message: Citer

Apocalypse a écrit:
Question de mappeur: en gros les Hasthables permettent d'éviter de se servir des tables de Vexorian?
Je ne connais la libraire sus-mentionnée qu'indirectement, mais il me semble que oui.

Apocalypse a écrit:
-Préciser que ce tutorial demande des connaissances en Jass, en VJass et le JNPG le plus récent Smile ou alors donner des exemples en Gui.
Pour les exemples en GUI ça ne va pas le faire, c'est trop compliqué pour moi.
Je préciserais que l'exemple utilise des notions de vJass et donc recquiert le JassNewGenPack pour son fonctionnement. Cependant il n'est pas nécessaire d'utiliser ce logiciel pour utiliser les hashtables.

Apocalypse a écrit:
-Donner des définitions (Qu'est-ce qu'un Handle par exemple; pour un débutant qui ne programme pas ailleurs que sur l'éditeur, je peux te garantir que c'est une notion bizarre au début)
A vrai dire, le handle est une notion assez floue pour moi. Je m'en souviens comme étant une adresse vers un objet, mais ne m'étant pas intéressé à du code à un niveau supérieur au Jass, ça s'arrête là.

Apocalypse a écrit:
-Mettre les liens des prérequis au début du tuto.
Une mention "Des liens utiles se trouve en fin de topic" suffira-t-elle ? j'aime bien respecter les standards à la wikipedia Wink

Apocalypse a écrit:
-Une carte d'exemple(s) serait appréciée Smile
Ah euh.. ben je sortirais mon pack de héros.

Sinon je vais éditer dès maintenant parce qu'il y a une solution au petit bug de mon code.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Magus
Membre a fort taux de post


Inscrit le: 13 Oct 2007
Messages: 994
Sujets: 25
Spécialité en worldedit: Codeur


MessagePosté le: 17/09/09 12:46    Sujet du message: Citer

Un handle est en effet une adresse qui pointe sur un objet en mémoire.
En dehors du jass, les handles sont sources d'erreurs pour des débutants avec les différentes méthodes dont les arguments sont passés à une fonction.

Par exemple, en Jass, les arguments sont passés en copie de valeur si je me souviens bien. Un petit exemple sera sous doute mieux :

Jass:
function test takes integer i returns nothing
    set i = i + 1
endfunction

Cette fonction ne fera rien. Car i est ce qu'on appel une "copie". On ne manipule donc qu'une copie de i, et pas i lui même. Il en va de même pour un pointeur. Par exemple :
Jass:
function test takes handle h returns nothing
    set h = un_handle
endfunction

De même cette fonction est inutile. Par contre, l'objet qui est pointé par l'handle lui reste toujours le même. Ainsi :
Jass:
function test takes handle h returns nothing
    call DestroyHandle(h)
endfunction

Cette fonction détruira bien l'objet pointé par h (DestroyHandle n'existe pas hein, c'est juste pour l'exemple). Mais h lui reste entièrement le même ! Il pointe toujours au même endroit dans la mémoire.
En résumé :
Jass:
function test takes handle h, integer i returns nothing
    set i = i + i //N'a aucun effet en dehors de la fonction
    call DestroyHandle(h) //Détruit bien l'objet en mémoire. Mais h est toujours le même
    set h = un_hande //N'a aucun effet en dehors de la fonction
endfunction

_________________
- La théorie c'est quand rien ne fonctionne mais tout le monde sait pourquoi.
- La pratique c'est quand tout fonctionne mais personne ne sait pourquoi.
- Chez moi la théorie et la pratique sont réunies, rien ne fonctionne et personne ne sait pourquoi.
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé MSN Messenger
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 17/09/09 16:31    Sujet du message: Citer

Citation:
Question de mappeur: en gros les Hasthables permettent d'éviter de se servir des tables de Vexorian?

Ne nous embrouillons pas, quasiment toutes les fonctions de Table sont inlinés, et c'est plus sexy d'utiliser Table que directement les fonctions natives des hashtables.
C'est utile pour attacher des entiers (instances de struct ou autre) à un handle (unité par ex)

Toutefois Table ne permet pas tout, et ce que je trouves débile, c'est que l'on soit obligé d'utiliser un string et non un entier en premier paramètre quand on veut utiliser une hashtable sous forme d'array 2D.

De même si on veut utiliser une hashtable comme une variable déployée sans limitation d'index autre qu'un integer, Table n'est d'aucun secours.
_________________
Le violet, c'est moche.
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Bantas
Anomalie floodiforme


Inscrit le: 21 Aoû 2007
Messages: 1524
Sujets: 37

Médailles: 1 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 17/09/09 17:02    Sujet du message: Citer

Troll-Brain a écrit:
Ne nous embrouillons pas, quasiment toutes les fonctions de Table sont inlinés, et c'est plus sexy d'utiliser Table que directement les fonctions natives des hashtables.
Question d'habitude je suppose. Les fonctions de manipulation des hashtables sont saiks imo. (c'est pas comme si ça faisait trois ans que je me sers de fonctions similaires hein ?)
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 17/09/09 17:53    Sujet du message: Citer

Jass:
set Ht[<unité>] = <data>
VS
Jass:
call SaveInteger(Ht,GetHandleId(<unité>),0,<data>)



Jass:
Ht[<unité>]
VS
Jass:
LoadInteger(Ht,GetHandleId(<unité>),0)


No match, owned, fail.

De toute façon, comme la plupart des codes partagés, je n'ai aucune vergogne à les éditer pour que cela ne me satisfasse pleinement.
(les points négatifs cités plus haut)
_________________
Le violet, c'est moche.
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Bantas
Anomalie floodiforme


Inscrit le: 21 Aoû 2007
Messages: 1524
Sujets: 37

Médailles: 1 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 21/09/09 11:15    Sujet du message: Citer

Bump.
Citation:
Une mention "Des liens utiles se trouve en fin de topic" suffira-t-elle ? j'aime bien respecter les standards à la wikipedia Wink


PS : Je me permets de poster un petit script que j'ai fait pour savoir si des valeurs de ma hashtable (nommée hasht, remplacez ça si la votre est appelée autrement) leakent ou non. Evidemment si vous avez plus de hashtables il vous faut plus de modifs..
Secret:

Jass:
scope CompterValeursHashT initializer InitTrig

globals
    private integer count = 0
endglobals

private function IncreaseCount takes hashtable hasht, integer parentKey, integer childKey, integer value returns nothing
    if not HaveSavedInteger(hasht, parentKey, childKey) then
        set count = count + 1
    endif
endfunction
debug hook SaveInteger IncreaseCount

private function DecreaseCount takes hashtable hasht, integer parentKey, integer childKey returns nothing
    if HaveSavedInteger(hasht, parentKey, childKey) then
        set count = count - 1
    endif
endfunction
debug hook RemoveSavedInteger DecreaseCount

private function Trig_Actions takes nothing returns boolean
    call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0., 0., 20., "Debug: hasht contient |cff8888ff" + I2S(count) + "|r valeur(s) entière(s).")
    return false
endfunction

//===========================================================================
private function InitTrig takes nothing returns nothing
    local integer i = 0
    local trigger trig = CreateTrigger()
    loop
        call TriggerRegisterPlayerChatEvent(trig, Player(i), "-debugmode CountHashTValues", true)
        exitwhen i == 11
        set i = i + 1
    endloop
    call TriggerAddCondition(trig, Condition(function Trig_Actions))
endfunction

endscope

Une fois que le script est dans la carte, il suffit que n'importe quel joueur tape "-debugmode CountHashTValues" (insensible à la casse) et il pourra voir combien d'entiers sont stockés dans hasht au moment où il a tapé le message.
_________________


Dernière édition par Bantas le 21/09/09 16:14; édité 1 fois
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 21/09/09 16:01    Sujet du message: Citer

Mais les hook en debug, pour le speed freak powa.
Parce que des hook c'est quand même des appels de fonctions avec des TriggerEvaluate.
_________________
Le violet, c'est moche.
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Bantas
Anomalie floodiforme


Inscrit le: 21 Aoû 2007
Messages: 1524
Sujets: 37

Médailles: 1 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 21/09/09 16:10    Sujet du message: Citer

Troll-Brain a écrit:
Mais les hook en debug, pour le speed freak powa.
Parce que des hook c'est quand même des appels de fonctions avec des TriggerEvaluate.
Ouais. En théorie je suis sensé désactiver le script quand je suis en dehors des versions debug m'enfin..

Je vais en profiter pour essayer si debug marche avec //! novjass. J'ai des doutes mais ça vaut le coup d'essayer. Je sais que la balise ne devrait pas servir à ça m'enfin bon, de toutes façons sans jasshelper ça ne devrait pas marcher du tout.

EDIT : Non, ça ne marche pas.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1) Grand mage créateur de sort (Quantité : 1)

MessagePosté le: 21/09/09 16:30    Sujet du message: Citer

TriggerRegisterAnyUnitEventBJ est l'une des BJ les plus utiles, et le mieux codé.
Faut pas tomber dans la phobie non plus.
Toutes les BJ ne sont pas evil, certaines sont utiles (sisi).
_________________
Le violet, c'est moche.
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Bantas
Anomalie floodiforme


Inscrit le: 21 Aoû 2007
Messages: 1524
Sujets: 37

Médailles: 1 (En savoir plus...)
Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 21/09/09 16:55    Sujet du message: Citer

Troll-Brain a écrit:
TriggerRegisterAnyUnitEventBJ est l'une des BJ les plus utiles, et le mieux codé.
Faut pas tomber dans la phobie non plus.
Toutes les BJ ne sont pas evil, certaines sont utiles (sisi).
Je suis tout à fait d'accord sur le fait que TriggerRegisterAnyUnitEventBJ soit assez pratique, mais on parle de joueurs qui font des messages ici.
_________________
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 Troll-Brain
Ri1kamoua


Inscrit le: 23 Aoû 2007
Messages: 7146
Sujets: 147
Spécialité en worldedit: le troll, le flood, la vulgarité, mon coeur balance
Médailles: 2 (En savoir plus...)
Grand mage créateur de sort (Quantité : 1) Rédacteur de tuto #3 (Quantité : 1)

MessagePosté le: 21/09/09 17:17    Sujet du message: Citer

Ah zut, encore une occasion manquée, de se taire.
_________________
Le violet, c'est moche.
Revenir en haut
Voir le profil de l'utilisateur Envoyer un message privé
 jk2pach
Invité








MessagePosté le: 04/10/09 14:49    Sujet du message: Citer

Passable en officiel donc?
_________________
Revenir en haut
Montrer les messages depuis:   
Poster un nouveau sujet   Répondre au sujet    Worldedit Index du Forum -> Tutoriels Toutes les heures sont au format GMT + 1 Heure
Aller à la page 1, 2  Suivante
Page 1 sur 2

 
Sauter vers:  
Vous ne pouvez pas poster de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas voter dans les sondages de ce forum


Powered by phpBB © 2001, 2005 phpBB Group
Traduction par : phpBB-fr.com