Craftbox, fabriquer son serveur Minecraft : La programmation

Python, c'est pas seulement un serpent !

Cet article fait suite au précédent (logique…) présentant les différentes étapes de montage de la machine. Il faut avoir respecté rigoureusement les branchements de l’article en question pour continuer le projet.

Rappel

Nous allons utiliser les ports GPIO du Raspberry Pi pour piloter nos LEDs. C’est ici notre seule et unique objectif. Comme nous l’avons vu dans le précédent article, la LED rouge, témoin d’alimentation de la machine, ne passera pas par le script Python mais simplement par les ports « alimentés » de notre Raspberry Pi. Vous avez normalement branché les autres sur les PINs OUTPUT et GND.

Le script Python gérera la communication entre le Pi et PINs (et donc les LED).

Le port GPIO du Raspberry Pi

J’ai un serpent dans ma boot

Avant de commencer l’explication sur les différentes lignes de codes que composent notre code, NE FUYER PAS !

Les gens pensent souvent à tort, que le « développement » ou le « code » est un monde inaccessible par sa complexité. Nous allons principalement parler de logique, c’est un domaine tout à fait accessible à tout le monde, la partie technique n’est pas très importante.

Tout le monde peut comprendre le code que nous allons écrire


Grands comme petits pourront parcourir et comprendre le code ci-dessous. Il a été volontairement accès sur l’accessibilité et la facilité de lecture au détriment de l’optimisation.

Python est un langage de programmation, connu pour sa courbe d’apprentissage généreuse et ses multiples utilisations dans le domaine scientifique. De nombreuses librairies sont disponibles pour nous faire gagner du temps et c’est grâce à elles que nous allons programmer notre micro serveur Minecraft.

A l’attaque

Dans un premier temps, nous allons créer notre répertoire de travail sur le Pi. Il est préférable de garder celui utilisé lors de l’installation de Minecraft.
Pour ma part, j’ai choisi de créer un répertoire « script ». Dans un premier temps, connectez-vous à votre Craftbox (Raspberry Pi) en utilisant Putty par exemple.
Pour rappel, il vous suffit de rentrer l’IP de votre machine puis le nom d’utilisateur et le mot de passe. Respectivement « pi » et « raspberry » (sans les guillemets) pour le login par défaut.

Commençons par installer le gestionnaire de paquets (pour les librairies) de Python sur la machine :

sudo apt-get install python3-pip

Je me positionne dans le répertoire courant de Minecraft :

cd /home/minecraft

Puis je créais mon dossier de travail pour le script Python :

sudo mkdir script

Pour rappel, la commande « sudo » vous permet d’accéder temporairement aux droits de l’utilisateur « root » (administrateur), l’utilisateur pi n’ayant pas « tous les droits ». Pour aller dans notre répertoire fraîchement créé :

cd script 

Avant de commencer notre fichier, nous allons charger les librairies nécessaires. Le gestionnaire de paquets (pour les librairies je le rappelle) s’appelle PIP comme vous avez pu le voir plus haut :

sudo pip install mcstatus
sudo pip install socket
  • mcstatus est une librairie qui surveille l’état de l’instance Minecraft Server présente sur la machine. Elle nous retournera des informations importantes pour notre serveur comme le nombre de joueurs.
  • socket est une librairie qui établie une connexion du même nom entre un client et un serveur, nous nous en serviront pour « pinger » (interroger) le site de Google afin de savoir si nous sommes en ligne ou hors ligne.

Puis nous allons créer et éditer le script Python en faisant la commande suivante :

sudo nano script.py

