
os
L'ordinateur lui-même : temps, évènements, minuteries, nom, mémoire, redémarrage.
La bibliothèque os parle de l'ordinateur qui exécute votre programme : depuis combien de temps il tourne, quelle heure il est dans le monde, quel numéro et quel nom il porte, combien de mémoire il reste, et comment le redémarrer.
C'est surtout la porte d'entrée des évènements. Un programme qui appelle os.pull_event attend sans dépenser une seule instruction, et se réveille quand quelque chose arrive : un levier qu'on tire, une touche qu'on presse, un clic sur l'écran, un message, une minuterie qui sonne. Presque tous les programmes qui tournent longtemps sont construits autour de cet appel.
os.label("Ferme de fer")
print("L'ordinateur n°" .. os.id() .. " s'appelle " .. os.label())
os.queue_event("colis", "64 lingots de fer")
local e = os.pull_event()
print("évènement : " .. e.name .. ", données : " .. e.data)L'ordinateur n°7 s'appelle Ferme de fer évènement : colis, données : 64 lingots de fer
Tous les ordinateurs ont la bibliothèque os, du Calculateur à tubes à l'Ordinateur moderne.
os.pull_event([name]) | Attend le prochain évènement et le renvoie sous forme de table. |
os.queue_event(name [, data]) | Ajoute un évènement à la fin de la file de cet ordinateur. |
os.start_timer(seconds) | Lance une minuterie : au bout de seconds, un évènement timer arrive, avec le numéro de la minuterie dans e.id. |
os.time() | Les ticks depuis le démarrage de l'ordinateur : 20 par seconde, en nombre entier. |
os.clock() | Les secondes depuis le démarrage de l'ordinateur : le même compte que os.time, divisé par 20 (il avance donc par pas de 0,05). |
os.day_time() | L'heure du monde de Minecraft, en ticks : de 0 à 23999, une journée complète durant 20 minutes. |
os.id() | Le numéro de cet ordinateur, unique dans le monde. |
os.label([name]) | Lit ou change le nom de l'ordinateur. |
os.tier() | La génération du processeur de l'ordinateur, le nombre affiché au démarrage (Tier 4 - 131072 cells). |
os.memory() | La mémoire du programme, en cellules : used est mesuré à l'instant, total est ce dont dispose l'ordinateur. |
os.reboot() | Redémarre l'ordinateur, comme le bouton Redémarrer ou Ctrl+R. |
os.shutdown() | Éteint l'ordinateur, comme le bouton Éteindre du terminal. |
Évènements et minuteries
Un évènement est une petite table que l'ordinateur range dans une file d'attente quand quelque chose se produit. Son champ name dit ce qui s'est passé, les autres champs donnent les détails. Votre programme les sort de la file, un par un, avec os.pull_event.
| nom | quand | champs |
|---|---|---|
timer | une minuterie lancée par os.start_timer arrive à son terme | id |
redstone | un signal de redstone qui arrive sur une face de l'ordinateur change | aucun : lisez les faces avec rs.get |
key | une touche spéciale est pressée dans le terminal | key : "enter", "backspace", "delete", "up", "down", "left", "right", "home", "end", "tab" |
char | un caractère est tapé dans le terminal | char : le caractère, comme "a" |
paste | Ctrl+V dans le terminal | text (4096 caractères au plus) |
click | un clic sur l'image du terminal, ou un clic droit sur un moniteur | x, y, px, py, button, source |
drag | la souris bouge avec un bouton enfoncé, dans le terminal | les mêmes que click |
disk | un support de stockage est inséré ou éjecté | inserted : true ou false |
link | une fréquence de Liaison de redstone utilisée par le programme change | a, b, power |
message | un message d'un autre ordinateur (net) | sender, channel, data, via, distance |
| les vôtres | os.queue_event | data |
La page Évènements détaille chaque champ, et le guide Évènements explique comment construire un programme autour des évènements.
Attend le prochain évènement et le renvoie sous forme de table.
namestring facultatif- n'attendre que les évènements de ce nom ; les autres sont jetés
- table
- l'évènement :
name, et les champs propres à ce genre d'évènement
Le programme s'arrête sur cette ligne. Il ne consomme aucune instruction pendant l'attente : un ordinateur qui attend des évènements ne coûte rien, même pendant des heures. Quand un évènement arrive, l'appel le renvoie : e.name vous dit ce qui s'est passé.
-- Compte les objets qu'une Presse mécanique termine : un observateur
-- qui la surveille envoie une impulsion sur la face gauche de l'ordinateur.
local pressages = 0
while true do
os.pull_event("redstone")
if rs.get("left") > 0 then
pressages = pressages + 1
print("pressés : " .. pressages)
end
endUn évènement redstone arrive quand le signal monte et quand il redescend : c'est pourquoi le programme vérifie rs.get("left") avant de compter.
Avec un nom, l'appel n'attend que ce genre d'évènement, et jette tous les autres évènements qui étaient dans la file avant lui, comme dans ComputerCraft. C'est parfait pour un programme simple qui n'attend qu'une chose. Dans cet exemple, l'évènement de redstone est perdu :
os.queue_event("redstone")
os.queue_event("colis", "fer")
os.queue_event("colis", "or")
local e = os.pull_event("colis")
print(e.name, e.data)
e = os.pull_event()
print(e.name, e.data)colis fer colis or
Sans nom, l'appel renvoie le prochain évènement, quel qu'il soit. Dès qu'un programme attend deux sortes de choses (une minuterie et un levier, un clic et un message), appelez-le sans nom et regardez e.name : avec un nom, les évènements de l'autre sorte seraient perdus. net.receive attend de la même façon les évènements message, et jette lui aussi les autres ; read prend les évènements de touches dont il a besoin et laisse les autres dans la file.
Les évènements qui arrivent pendant que le programme calcule ou dort (sleep) ne sont pas perdus : ils attendent dans la file, dans leur ordre d'arrivée. La file contient 256 évènements ; quand elle est pleine, le plus ancien est abandonné.
Un clic droit sur un moniteur ouvre normalement le terminal. Dès que le programme a attendu des évènements click, ou n'importe quel évènement (os.pull_event() sans nom), un clic droit sur son moniteur appuie sur l'écran à la place, et un évènement click arrive avec source = "monitor". Accroupissez-vous pour ouvrir quand même le terminal. Cela dure jusqu'à la fin du programme.
Un programme qui réagit à un levier, à un bouton dessiné à l'écran et à une minuterie, le tout dans une seule boucle :
-- Une ligne de Presses mécaniques pilotée par un Embrayage sur la face arrière :
-- un levier à gauche ou le bouton à l'écran la démarre et l'arrête.
local en_marche = false
local rafraichir = os.start_timer(5)
local function dessiner()
term.clear()
term.set_cursor(1, 1)
print("Ligne de presses : " .. (en_marche and "en marche" or "arrêtée"))
print("Allumé depuis " .. math.floor(os.clock()) .. " s")
term.set_cursor(1, 4)
write("[ MARCHE / ARRÊT ]")
end
local function mettre_en_marche(oui)
en_marche = oui
rs.set("back", not oui) -- un Embrayage alimenté arrête la ligne
dessiner()
end
mettre_en_marche(false)
while true do
local e = os.pull_event()
if e.name == "timer" and e.id == rafraichir then
dessiner()
rafraichir = os.start_timer(5)
elseif e.name == "redstone" then
mettre_en_marche(rs.get("left") > 0)
elseif e.name == "click" and e.y == 4 and e.x <= 18 then
mettre_en_marche(not en_marche)
end
endIl n'existe pas d'évènement terminate : Ctrl+T (le bouton Stopper) arrête toujours le programme, sans qu'il puisse l'intercepter.
Voir aussi os.start_timer() os.queue_event() Évènements Évènements
os.queue_event(name [, data])
Ajoute un évènement à la fin de la file de cet ordinateur.
namestring- le nom de l'évènement
dataany facultatif- une valeur livrée dans le champ
datade l'évènement
L'évènement revient par os.pull_event comme n'importe quel autre, après ceux qui attendent déjà. La valeur passée en data (un nombre, un texte, une table...) arrive dans e.data.
os.queue_event("commande", {objet = "minecraft:iron_ingot", nombre = 32})
local e = os.pull_event("commande")
print(e.data.nombre .. " x " .. e.data.objet)32 x minecraft:iron_ingot
Un usage courant : faire travailler la boucle principale une fois dès le départ. Un programme qui met à jour une lampe à chaque évènement redstone n'afficherait rien avant le premier mouvement du levier :
os.queue_event("redstone") -- un faux premier évènement : lire le levier tout de suite
while true do
os.pull_event("redstone")
rs.set("top", rs.get("left") > 0)
endLe nom doit être un texte : os.queue_event(5) arrête le programme avec bad argument #1 to 'queue_event' (string expected, got number). Pour envoyer un évènement à un autre ordinateur, utilisez net.send.
Voir aussi os.pull_event()
Lance une minuterie : au bout de seconds, un évènement timer arrive, avec le numéro de la minuterie dans e.id.
secondsnumber- le délai, en secondes
- number
- le numéro de la minuterie
Contrairement à sleep, le programme ne s'arrête pas : il continue, et l'évènement attend dans la file jusqu'à ce que le programme le tire. C'est ainsi qu'un programme peut attendre un levier et faire quelque chose chaque seconde en même temps.
local id = os.start_timer(2)
local e = os.pull_event("timer")
print(e.name, e.id == id)timer true
- Le délai est arrondi au tick supérieur (un vingtième de seconde), un tick au moins :
os.start_timer(0)sonne au tick suivant,os.start_timer(0.12)après 3 ticks. - Le temps compte pendant que l'ordinateur tourne. Un ordinateur sans rotation est figé, ses minuteries aussi.
- Chaque minuterie reçoit un nouveau numéro. Comparez
e.idau numéro que vous avez gardé, pour qu'une vieille minuterie ne vous trompe pas. - 256 minuteries au plus peuvent attendre en même temps ; une de plus arrête le programme avec
too many timers. - Aucune fonction n'annule une minuterie : oubliez son numéro, et ignorez son évènement quand il arrive.
- Un redémarrage efface toutes les minuteries.
Un battement de cœur : la lampe du dessus clignote une fois par seconde pour montrer que le programme est vivant, pendant que l'ordinateur compte les impulsions qui arrivent à gauche :
local lampe = false
local impulsions = 0
local battement = os.start_timer(1)
while true do
local e = os.pull_event()
if e.name == "timer" and e.id == battement then
lampe = not lampe
rs.set("top", lampe)
battement = os.start_timer(1)
elseif e.name == "redstone" and rs.get("left") > 0 then
impulsions = impulsions + 1
print("impulsion " .. impulsions)
end
endUne attente avec limite de temps : attendre qu'un train appuie sur le rail détecteur à gauche, mais abandonner au bout de 30 secondes. Comme une fonction ne renvoie qu'une valeur en Brass, le résultat est true ou false :
local function attendre_train(secondes)
local limite = os.start_timer(secondes)
while true do
local e = os.pull_event()
if e.name == "redstone" and rs.get("left") > 0 then
return true
elseif e.name == "timer" and e.id == limite then
return false
end
end
end
if attendre_train(30) then
print("Train arrivé")
else
print("Train en retard !")
rs.set("top", true) -- la lampe d'alarme
endVoir aussi os.pull_event() sleep()
Temps
Trois horloges. os.time et os.clock mesurent depuis combien de temps l'ordinateur tourne, pour chronométrer une opération ou calculer un débit. os.day_time lit l'heure du monde de Minecraft, pour agir la nuit ou à midi. Le guide Temps et minuteries les compare avec sleep et les minuteries.
Les ticks depuis le démarrage de l'ordinateur : 20 par seconde, en nombre entier.
- number
- le nombre de ticks depuis le démarrage de l'ordinateur
Le compte part de 0 quand l'ordinateur démarre (posé, rallumé, redémarré) et n'avance que pendant qu'il tourne : un ordinateur sans rotation est figé, et son horloge s'arrête avec lui. C'est un chronomètre, pas un calendrier.
local debut = os.time()
sleep(1.5)
print("attendu " .. os.time() - debut .. " ticks")attendu 30 ticks
Voir aussi os.clock() os.day_time()
Les secondes depuis le démarrage de l'ordinateur : le même compte que os.time, divisé par 20 (il avance donc par pas de 0,05).
- number
- le nombre de secondes depuis le démarrage de l'ordinateur
C'est la plus pratique pour les durées et les débits. Par exemple, les objets par minute d'une ligne de production, d'après les impulsions d'un observateur sur la face gauche :
local debut = os.clock()
local objets = 0
while true do
os.pull_event("redstone")
if rs.get("left") > 0 then
objets = objets + 1
local minutes = (os.clock() - debut) / 60
print(math.round(objets / minutes) .. " objets par minute")
end
endVoir aussi os.time()
L'heure du monde de Minecraft, en ticks : de 0 à 23999, une journée complète durant 20 minutes.
- number
- l'heure du monde, de 0 à 23999
| valeur | heure | dans le monde |
|---|---|---|
| 0 | 6 h | lever du soleil |
| 1000 | 7 h | matin (/time set day) |
| 6000 | 12 h | midi |
| 12000 | 18 h | coucher du soleil |
| 13000 | 19 h | nuit (/time set night) |
| 18000 | 0 h | minuit |
| 23000 | 5 h | aube |
La valeur est la même pour tous les ordinateurs du monde. Elle saute quand les joueurs dorment dans un lit ou utilisent /time, et reste figée quand le cycle jour/nuit est désactivé.
Des lampes qui s'allument la nuit, comme dans le projet Éclairage jour et nuit :
while true do
local t = os.day_time()
rs.set("top", t >= 13000 and t < 23000) -- la nuit : lampes allumées
sleep(10)
endPour afficher l'heure comme une horloge (le programme clock le fait), décalez la valeur de 6000, puisque le tick 0 correspond à 6 h du matin :
local function texte_heure(t)
local depuis_minuit = (t + 6000) % 24000
local h = math.floor(depuis_minuit / 1000)
local m = math.floor(depuis_minuit % 1000 * 60 / 1000)
return string.format("%02d:%02d", h, m)
end
print(texte_heure(6000))
print(texte_heure(13000))
print(texte_heure(23500))12:00 19:00 05:30
Une routine quotidienne : une fois par jour, à midi, l'ordinateur sonne une cloche sur sa face arrière. Il retient la mesure précédente pour repérer le moment où l'heure dépasse 6000 :
local avant = os.day_time()
while true do
sleep(5)
local maintenant = os.day_time()
if avant < 6000 and maintenant >= 6000 then
rs.set("back", true) -- midi : on sonne
sleep(1)
rs.set("back", false)
end
avant = maintenant
endVoir aussi os.time()
Identité
Chaque ordinateur a un numéro donné par le monde, et peut avoir un nom donné par vous.
Le numéro de cet ordinateur, unique dans le monde.
- number
- le numéro de cet ordinateur
Le monde distribue les numéros dans l'ordre, à partir de 0, la première fois qu'un ordinateur tourne. Le numéro reste attaché à l'ordinateur : cassez-le à la pioche ou ramassez-le avec la Clé de Create, posez-le ailleurs, il garde son numéro (et son nom). Sur un ordinateur en réseau, net.id renvoie le même numéro : c'est l'adresse à laquelle les autres ordinateurs envoient leurs messages.
print("Ordinateur n°" .. os.id())Ordinateur n°7
La commande id du shell l'affiche aussi, tout comme l'infobulle des Lunettes d'ingénieur (Ordinateur n°7).
Voir aussi os.label() net.id()
Lit ou change le nom de l'ordinateur.
namestring facultatif- le nouveau nom, 32 caractères au plus ;
nilou""l'efface
- string|nil
- le nom de l'ordinateur, ou
nils'il n'en a pas
Sans argument, elle lit seulement le nom. Avec un argument, elle le change, puis renvoie le nouveau. Un nombre est converti en texte.
os.label("Portail nord")
print(os.label())
os.label(nil)
print(os.label())Portail nord nil
Le nom apparaît dans l'infobulle des Lunettes d'ingénieur (Étiquette : Portail nord), dans la commande id du shell, et dans le champ label de net.computers sur les autres ordinateurs du réseau. Comme le numéro, il reste sur l'ordinateur quand vous le cassez et le reposez. La commande du shell label Portail nord fait la même chose.
Un nom de plus de 32 caractères arrête le programme avec bad argument #1 to 'label' (at most 32 characters).
Le nom permet aussi de donner un rôle à un ordinateur : copiez le même programme sur plusieurs ordinateurs, et laissez chacun agir selon son nom.
local role = os.label() or "sans nom"
if role == "Portail nord" then
rs.set("left", true) -- ce portail s'ouvre par la face gauche
elseif role == "Portail sud" then
rs.set("right", true)
else
print("Donnez-moi d'abord un nom : label Portail nord")
endSur un réseau, les noms rendent la liste des ordinateurs lisible. Nommez chaque ordinateur une fois (label Fonderie, label Presses...), puis un ordinateur central les liste :
for _, c in ipairs(net.computers()) do
print("n°" .. c.id .. " " .. (c.label or "(sans nom)") .. " par " .. c.via)
endVoir aussi os.id() net.computers()
La génération du processeur de l'ordinateur, le nombre affiché au démarrage (Tier 4 - 131072 cells).
- number
- la génération du processeur, de 1 à 5
| ordinateur | génération |
|---|---|
| Calculateur à tubes | 1 |
| Ordinateur à transistors | 2 |
| Mini-ordinateur | 3 |
| Micro-ordinateur, Microcontrôleur | 4 |
| Ordinateur moderne | 5 |
Un programme emporté sur un support d'un ordinateur à l'autre peut s'adapter : dessiner avec gfx seulement à partir de la génération 2 (le Calculateur à tubes imprime sur papier), utiliser le réseau seulement à partir de la 3.
if os.tier() >= 2 then
gfx.clear("black")
gfx.text(4, 4, "STOCK", "yellow", 2)
else
print("STOCK")
endMémoire
La mémoire du programme, en cellules : used est mesuré à l'instant, total est ce dont dispose l'ordinateur.
- table
usedettotal, en cellules de mémoire
| ordinateur | total |
|---|---|
| Calculateur à tubes | 2 048 |
| Ordinateur à transistors | 8 192 |
| Mini-ordinateur | 32 768 |
| Micro-ordinateur | 131 072 |
| Microcontrôleur | 16 384 |
| Ordinateur moderne | 1 048 576 |
Tout ce que le programme garde en vie compte : chaque table prend 4 cellules plus 2 par entrée, un texte 1 cellule plus 1 par tranche de 8 caractères, le code du programme, les évènements qui attendent dans la file. Quand un programme a besoin de plus que total, il s'arrête avec out of memory. Une table de 1000 mesures prend environ 2000 cellules :
local avant = os.memory().used
local mesures = {}
for i = 1, 1000 do
mesures[i] = i * 0.5
end
print(os.memory().used - avant .. " cellules")2005 cellules
L'appel parcourt toutes les données vivantes du programme pour les compter : il coûte environ une instruction par tranche de 16 cellules utilisées. Vérifiez la mémoire de temps en temps (toutes les quelques secondes, ou avant de charger un gros fichier), pas à chaque tick. Une jauge pour un enregistreur de données qui ne doit pas déborder d'un Calculateur à tubes :
local m = os.memory()
local pourcent = math.floor(m.used * 100 / m.total)
print("mémoire : " .. pourcent .. " %")
if pourcent > 80 then
print("trop de mesures gardées, on jette les plus vieilles")
endVoir aussi Vitesse, mémoire et limites Limites
Alimentation
Les deux fonctions terminent le programme sur-le-champ : les lignes qui suivent l'appel ne s'exécutent jamais. L'ordinateur agit à la fin du tick.
os.reboot()
Redémarre l'ordinateur, comme le bouton Redémarrer ou Ctrl+R.
À la fin du tick, l'ordinateur relâche ses sorties (faces de redstone remises à 0, plus rien d'émis sur les fréquences des Liaisons de redstone, lignes de display.set effacées), efface l'écran, affiche sa bannière de démarrage et relance startup. Les variables, les minuteries et les évènements en attente sont perdus ; les fichiers, le nom et le numéro restent. os.time repart de 0.
Seuls un démarrage, un redémarrage, un arrêt ou le déchargement de son chunk relâchent les sorties. Quand un programme se termine simplement, plante ou est arrêté avec Ctrl+T, ses faces de redstone et ses fréquences de Liaisons de redstone restent comme elles étaient.
Un usage typique : un programme de mise à jour qui écrit une nouvelle version du programme, puis redémarre dessus.
local nouvelle_version = 'print("Fonderie v2 prête")'
fs.write("startup", nouvelle_version)
print("mis à jour, redémarrage")
os.reboot()Un ordinateur démarre au plus deux fois par seconde : un redémarrage demandé moins de 10 ticks après le précédent attend ce moment. Un startup qui appelle toujours os.reboot() tourne donc en boucle sans fin, deux fois par seconde. Éjectez le support pour casser la boucle.
Voir aussi os.shutdown() Les ordinateurs
os.shutdown()
Éteint l'ordinateur, comme le bouton Éteindre du terminal.
À la fin du tick, le programme s'arrête, l'écran devient noir et toutes les sorties sont relâchées. L'ordinateur reste éteint, même après un rechargement du monde, jusqu'à ce qu'un joueur ouvre son terminal et appuie sur Allumer (ou Redémarrer).
-- Fin de l'équipe de nuit : lampes éteintes, puis l'ordinateur s'éteint tout seul.
rs.set("top", false)
print("Fin de service, bonne nuit")
sleep(2)
os.shutdown()Voir aussi os.reboot()
Motifs courants
Agir toutes les N secondes sans cesser de répondre. sleep fige le programme : un clic pendant un sleep(60) attend une minute sa réponse. Une minuterie donne le même rythme, et le programme réagit toujours tout de suite au reste :
local rapport = os.start_timer(60)
while true do
local e = os.pull_event()
if e.name == "timer" and e.id == rapport then
print("rapport, heure du monde " .. os.day_time())
rapport = os.start_timer(60)
elseif e.name == "char" and e.char == "q" then
print("au revoir")
break
end
endPlusieurs minuteries à la fois. Gardez chaque numéro dans une variable nommée d'après son travail, et comparez :
local clignoter = os.start_timer(0.5)
local sauver = os.start_timer(30)
local lampe = false
while true do
local e = os.pull_event("timer")
if e.id == clignoter then
lampe = not lampe
rs.set("top", lampe)
clignoter = os.start_timer(0.5)
elseif e.id == sauver then
fs.write("etat_lampe", tostring(lampe))
sauver = os.start_timer(30)
end
endIci, n'attendre que "timer" ne pose pas de problème, puisque le programme n'écoute rien d'autre.