Create: Computing AgesDoc Brass
Référence

É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.

Brass
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ènementChampsEnvoyé quandOrdinateurs
redstoneaucunune entrée redstone de l'ordinateur changetous
timeridun minuteur lancé par os.start_timer arrive à son termetous
keykeyEntrée, une flèche, Tab... est pressée dans le terminaltous
charcharun caractère est tapé dans le terminaltous
pastetextCtrl+V dans le terminaltous
clickx, y, px, py, button, sourceun clic sur l'écran du terminal ou sur un moniteurterminal : tous sauf le Calculateur à tubes ; moniteur : tous
dragx, y, px, py, button, sourcela souris bouge bouton enfoncé, dans le terminaltous sauf le Calculateur à tubes
messagesender, channel, data, via, distanceun autre ordinateur envoie un messageMini-ordinateur et plus récents
linka, b, powerune fréquence de Liaison de redstone utilisée par l'ordinateur changetous
diskinsertedun joueur insère ou éjecte le support de stockagetous sauf le Microcontrôleur
le nom de votre choixdatale programme appelle os.queue_eventtous

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.

FonctionReprend surLes autres évènements pendant ce temps
os.pull_event()le prochain évènement, quel qu'il soitaucun n'est perdu : chaque appel renvoie le suivant
os.pull_event(nom)le prochain évènement de ce nomjetés
net.receive([délai])le prochain évènement message, ou nil après délai secondesjetés
read([masque])la touche Entréekey, char et paste construisent la ligne ; les autres restent dans la file, dans l'ordre
sleep(secondes)la fin du délairestent 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 :

Brass
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)
Écran
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 :

Brass
os.queue_event("cloche")
sleep(1)
print(os.pull_event().name)
Écran
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 :

Brass
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)
Écran
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.send de l'expéditeur renvoie false) 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 sleep attendent avec lui.

redstone

ChampTypeValeur
(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 :

Brass
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
end

Voir rs et Redstone et liaisons de Create.

timer

ChampTypeValeur
idnumberle 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 :

Brass
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
end
Écran
une 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

ChampTypeValeur
keystring"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 :

Brass
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

ChampTypeValeur
charstringle 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 :

Brass
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
end
Attention

os.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

ChampTypeValeur
textstringle 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 :

Brass
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

ChampTypeValeur
xnumbercolonne du caractère cliqué, à partir de 1 (à gauche)
ynumberligne du caractère cliqué, à partir de 1 (en haut)
pxnumbercolonne du pixel cliqué dans le dessin gfx, à partir de 1
pynumberligne du pixel cliqué, à partir de 1
buttonnumber1 gauche, 2 droit, 3 milieu (toujours 1 sur un moniteur)
sourcestring"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() ou os.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 :

Brass
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
Écran
Écran

drag

ChampTypeValeur
x, y, px, pynumberlà où est la souris maintenant, comme pour click
buttonnumberle bouton enfoncé : 1 gauche, 2 droit, 3 milieu
sourcestringtoujours "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.

Brass
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
end

message

ChampTypeValeur
sendernumberle numéro de l'ordinateur qui l'a envoyé (son net.id())
channelstringle canal donné à net.send ou net.broadcast, "default" sans canal
dataanyune copie de la valeur envoyée (absent si rien n'a été envoyé)
viastring"cable", "radio" ou "wifi"
distancenumberla 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 :

Brass
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
end

Le 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.

ChampTypeValeur
astringpremier objet de la fréquence, tel que le programme l'a écrit
bstringsecond objet de la fréquence
powernumberla 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.

Brass
-- 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
end

Voir link et Liaison de redstone.

disk

ChampTypeValeur
insertedbooleantrue 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.

Brass
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
end

Vos propres évènements

ChampTypeValeur
dataanyle 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 :

Brass
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)
Écran
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.

comptepresse
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
end

La boucle appelle os.pull_event() sans nom : aucun évènement n'est jeté, et un clic sur un moniteur lui parvient.