« nano » étant l’éditeur de texte que nous allons utilisé pour écrire notre code (sorte de Notepad si vous préférez.

Une fois dans « nano« , nous allons mettre les mains dans le cambouis ^^, c’est parti pour le code :

#!/usr/bin/env python
# -*- coding: utf-8 -*-

Ces deux premières lignes serviront à l’interprétation du code, la première indique qu’il sagit de code python et la deuxième que nous allons utiliser l’encodage utf8 pour le texte.
Si vous n’êtres pas à l’aise avec ces notions, passez outre, il n’est pas essentiel de maîtriser cette partie.

import RPi.GPIO as GPIO  # bibliothèque pour utiliser les GPIO
import time              # bibliothèque pour gestion du temps
from mcstatus import MinecraftServer  # bibliothéque de status du serveur
import socket

Le code ci-dessus charge les librairies que nous avons préalablement installé et ceux présentes d’origines.

Nous allons définir notre serveur Minecraft et l’associé à une variable globale pour ainsi l’utiliser sur l’ensemble de notre code. Localhost étant la machine sur lequel se situe le serveur et 25565 le port utilisé par le serveur Minecraft (par default) :

server = MinecraftServer.lookup("localhost:25565");

Notre code va être coupé par de multiple portion de code qu’on appelle des « fonctions ». Cela nous permet de mieux découper et lire le code que nous écrivons. Commençons par la portion qui vérifie l’état de la connexion à internet / réseau de la machine :

def is_connected():
    try:
        host = socket.gethostbyname("www.google.com")
        socket.create_connection((host, 80), 2)
        print("WIFI fonctionnel")
        GPIO.output(21, GPIO.HIGH)  # allume la LED jaune
        return True
    except:
        GPIO.output(21, GPIO.LOW)
        print("Le wifi ne marche pas !")
        pass
    return False
  • def : définie notre fonction (ou définition) « is_connected() » correspond au nom de la fonction.
  • try / except : sécurise notre code en cas d’échec. Try va essayer, dans notre cas, nous allons essayer nous connecter à Google.com grâce à la libraire socket.
    Si il y a une erreur, notre code passera dans la portion « except » et éteindra la LED jaune du Wifi positionnée sur la sortie 21 du GPIO.
    L’élément GPIO.LOW baisse la tension à 0v et va éteindre la LED.
    L’élément GPIO.HIGH baisse la tension à 3.3v et va allumer la LED.
  • Return true renvoie la valeur « vrai » à l’appelant, sinon ce sera false.
def blink(players):
    i = 0
    while i < 5:
        if players > 0:
            GPIO.output(25, GPIO.HIGH)
            if players > 1:
                GPIO.output(24, GPIO.HIGH)
                if players > 2:
                    GPIO.output(23, GPIO.HIGH)
                    if players > 3:
                        GPIO.output(18, GPIO.HIGH)
        time.sleep(0.2)
        GPIO.output(18, GPIO.LOW)
        GPIO.output(23, GPIO.LOW)
        GPIO.output(24, GPIO.LOW)
        GPIO.output(25, GPIO.LOW)
        time.sleep(0.2)
        i += 1

Vous l’aurez peut être deviné, c’est la fonction qui va nous permettre de faire clignoter nos différentes LEDs correspondant au nombre de joueurs (de un à quatre). La fonction possède un paramètre « players » qui correspond au nombre de joueurs. La logique est la suivante.
Si la valeur de « players » vaut 2, on va définir la valeur de sortie correspondant au PIN des LED du joueur 1 et 2 sur GPIO.HIGH puis on attend 200ms ensuite on éteint toute les LED avec GPIO.LOW et enfin on attend encore 200ms. Le processus recommence…

  • i = 0 déclare une variable à 0 pour notre def (fonction)
  • while permet d’exécuter un code tant qu’une condition est respectée, ici tant que i est inférieur à 5.
  • time.sleep(0.2) va faire un pause de traitement selon un temps défini, ici 200ms
  • i += 1 va incrémenter notre variable locale (à la fonction) c’est la même chose que i = i + 1
def process():
    print("Process DEF")

    # boucle répétée jusqu'à l'interruption du programme
    while True:
        # 'status' est supporté par toutes les versions également ou supéreieur à 1.7
        status = server.status()
        # Affiche les informations sur le nombre de joueurs et le nombre de réponse
        print("Le serveur a {0} joueur(s) et répond en {1} ms".format(
            status.players.online, status.latency))
        if status.players.online > 0:
            # Si il y a un ou plusieurs joueurs alors on allume la/les leds
            blink(status.players.online)
        else:
            # Si il n'y a pas de joueur alors on eteint la/les LEDs
            GPIO.output(18, GPIO.LOW)  # sortie au niveau logique bas (0 V)
            GPIO.output(23, GPIO.LOW)
            GPIO.output(24, GPIO.LOW)
            GPIO.output(25, GPIO.LOW)
            time.sleep(3)  # on ne change rien pendant 1 seconde
  • Process() sera la fonction qui va appeler de manière récurrente la librairie mcstatus et donc notre fonction blink().
  • status = server.status() définie une variable avec l’instance de la librairie. Il ira récupérer les informations de notre instance locale de Minecraft Serveur.
  • While: true générera une boucle jusqu’à l’interruption du programme.
def setup():
    print("Setup")
    GPIO.setmode(GPIO.BCM)  # Mode de numérotation des pins du GPIO
    GPIO.setup(18, GPIO.OUT)
    GPIO.setup(21, GPIO.OUT)
    GPIO.setup(23, GPIO.OUT)
    GPIO.setup(24, GPIO.OUT)
    GPIO.setup(25, GPIO.OUT)
    print("end setup")

setup() sera notre fonction d’initialisation. indispensable au bon fonctionnement de notre interaction électrique.

  • GPIO.setmode(GPIO.BCM) définie le mode de numérotation des pins du GPIO. C’est avec ce système que nous pourront utiliser des nombres pour identifier nos PINs
  • GPIO.setup() prépare la PIN en question pour son utilisation future dans la programme.
def destroy():
    GPIO.output(18, GPIO.LOW)  # eteint la led
    GPIO.output(21, GPIO.LOW)
    GPIO.output(23, GPIO.LOW)
    GPIO.output(24, GPIO.LOW)
    GPIO.output(25, GPIO.LOW)
    GPIO.cleanup()  # Libère les ressources
    print("Fin du programme, on sort proprement")
  • destroy() est la fonction qui sera utilisée lors de la fermeture du programme. Il faudra, sortir « proprement » pour ne pas endommager notre matériel.
  • GPIO.LOW va baisser la tension de sortie au minimum, soit 0v
  • GPIO.Cleanup() libère les ressources, notre GPIO ne sera plus contraint.
if __name__ == '__main__':  # Le script demarre
    while True:
        try:
            setup()
            is_connected()
            process()
        except KeyboardInterrupt: 
            destroy()
            break
        except Exception as err:
            destroy()
            print('Erreur: ', err)
            break

La première ligne du code ci-dessus sera le code qui sera exécuté quand le script sera lancé. C’est notre point d’entré.

  • While True génère une boucle infini car la condition est toujours vraie.
  • try sécurise le code exécuté à l’intérieur de ce dernier
  • except KeyboardInterrupt va exécuter le code quand on va appuyer sur Ctrl + c
  • except Exception va exécuter un portion de code si une erreur de type « exception » est capturé dans le try

Terminus le terminal

Voilà pour les explications détaillées, vous pouvez retrouver l’ensemble du code directement sur le dépôt GIT officiel du projet :

https://github.com/paduction/Craftbox

Enfin, faites Ctrl + W pour fermer le fichier, à la confirmation répondez « O » pour valider l’enregistrement du fichier. Nous venons officiellement de créer notre script sur la machine.

Testons le code

Pour tester, nous allons lancer notre script avec la commande python avec pour paramètre notre fichier :

sudo python blink.py

Maintenant que le script est lancé, vous pourrez tester en ajoutant votre Craftbox dans la liste des serveurs multijoueurs, ce qui était déjà le cas normalement si vous avez fait les articles précédents.

Fenêtre des paramètres réseau des serveurs Minecraft

En vous connectant, vous devriez voir une LED bleu s’allumer ;)

