Évènements
Tous les évènements qu'un programme peut recevoir, avec leurs champs, leur origine et la façon dont les fonctions d'attente les traitent.
Un évènement, c'est quelque chose qui est arrivé à l'ordinateur pendant que le programme tournait : une entrée redstone a changé, une touche a été pressée, un minuteur est arrivé à son terme, un message est arrivé. L'ordinateur range chaque évènement dans une file d'attente, et le programme les en sort un par un avec os.pull_event. Chaque évènement arrive sous forme de table : son champ name dit ce qui s'est passé, et les autres champs dépendent de l'évènement.
local e = os.pull_event() -- attend le prochain évènement, quel qu'il soit
print(e.name) -- "redstone", "key", "click", "timer"...Le guide Évènements explique comment construire un programme autour des évènements. Cette page les liste tous, champ par champ.
Tous les évènements
| Évènement | Champs | Envoyé quand | Ordinateurs |
|---|---|---|---|
redstone | aucun | une entrée redstone de l'ordinateur change | tous |
timer | id | un minuteur lancé par os.start_timer arrive à son terme | tous |
key | key | Entrée, une flèche, Tab... est pressée dans le terminal | tous |
char | char | un caractère est tapé dans le terminal | tous |
paste | text | Ctrl+V dans le terminal | tous |
click | x, y, px, py, button, source | un clic sur l'écran du terminal ou sur un moniteur | terminal : tous sauf le Calculateur à tubes ; moniteur : tous |
drag | x, y, px, py, button, source | la souris bouge bouton enfoncé, dans le terminal | tous sauf le Calculateur à tubes |
message | sender, channel, data, via, distance | un autre ordinateur envoie un message | Mini-ordinateur et plus récents |
link | a, b, power | une fréquence de Liaison de redstone utilisée par l'ordinateur change | tous |
disk | inserted | un joueur insère ou éjecte le support de stockage | tous sauf le Microcontrôleur |
| le nom de votre choix | data | le programme appelle os.queue_event | tous |
Chaque table d'évènement a aussi son champ name. Un champ qui vaudrait nil est tout simplement absent (un message envoyé sans données n'a pas de data).
Attendre des évènements
Quatre fonctions endorment le programme jusqu'à ce qu'il se passe quelque chose. Elles ne traitent pas les autres évènements de la même façon, et cela compte dès qu'un programme écoute plus d'une chose.
| Fonction | Reprend sur | Les autres évènements pendant ce temps |
|---|---|---|
os.pull_event() | le prochain évènement, quel qu'il soit | aucun n'est perdu : chaque appel renvoie le suivant |
os.pull_event(nom) | le prochain évènement de ce nom | jetés |
net.receive([délai]) | le prochain évènement message, ou nil après délai secondes | jetés |
read([masque]) | la touche Entrée | key, char et paste construisent la ligne ; les autres restent dans la file, dans l'ordre |
sleep(secondes) | la fin du délai | restent dans la file |
os.pull_event avec un nom jette tout ce qui arrive avant l'évènement attendu. Ici, l'évènement alarme est perdu, alors que cloche, mis en file après porte, est toujours là pour l'appel suivant :
os.queue_event("alarme")
os.queue_event("porte", "ouverte")
os.queue_event("cloche")
local e = os.pull_event("porte")
print(e.data)
print(os.pull_event().name)ouverte cloche
Un programme qui attend plusieurs sortes d'évènements appelle donc os.pull_event() sans nom et regarde e.name. sleep garde ce qui arrive pendant la pause :
os.queue_event("cloche")
sleep(1)
print(os.pull_event().name)cloche
os.pull_event n'a pas de limite de temps. Pour arrêter d'attendre au bout d'un moment, lancez un minuteur et attendez l'un ou l'autre :
local function attendre(nom, secondes)
local minuteur = os.start_timer(secondes)
while true do
local e = os.pull_event()
if e.name == nom then return e end
if e.name == "timer" and e.id == minuteur then return nil end
end
end
local e = attendre("redstone", 0.5)
print(e == nil)true
La file d'attente
- Elle contient 256 évènements. Quand elle est pleine, le plus ancien disparaît pour faire de la place au nouveau.
- Les évènements s'accumulent pendant que le programme calcule ou dort, et attendent là qu'il appelle
os.pull_event. - Les messages des autres ordinateurs sont refusés (le
net.sendde l'expéditeur renvoiefalse) quand les évènements en attente occupent plus d'un quart de la mémoire de l'ordinateur. - À l'invite du shell, sans programme en cours, les évènements sont jetés (les messages aussi) : les touches vont à la ligne de commande.
- Redémarrer ou éteindre vide la file et oublie les minuteurs.
- Un ordinateur sans rotation est figé : les évènements attendent dans sa file, et ses minuteurs et
sleepattendent avec lui.
redstone
| Champ | Type | Valeur |
|---|---|---|
| (aucun) | seulement name |
Envoyé quand le signal redstone qui entre dans l'ordinateur change sur l'une de ses six faces. L'évènement ne dit ni la face ni la nouvelle puissance : lisez-les avec rs.get. Un seul évènement peut correspondre à plusieurs faces qui ont changé ensemble.
Compter les plaques de fer d'une chaîne de presses mécaniques, avec un observateur qui envoie une impulsion sur la face gauche. Le programme garde la valeur précédente pour compter chaque impulsion une seule fois, sur son front montant :
local compte = 0
local avant = 0
while true do
os.pull_event("redstone")
local maintenant = rs.get("left")
if maintenant > 0 and avant == 0 then
compte = compte + 1
print("plaques de fer : " .. compte)
end
avant = maintenant
endVoir rs et Redstone et liaisons de Create.
timer
| Champ | Type | Valeur |
|---|---|---|
id | number | le numéro qu'a renvoyé os.start_timer |
Envoyé une fois, quand un minuteur lancé par os.start_timer(secondes) arrive à son terme. Le délai est arrondi au tick supérieur (1/20 s), un tick au minimum. Jusqu'à 256 minuteurs peuvent attendre en même temps. Comparez e.id au numéro que vous avez gardé pour savoir de quel minuteur il s'agit :
local court = os.start_timer(0.5)
local long = os.start_timer(1)
for i = 1, 2 do
local e = os.pull_event("timer")
if e.id == court then print("une demi-seconde") end
if e.id == long then print("une seconde") end
endune demi-seconde une seconde
Un minuteur ne sonne qu'une fois : pour une horloge qui avance chaque seconde, relancez-en un à chaque fois qu'il sonne (voir la boucle principale en bas de cette page).
key
| Champ | Type | Valeur |
|---|---|---|
key | string | "enter", "backspace", "delete", "up", "down", "left", "right", "home", "end" ou "tab" |
Envoyé quand l'une de ces dix touches est pressée alors qu'un joueur a le terminal ouvert. Les lettres, les chiffres et la barre d'espace n'envoient pas d'évènement key : ils tapent des caractères, voir char. La touche Entrée du pavé numérique donne aussi "enter". La page Clavier détaille ce que le clavier envoie et ce qu'il n'envoie pas.
Un menu parcouru avec les flèches, pour choisir la destination d'un train :
local gares = {"Mine", "Ferme", "Port"}
local choix = 1
while true do
term.clear()
for i, nom in ipairs(gares) do
term.set_cursor(2, i)
if i == choix then term.write("> " .. nom) else term.write(" " .. nom) end
end
local e = os.pull_event("key")
if e.key == "up" and choix > 1 then choix = choix - 1 end
if e.key == "down" and choix < #gares then choix = choix + 1 end
if e.key == "enter" then break end
end
print("")
print("Départ pour " .. gares[choix])char
| Champ | Type | Valeur |
|---|---|---|
char | string | le caractère tapé, long d'un caractère : "a", "A", "7", " ", "é"... |
Envoyé pour chaque caractère tapé dans le terminal : les lettres (en majuscule ou en minuscule, comme elles sont tapées), les chiffres, la ponctuation, l'espace. Testez les lettres avec string.lower pour que le verrouillage des majuscules n'y change rien :
print("Appuyez sur Q pour arrêter les concasseurs")
while true do
local e = os.pull_event("char")
if string.lower(e.char) == "q" then
rs.set("back", false)
break
end
endos.pull_event("key") jette les évènements char, et os.pull_event("char") les évènements key. Pour lire les deux (flèches et lettres), appelez os.pull_event() et testez e.name.
paste
| Champ | Type | Valeur |
|---|---|---|
text | string | le texte du presse-papiers, 4096 caractères au plus, retours à la ligne compris |
Envoyé quand le joueur appuie sur Ctrl+V dans le terminal avec quelque chose dans le presse-papiers. Un texte plus long est coupé à 4096 caractères. Coller une liste d'identifiants d'objets, un par ligne :
local e = os.pull_event("paste")
local ids = string.split(e.text, "\n")
print(#ids .. " lignes collées")Pendant un read(), le collage est tapé dans la ligne à la place (jusqu'à son premier retour à la ligne).
click
| Champ | Type | Valeur |
|---|---|---|
x | number | colonne du caractère cliqué, à partir de 1 (à gauche) |
y | number | ligne du caractère cliqué, à partir de 1 (en haut) |
px | number | colonne du pixel cliqué dans le dessin gfx, à partir de 1 |
py | number | ligne du pixel cliqué, à partir de 1 |
button | number | 1 gauche, 2 droit, 3 milieu (toujours 1 sur un moniteur) |
source | string | "terminal" ou "monitor" |
Un clic vient de deux endroits :
- Le terminal : un clic du bouton gauche, droit ou du milieu sur l'écran de la fenêtre du terminal. Tous les ordinateurs à écran l'envoient, sauf le Calculateur à tubes, dont le terminal est du papier.
- Un moniteur : un clic droit sur la face avant d'un moniteur qui affiche l'ordinateur, sur tous les ordinateurs. Il ne devient un clic que si le programme en cours attend des clics : une fois qu'il a appelé
os.pull_event()ouos.pull_event("click"). Sinon, ou si le joueur est accroupi, le clic droit ouvre le terminal comme d'habitude.
x et y servent aux boutons de texte dessinés avec term, px et py aux dessins faits avec gfx (un caractère fait 6 pixels de large et 9 de haut). Un panneau de porte, avec une Liaison de redstone fer et or qui commande la porte :
term.clear()
term.set_cursor(2, 1)
term.write("Porte du hangar")
term.set_cursor(2, 3)
term.set_bg(term.colors.green)
term.write(" OUVRIR ")
term.set_cursor(12, 3)
term.set_bg(term.colors.red)
term.write(" FERMER ")
term.set_bg(term.colors.black)
while true do
local e = os.pull_event("click")
if e.y == 3 and e.x >= 2 and e.x <= 9 then
link.set("minecraft:iron_ingot", "minecraft:gold_ingot", 15)
elseif e.y == 3 and e.x >= 12 and e.x <= 19 then
link.set("minecraft:iron_ingot", "minecraft:gold_ingot", 0)
end
end
drag
| Champ | Type | Valeur |
|---|---|---|
x, y, px, py | number | là où est la souris maintenant, comme pour click |
button | number | le bouton enfoncé : 1 gauche, 2 droit, 3 milieu |
source | string | toujours "terminal" |
Envoyé pendant que le joueur déplace la souris sur l'écran du terminal avec un bouton enfoncé, après l'avoir pressé sur l'écran (l'appui lui-même est un click). Seul le terminal l'envoie, pas les moniteurs. Un drag toutes les 50 ms au plus, et seulement quand la souris est passée sur un autre pixel : un geste rapide laisse des trous, alors reliez les points par une ligne.
local dernierX, dernierY
gfx.clear()
while true do
local e = os.pull_event()
if e.name == "click" then
dernierX, dernierY = e.px, e.py
elseif e.name == "drag" and dernierX then
local couleur = "orange"
if e.button == 2 then couleur = "none" end -- le bouton droit efface
gfx.line(dernierX, dernierY, e.px, e.py, couleur, 2)
dernierX, dernierY = e.px, e.py
end
endmessage
| Champ | Type | Valeur |
|---|---|---|
sender | number | le numéro de l'ordinateur qui l'a envoyé (son net.id()) |
channel | string | le canal donné à net.send ou net.broadcast, "default" sans canal |
data | any | une copie de la valeur envoyée (absent si rien n'a été envoyé) |
via | string | "cable", "radio" ou "wifi" |
distance | number | la distance entre les deux ordinateurs en blocs, arrondie au dixième |
Envoyé quand un autre ordinateur joint celui-ci avec net.send ou net.broadcast. Seuls le Mini-ordinateur et les ordinateurs plus récents ont net. net.receive attend exactement cet évènement et le renvoie : net.receive() revient à os.pull_event("message"), avec une limite de temps facultative.
Les données sont une copie : nombres, textes, booléens et tables de tout cela arrivent tels qu'ils ont été envoyés, et les modifier ne change pas ceux de l'expéditeur. Un tableau des départs qui reçoit ce qu'annoncent les dépôts :
while true do
local e = os.pull_event("message")
if e.channel == "trains" then
print("#" .. e.sender .. " (" .. e.via .. ", " .. e.distance .. " blocs) : " .. tostring(e.data))
end
endLe message n'est pas remis (et net.send renvoie false) quand le destinataire est éteint, dans un chunk non chargé, ou quand sa file contient déjà des évènements pour plus d'un quart de sa mémoire. Un destinataire dont le programme est terminé, revenu à l'invite du shell, perd le message alors que net.send a renvoyé true : un récepteur doit tourner en permanence comme programme (son startup). Voir Réseaux.
link
| Champ | Type | Valeur |
|---|---|---|
a | string | premier objet de la fréquence, tel que le programme l'a écrit |
b | string | second objet de la fréquence |
power | number | la puissance reçue maintenant, de 0 à 15 |
Envoyé quand le signal le plus fort des autres Liaisons de redstone d'une fréquence change. L'ordinateur n'écoute que les fréquences qu'il a utilisées depuis son démarrage, avec link.get, link.set ou les méthodes d'un périphérique Liaison de redstone. Sa propre émission ne compte jamais, et la première utilisation n'envoie pas d'évènement : le programme a déjà eu la valeur.
-- un levier au loin, sur une Liaison de redstone réglée sur fer + redstone
local puissance = link.get("minecraft:iron_ingot", "minecraft:redstone") -- commence à écouter
print("levier : " .. puissance)
while true do
local e = os.pull_event("link")
if e.a == "minecraft:iron_ingot" and e.b == "minecraft:redstone" then
print("levier : " .. e.power)
end
endVoir link et Liaison de redstone.
disk
| Champ | Type | Valeur |
|---|---|---|
inserted | boolean | true quand un support a été inséré, false quand il a été éjecté |
Envoyé quand un joueur insère un support de stockage (clic droit avec) ou l'éjecte (accroupi, clic droit à main vide). Le Microcontrôleur n'a pas de lecteur et ne l'envoie jamais. Un programme en cours continue de tourner quand son support s'en va : il est en mémoire. Tant qu'aucun support ne revient, import et les fonctions fs (toutes sauf fs.cwd) s'arrêtent sur l'erreur no storage medium.
while true do
local e = os.pull_event("disk")
if e.inserted then
print("support inséré : " .. table.concat(fs.list("/"), ", "))
else
print("support éjecté")
end
endVos propres évènements
| Champ | Type | Valeur |
|---|---|---|
data | any | le second argument de os.queue_event (absent sans lui) |
os.queue_event(nom, données) place un évènement de n'importe quel nom dans la file de l'ordinateur lui-même, derrière les évènements déjà présents. Servez-vous-en pour confier du travail à la boucle principale, ou pour réveiller une boucle qui attend dans os.pull_event. Les données sont transmises telles quelles, sans copie :
os.queue_event("commande", {objet = "minecraft:iron_ingot", nombre = 16})
local e = os.pull_event("commande")
print(e.name, e.data.objet, e.data.nombre)commande minecraft:iron_ingot 16
La file appartient à l'ordinateur : pour en joindre un autre, envoyez un message avec net. Évitez les noms des évènements du jeu (key, char...), que read() et les autres programmes prendraient pour de vrais.
Une boucle principale pour tous les évènements
La plupart des vrais programmes finissent avec une seule boucle qui attend n'importe quel évènement et agit selon son nom. Un compteur pour une chaîne de presses : les impulsions sur la face gauche comptent les plaques, un minuteur redessine l'écran chaque seconde, un clic remet le compte à zéro et la touche Q arrête le programme.
local compte = 0
local avant = 0
local actif = true
local function afficher()
term.clear()
term.set_cursor(1, 1)
print("Plaques de fer : " .. compte)
print("Clic : remise à zéro Q : quitter")
end
afficher()
local minuteur = os.start_timer(1)
while actif do
local e = os.pull_event()
if e.name == "redstone" then
local maintenant = rs.get("left")
if maintenant > 0 and avant == 0 then compte = compte + 1 end
avant = maintenant
elseif e.name == "timer" and e.id == minuteur then
afficher()
minuteur = os.start_timer(1)
elseif e.name == "click" then
compte = 0
afficher()
elseif e.name == "char" and string.lower(e.char) == "q" then
actif = false
end
endLa boucle appelle os.pull_event() sans nom : aucun évènement n'est jeté, et un clic sur un moniteur lui parvient.