Create: Computing AgesDoc Brass
Piloter le monde

Redstone et liaisons de Create

Les six faces de l'ordinateur, les Liaisons de redstone de Create et les blocs qui obéissent à la redstone : lire boutons et détecteurs, piloter embrayages, inverseurs et chaînes Create entières.

La redstone est le moyen par lequel un ordinateur touche l'essentiel du monde. Un bouton, un levier, une plaque de pression ou un détecteur de Create signalent au programme que quelque chose s'est passé ; une lampe, une porte, un Embrayage ou un Inverseur de rotation font ce que le programme décide. Un ordinateur atteint la redstone de trois façons :

  1. Ses six faces, avec la bibliothèque rs : un fil, un bouton, une lampe ou un Embrayage de Create posé directement contre lui.
  2. Les Liaisons de redstone de Create, avec la bibliothèque link ou une Liaison de redstone utilisée comme périphérique (Liaison de redstone) : des signaux sans fil, jusqu'à 256 blocs par défaut.
  3. Les appareils qui ont leurs propres sorties, pilotés comme périphériques : le Feu tricolore, la Boucle de détection, le brûleur à air chaud (Hot Air Burner) de Create Aeronautics.

Les six faces

Les faces sont nommées par rapport à l'écran, telles que vous voyez l'ordinateur en face de son écran : front est l'écran lui-même, left et right sont votre gauche et votre droite, top et bottom le dessus et le dessous.

                   back
            (l'arbre arrive ici)
            +-------------------+
            |                   |
     left   |    ordinateur     |   right
            |    (vu de         |
            |     dessus)       |
            +-------------------+
                   front
                 (l'écran)

                   vous

Comme les noms suivent l'écran, un programme continue de marcher quand vous reconstruisez le même montage tourné dans une autre direction.

Deux faces sont souvent prises : l'arbre qui entraîne l'ordinateur arrive à l'arrière, back (en dessous, bottom, pour le Microcontrôleur, entraîné par le bas), et un moniteur peut occuper une autre face. Les autres faces sont libres pour la redstone.

rs.sides() renvoie les six noms, pratique pour parcourir toutes les faces. Tout autre nom arrête le programme avec bad side 'up' (front, back, left, right, top, bottom).

Lire les entrées

rs.get(face) renvoie la puissance redstone que le bloc posé sur cette face envoie dans l'ordinateur, de 0 (rien) à 15 (pleine puissance) : un levier, un bouton, une plaque de pression, un fil de redstone qui pointe vers l'ordinateur, un bloc alimenté, un comparateur, un Observateur intelligent de Create, une Liaison de redstone en mode réception posée contre lui...

La puissance redstone est analogique : 16 niveaux, pas seulement allumé ou éteint. Un fil perd un niveau par bloc, un comparateur mesure le remplissage d'un conteneur, un Levier analogique de Create donne le niveau que vous réglez. Pour traiter une face comme un simple interrupteur, testez rs.get(face) > 0.

Brass
if rs.get("left") > 0 then
  print("le levier de gauche est levé")
end
print("puissance sur le dessus : " .. rs.get("top") .. " / 15")

Attendre un changement : l'évènement redstone

Lire une face en boucle fonctionne, mais gaspille des instructions. Mieux vaut attendre l'évènement redstone. L'ordinateur en place un dans la file chaque fois qu'une entrée change, sur n'importe quelle face, y compris un changement de niveau (de 7 à 8). L'évènement ne porte aucun champ : lisez les faces qui vous intéressent quand il arrive.

Brass
while true do
  os.pull_event("redstone")
  print("gauche " .. rs.get("left") .. ", droite " .. rs.get("right"))
end

Comme un bouton donne un évènement quand on l'enfonce et quand il se relâche, et qu'un changement sur une autre face en donne un aussi, la plupart des programmes cherchent un front : l'instant où une face passe d'éteinte à allumée (front montant) ou d'allumée à éteinte (front descendant). Retenez la dernière valeur de chaque face et comparez :

Brass
local avant = {}
for _, face in ipairs(rs.sides()) do
  avant[face] = rs.get(face)
end

while true do
  os.pull_event("redstone")
  for _, face in ipairs(rs.sides()) do
    local maintenant = rs.get(face)
    if maintenant > 0 and avant[face] == 0 then
      print(face .. " s'allume")
    elseif maintenant == 0 and avant[face] > 0 then
      print(face .. " s'éteint")
    end
    avant[face] = maintenant
  end
end

Un programme qui attend dans os.pull_event lit les faces moins d'un tick après le changement : il voit toutes les impulsions ordinaires, même celle de 2 ticks d'un observateur. Un programme occupé ailleurs, ou qui dort entre deux lectures, peut regarder trop tard et trouver une impulsion courte déjà terminée : gardez ces programmes dans une boucle principale, ou allongez les impulsions avec un Extenseur d'impulsions de Create.

Régler les sorties

rs.set(face, puissance) envoie de la puissance par une face : un nombre de 0 à 15, ou true (15) et false (0). Au-delà de 15, la valeur compte pour 15 ; en dessous de 0, pour 0. Un nombre à virgule arrête le programme avec bad argument #2 to 'set' (number has no integer representation) : arrondissez-le d'abord avec math.floor.

Brass
local niveau = 11.6                  -- une valeur calculée par le programme
rs.set("top", true)                  -- la lampe du dessus s'allume
rs.set("right", 8)                   -- mi-puissance, pour une ligne de comparateurs ou un Tube Nixie
rs.set("left", math.floor(niveau))   -- 11
print(rs.get_output("top"))          -- ce que l'ordinateur envoie sur le dessus : 15

L'ordinateur donne une puissance forte, comme un bloc de redstone : la lampe ou l'Embrayage qui touche la face s'active, et un bloc plein contre la face transmet le signal à ce qui le touche.

rs.get_output(face) renvoie ce que l'ordinateur envoie sur une face. rs.get(face) est ce qu'il reçoit : ce sont deux choses distinctes, et un programme peut se servir des deux sur la même face.

Appliqué à la fin du tick

Les changements de sorties ne partent pas tout de suite vers le monde : ils sont appliqués une fois, à la fin du tick où le programme s'est exécuté, avec la dernière valeur demandée. Une boucle qui allume et éteint une face mille fois dans un tick ne coûte donc au monde qu'une seule mise à jour, et le serveur ne rame jamais.

Le revers de la médaille : allumer puis éteindre dans le même tick ne fait aucune impulsion.

Brass
rs.set("top", true)
rs.set("top", false)   -- même tick : la lampe ne voit jamais le 15

rs.set("top", true)
sleep(0.05)            -- un tick : le monde voit le 15
rs.set("top", false)   -- une impulsion d'un tick

La même règle vaut pour les Liaisons de redstone et pour la vitesse d'un Contrôleur de vitesse de rotation.

Relâchées quand l'ordinateur s'arrête

ce qui se passeles sorties
le programme se termine, plante, ou est arrêté par Ctrl+Trestent telles quelles
l'ordinateur cesse de tourner (pas de rotation, surcharge)restent : l'ordinateur est figé
l'ordinateur redémarre, s'éteint, ou son chunk se déchargerelâchées : toutes les faces à 0, toutes les Liaisons de redstone muettes

Une lampe allumée par un programme reste donc allumée après la fin du programme, jusqu'à ce que quelque chose l'éteigne ou que l'ordinateur redémarre. Et un programme qui démarre après un redémarrage trouve toutes les sorties à 0 : mettez-les dans un état connu au début.

Quand une sortie fait tourner une machine, pensez au plantage. Lancez le programme dans pcall et remettez tout en sécurité quoi qu'il arrive :

Brass
local function principal()
  -- le vrai programme : fait tourner la chaîne de presses...
end

local resultat = pcall(principal)
rs.set("left", true)   -- l'Embrayage de gauche arrête la chaîne, quoi qu'il se soit passé
if not resultat.ok then
  print("chaîne arrêtée : " .. resultat.error)
end

Ctrl+T ne s'intercepte pas : après lui, les sorties restent comme elles étaient.

Une Liaison de redstone envoie un signal redstone à travers les airs à toutes les liaisons de la même fréquence, une paire d'objets placés dans ses deux emplacements. L'ordinateur est lui-même une Liaison de redstone, pour 32 fréquences à la fois au plus, dans les deux sens :

  • link.set(a, b, puissance) émet sur la fréquence formée des objets a et b (des identifiants d'objets comme "minecraft:iron_ingot" ; un emplacement vide vaut "minecraft:air"). La puissance va de 0 à 15, ou true / false, comme pour rs.set.
  • link.get(a, b) renvoie la plus forte puissance émise par les autres liaisons de cette fréquence à portée. L'ordinateur n'entend jamais son propre signal.

Les liaisons portent à 256 blocs par défaut (le réglage serveur linkRange de Create), dans les chunks chargés, et transmettent le niveau complet de 0 à 15. Un identifiant d'objet erroné arrête le programme avec unknown item 'minecraft:iron_ingt' ; une 33e fréquence avec too many link frequencies (max 32).

Dès qu'un programme a utilisé une fréquence (avec link.get ou link.set), chaque changement de la puissance reçue dessus place dans la file un évènement link avec les deux objets et la nouvelle puissance. Pour écouter une fréquence, lisez-la donc une fois, puis attendez :

Brass
-- un levier à distance : la lampe du dessus recopie la fréquence fer + redstone
local A, B = "minecraft:iron_ingot", "minecraft:redstone"
rs.set("top", link.get(A, B))
while true do
  local e = os.pull_event("link")
  if e.a == A and e.b == B then
    rs.set("top", e.power)
  end
end

Et pour piloter une machine lointaine, posez à côté d'elle une Liaison de redstone en mode réception avec les deux mêmes objets, puis émettez :

Brass
link.set("minecraft:iron_ingot", "minecraft:gold_ingot", true)    -- le pont se lève
sleep(10)
link.set("minecraft:iron_ingot", "minecraft:gold_ingot", false)   -- et redescend

Tous les signaux de Liaison de redstone de l'ordinateur s'arrêtent quand il redémarre, s'éteint ou se décharge.

Taper des identifiants d'objets est source d'erreurs, et changer de fréquence oblige à modifier le programme. À la place, posez une Liaison de redstone contre l'ordinateur (ou sur son Câble de données), et mettez les objets dans ses emplacements, dans le monde. Comme périphérique, elle offre les mêmes get et set, sur sa fréquence :

Brass
local liaison = peripheral.find("redstone_link")
local f = liaison.frequency()
print("fréquence : " .. f.a .. " + " .. f.b)
liaison.set(15)            -- tous les récepteurs de cette fréquence s'allument
print(liaison.get())       -- ce que les autres liaisons y envoient

C'est toujours l'ordinateur qui émet et qui écoute : le bloc ne fait que nommer la fréquence, et changer les objets de ses emplacements règle le programme sur une autre fréquence sans toucher au code. Voir Liaison de redstone pour frequency et is_receiver.

Les appareils qui ont leurs propres sorties

Certains blocs du mod obéissent seuls à la redstone, et offrent à un ordinateur un contrôle plus fin comme périphériques :

  • Feu tricolore (Feu tricolore). Sans ordinateur, il suit la plus forte entrée redstone : 0 éteint, 1 à 4 rouge, 5 à 7 rouge et orange, 8 à 11 vert, 12 à 14 orange, 15 orange clignotant. rs.set(face, 9) passe donc au vert un feu posé contre l'ordinateur. Comme périphérique, set("green") en prend le contrôle, et le feu ignore alors la redstone jusqu'à release(), même après la fin du programme ou un redémarrage.
  • Boucle de détection (Boucle de détection). Elle donne 15 tant que quelque chose se trouve au-dessus (créatures, joueurs, wagonnets, bateaux, véhicules de Create Aeronautics) : une boucle contre l'ordinateur déclenche donc des évènements redstone. Comme périphérique, count() dit combien.
  • Brûleur à air chaud de Create Aeronautics (Brûleur à air chaud). Sa flamme suit la redstone qu'il reçoit : rs.set(face, 15) quand il touche l'ordinateur, une Liaison de redstone sinon.

Piloter Create

Beaucoup de blocs de Create changent de comportement quand ils sont alimentés. Un ordinateur qui règle leur redstone mène toute la machine :

bloc de Createune fois alimenté
Embrayagecoupe la rotation : tout ce qui suit s'arrête
Inverseur de rotationinverse le sens de rotation qui suit
Inverseur de rotation séquencéexécute sa liste de mouvements programmée, puis attend le signal suivant
Chaine de transmission ajustablechange le rapport de vitesse, de 1 à 2 selon le niveau analogique
Tube Nixieaffiche le niveau de puissance, de 0 à 15
Liaison de redstone (mode émission)envoie le signal à ses récepteurs

Le Contrôleur de vitesse de rotation n'écoute pas la redstone : un ordinateur règle sa vitesse comme périphérique, avec kinetic.set_speed() (voir Blocs cinétiques de Create). Le même périphérique cinétique lit la vitesse et le stress de n'importe quel bloc de Create.

Brass
local controleur = peripheral.wrap("top")   -- un Contrôleur de vitesse de rotation sur le dessus
controleur.set_speed(64)                    -- la chaîne tourne maintenant à 64 tr/min

Une chaîne de presses avec un Embrayage

Un tapis de Presses mécaniques fabrique des plaques de fer. Le moteur atteint la chaîne à travers un Embrayage posé sur la face gauche de l'ordinateur ; un Observateur intelligent qui surveille le tapis après la dernière presse est relié à la face droite. Le programme presse exactement un lot, puis arrête la chaîne :

lot
local LOT = 64
local faites = 0
local etait_allume = rs.get("right") > 0

rs.set("left", false)   -- embrayage relâché : la chaîne tourne
while faites < LOT do
  os.pull_event("redstone")
  local allume = rs.get("right") > 0
  if allume and not etait_allume then   -- une nouvelle plaque devant l'observateur
    faites = faites + 1
  end
  etait_allume = allume
end
rs.set("left", true)    -- embrayage alimenté : la chaîne s'arrête
print(faites .. " plaques de fer pressées")

La sortie reste allumée après la fin du programme : la chaîne reste arrêtée jusqu'au lot suivant.

Inverser avec un Inverseur de rotation

Un pont-levis sur un Roulement mécanique, un monte-charge sur une Poulie à corde : le même moteur les déplace dans les deux sens, un Inverseur de rotation choisit lequel. Avec un inverseur sur la face droite, un seul bouton à gauche le bascule :

Brass
local monte = false
local etait_appuye = false
while true do
  os.pull_event("redstone")
  local appuye = rs.get("left") > 0
  if appuye and not etait_appuye then
    monte = not monte
    rs.set("right", monte)   -- inverseur alimenté : l'autre sens
  end
  etait_appuye = appuye
end

Lancer un Inverseur de rotation séquencé

Un Inverseur de rotation séquencé exécute une liste de mouvements réglée dans son écran (« tourner de 90°, attendre, revenir ») chaque fois qu'il reçoit un signal. L'ordinateur décide quand : ici, chaque fois qu'un train passe devant l'Observateur de train relié à la face gauche (une plaque de pression ou n'importe quel détecteur marche de la même façon) :

Brass
while true do
  os.pull_event("redstone")
  if rs.get("left") > 0 then
    rs.set("top", true)    -- l'inverseur séquencé du dessus lance sa séquence
    sleep(0.1)
    rs.set("top", false)   -- prêt pour le train suivant
  end
end

Exemple : un générateur d'impulsions

Une fonction qui envoie un nombre d'impulsions, d'une longueur et d'un espacement choisis : pour alimenter un distributeur, lancer plusieurs fois un inverseur séquencé, ou faire clignoter une lampe.

Brass
local function impulsions(face, nombre, duree, pause)
  for i = 1, nombre do
    rs.set(face, true)
    sleep(duree)
    rs.set(face, false)
    sleep(pause)
  end
end

impulsions("top", 5, 0.1, 0.4)   -- cinq impulsions courtes, deux par seconde
while true do
  impulsions("right", 1, 0.5, 0.5)   -- puis une horloge régulière à 1 Hz à droite
end

L'impulsion la plus courte dure un tick (sleep(0.05)), et les durées s'arrondissent au tick supérieur. Sur un ordinateur lent, le code entre deux pauses prend aussi du temps : voir Vitesse, mémoire et limites.

Exemple : compter les objets d'un entonnoir

Un Observateur intelligent posé contre un entonnoir donne une impulsion chaque fois que des objets le traversent. Relié à la face gauche, il permet à l'ordinateur de compter ce qui sort d'une chaîne de Presses mécaniques, et de l'afficher sur son écran et sur un Panneau d'affichage (par une Liaison d'affichage pointée sur l'ordinateur) :

compteur
local compte = 0
local etait_allume = rs.get("left") > 0

local function afficher()
  term.clear()
  term.set_cursor(1, 1)
  print("Plaques de fer : " .. compte)
  display.set({"Plaques de fer", tostring(compte)})
end

afficher()
while true do
  os.pull_event("redstone")
  local allume = rs.get("left") > 0
  if allume and not etait_allume then
    compte = compte + 1
    afficher()
  end
  etait_allume = allume
end

Un entonnoir peut déplacer plusieurs objets d'un coup : chaque impulsion est alors un transfert, pas un objet. Pour compter les objets exactement, lisez plutôt l'inventaire d'arrivée comme périphérique (inventory.count()).

Exemple : une sortie codée en binaire

Une face peut porter 16 niveaux, mais un fil de redstone perd un niveau par bloc, et certaines machines ne comprennent qu'allumé ou éteint. Quatre faces utilisées comme quatre bits portent un nombre de 0 à 15 avec de simples signaux allumé/éteint : pour allumer une lampe parmi 16 à travers un décodeur, ou choisir une destination parmi 16 avec quatre Liaisons de redstone.

Brass
local BITS = {"left", "right", "top", "bottom"}   -- valent 1, 2, 4 et 8

local function afficher_binaire(n)
  local allumees = {}
  for i, face in ipairs(BITS) do
    local allume = (n // 2 ^ (i - 1)) % 2 == 1
    rs.set(face, allume)
    if allume then
      table.insert(allumees, face)
    end
  end
  return allumees
end

print(table.concat(afficher_binaire(11), " "))
print(table.concat(afficher_binaire(4), " "))
Écran
left right bottom
top

11 vaut 8 + 2 + 1 : les faces qui valent 8, 2 et 1 sont allumées. (n // 2 ^ (i - 1)) % 2 est le bit numéro i de n. Les quatre faces changent dans le même tick, puisque les sorties sont appliquées ensemble à la fin du tick : ce qui les lit ne voit jamais un nombre à moitié écrit.