Evidemment, nous n’allons pas exécuter le script « à la main » à chaque démarrage de la machine au contraire, nous allons réutilisé la même méthode qu’au début du projet en passant par rc.local.

Modifions le fichier ensemble avec la commande :

sudo nano /etc/rc.local
python /home/minecraft/script/blink.py > /home/minecraft/script/log.txt 2>&1 & sh /home/minecraft/autorun-minecraft.sh || /bin/true

Cette ligne est à positionner juste avant la ligne « exit 0 ».

Final Stage

Pour terminer enfin, nous allons redémarrer le serveur avec la commande suivante :

sudo reboot

Si tout s’est bien passé, vous devriez voir la LED jaune s’allumée quelques temps après le redémarrage de la machine. Prenez le temps de tester en vous connectant une fois de plus à votre micro serveur.
Félicitation, vous avez fini votre Craftbox !

Dans un monde parfait, le code fonctionne sans test et du premier coup. Je suis conscient que cette partie peut-être un peu difficile pour certains. Prenez votre temps pour le réaliser, pour le comprendre, relisez bien les différentes étapes et aidez-vous du lien ci-dessous qui contient l’ensemble du code final :

https://github.com/paduction/Craftbox

Si vraiment vous n’arrivez pas à finaliser votre Craftbox, venez en discuter sur le channel dédié du Discord de Paduction, la petite communauté et moi-même essayerons de vous aider le mieux possible ;)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *