1. Le forum de Minecraft-France va définitivement fermer ses portes. Celui-ci restera en lecture seule mais vous ne pourrez plus y apporter de nouveaux topics. Nous vous invitons à nous rejoindre sur le Discord de Minecraft-France qui permet de présenter vos projets, discuter avec la communauté etc.. Merci à tous d'avoir fait vivre ce forum de nombreuses années. Pour nous rejoindre sur Discord, Cliquez ici

Autres [.NET] Récupération de la tête du joueur (2 méthodes)

Discussion dans 'Tutoriels' créé par Hawezo, 6 Mar 2016.

  1. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Il peut être bon enfant, après avoir connecté votre joueur à votre launcher, d'afficher sa tête, afin de rendre le tout encore plus sublime.

    Je vais vous montrer deux manières de récupérer la tête de votre joueurs lorsqu'il sera connecté, ou simplement à l'aide de son pseudonyme pour la première méthode.


    [​IMG]
    0. Code XAML de la fenêtre

    Dans ce tutoriel, aucun graphisme particulier, si ce n'est le minimum requis.
    Un bouton, une zone de texte pour le pseudonyme, une zone d'image, et puisqu'on est fous, une bordure. En WPF, bien entendu.
    Voici le code XAML de notre fenêtre :
    Code (xml):

    <Window x:Class="SkinRetriever.MainWindow"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
           xmlns:local="clr-namespace:SkinRetriever"
           mc:Ignorable="d"
           Title="MainWindow" Height="123.835" Width="226.165">
        <Grid Background="#FF212121">
            <Button x:Name="BTN_GET" Content="Obtenir" HorizontalAlignment="Center" Margin="88,47,10,23" VerticalAlignment="Center" Width="120" Height="30" TextOptions.TextHintingMode="Animated"/>
            <TextBox x:Name="TXT_USERNAME" HorizontalAlignment="Center" Height="30" Margin="88,17,10,53" TextWrapping="Wrap" Text="Hawezo" VerticalAlignment="Center" Width="120" TextAlignment="Center" TextOptions.TextHintingMode="Animated" VerticalContentAlignment="Center"/>
            <Border BorderBrush="#FF767676" BorderThickness="1" HorizontalAlignment="Left" Height="64" Margin="10,10,0,-10" VerticalAlignment="Top" Width="64">
                <Image x:Name="IMG_HEAD" HorizontalAlignment="Left" Height="64" Margin="0" VerticalAlignment="Top" Width="64"/>
            </Border>
        </Grid>
    </Window>
     
    Comme vous le voyez, c'est une interface tout à fait rudimentaire.


    I. La méthode dépendante

    Cette méthode, si elle est la plus simple, est celle qui comporte le plus de risque de dysfonctionner.
    En effet, son fonctionnement est à base de requête vers des API externes, telles que Minotar, que nous allons utiliser ici.

    Double-cliquez sur le bouton BTN_GET afin d'ouvrir son évènement par défaut, Click.

    1. Manière simple

    Je vous la déconseille (genre vraiment), mais c'est toujours utile quand même.
    La manière la plus simple est de télécharger l'image directement avec un WebClient dans un MemoryStream, sans passer par un autre thread.

    D'ailleurs, je déconseille, mais vous faire généralement votre connexion dans un autre thread : si tel est le cas, rien ne vous empêche de mettre cela à la fin de votre thread, ça ne bloquera rien, et dans ce cas, c'est même conseillé !

    Vous devez donc créer une variable de type BitmapImage, appeler sa fonction BeginInit(), puis mettre la valeur de son StreamSource à un nouveau MemoryStream nouvellement déclaré, qui lui aura dans son constructeur un nouveau WebClient vide, mais dont on appellera directement la méthode DownloadData, avec comme argument l'URL de Minotar avec le nom du joueur à la fin. :D
    Si vous avez suivi, franchement, bien joué.

    Voici le code :
    Code (csharp):

    BitmapImage head = new BitmapImage(); // Création d'un objet BitmapImage
    head.BeginInit(); // Initialisation de l'objet
    head.StreamSource = new MemoryStream(new WebClient().DownloadData("https://minotar.net/avatar/" + TXT_USERNAME.Text)); // Récupération de l'image grâce à un WebClient couplé d'un MemoryStream, le tout calé dans le StreamSource du BitmapImage
    head.EndInit(); // Fin de son initialisation

    Image image = this.IMG_HEAD as Image; // Conversion du contrôle Image
    image.Source = head; // Affichage de la source
     

    Il y a également quelque chose auquel il faut faire attention : les exceptions web.
    En effet, si vous n'êtes pas connecté à internet, que Minotar est indisponible, ou que vous avez mal écrit l'adresse... attention. À vous de gérer cela avec un try/catch.

    2. La manière chiante compliquée

    Si vous n'êtes pas dans un thread, vous devez donc en créer un.
    C'est heureusement plutôt simple. Dans l'évènement Click de votre bouton, écrivez :
    Code (csharp):

    String name = TXT_USERNAME.Text;
    Thread headDownload = new Thread(() => thread_Head(name));
    headDownload.Start();
     
    Maintenant, écrivez la méthode headDownload avec le contenu du code de la manière simple, avec par contre un appel au Dispatcher afin de pouvoir accéder aux éléments du thread de l'IU. Compris ? Allez, je vous le donne.
    Code (csharp):

    private void thread_Head(String name)
    {
      BitmapImage head = new BitmapImage();
      head.BeginInit();
      head.StreamSource = new MemoryStream(new WebClient().DownloadData("https://minotar.net/avatar/" + name));
      head.EndInit();
      head.Freeze();

      this.Dispatcher.Invoke((Action)(delegate
        {
            Image image = this.IMG_HEAD as Image; // Conversion du contrôle Image
            image.Source = head; // Affichage de la source
        }));
       
    }
     

    II. La manière indépendante

    Cette façon de faire est carrément plus complexe, mais vous ne serez pas dépendant d'API comme Minotar.
    Elle consiste à télécharger directement le skin, et à en extraire la tête \o/

    1. Télécharger le skin

    Il y a plusieurs manières de récupérer le skin du joueur. La première, la plus simple, et de le récupérer directement depuis sa source, à l'adresse suivante :
    http://s3.amazonaws.com/MinecraftSkins/USERNAME.png
    Je vais utiliser cette façon de faire par soucis de simplicité.

    La seconde méthode est de faire une requête GET à l'adresse https://sessionserver.mojang.com/session/minecraft/profile/UUID et de décoder le texte de la clé "value", codée en base64, et de récupérer l'URL de la clé SKIN.url fraîchement obtenue.
    C'est moins compliqué que ça en a l'air, mais ça reste fastidieux pour pas grand chose.
    Pour information, j'ai développé une API permettant de faire cette requête.

    Voici donc le code de mon téléchargement :
    Code (csharp):

    private void BTN_GET_Click(object sender, RoutedEventArgs e)
    {
        String name = TXT_USERNAME.Text;
        Thread headDownload = new Thread(() => thread_Head(name));
        headDownload.Start();
    }

    private void thread_Head(String name)
    {
        BitmapImage head = new BitmapImage();
        head.BeginInit();
        head.StreamSource = new MemoryStream(new WebClient().DownloadData("http://s3.amazonaws.com/MinecraftSkins/" + name + ".png"));
        head.EndInit();
        head.Freeze();

        this.Dispatcher.Invoke((Action)(delegate
            {
                Image image = this.IMG_HEAD as Image; // Conversion du contrôle Image
                image.Source = head; // Affichage de la source
            }));

    }
     
    2. Découpage de précision

    Vous avez maintenant le skin. Il faut maintenant ne récupérer que ce qui nous intéresse : la tête.
    Pour cela, rien de plus simple ! À la place de mettre head comme source, découpez votre image à l'aide de CroppedImage.
    La tête est située à 8 pixels du bord supérieur gauche (0, 0) et mesure 8 pixels.
    Code (csharp):

    image.Source = new CroppedBitmap(head, new Int32Rect(8, 8, 8, 8));
     
    Simplissime... sauf que si vous lancez, votre tête sera floue.

    Pour remédier à ce problème, modifier le XAML de votre Image et ajoutez-y RenderOptions.BitmapScalingMode="NearestNeighbor". Cela a pour effet d'empêcher le floutage des éléments trop petits lors de leur redimensionnement.

    Voici le code-behind final :
    Code (csharp):

    private void BTN_GET_Click(object sender, RoutedEventArgs e)
    {
        String name = TXT_USERNAME.Text;
        Thread headDownload = new Thread(() => thread_Head(name));
        headDownload.Start();
    }

    private void thread_Head(String name)
    {
        BitmapImage head = new BitmapImage();
        head.BeginInit();
        head.StreamSource = new MemoryStream(new WebClient().DownloadData("https://minotar.net/skin/" + name + ""));
        head.EndInit();
        head.Freeze();

        this.Dispatcher.Invoke((Action)(delegate
            {
                Image image = this.IMG_HEAD as Image; // Conversion du contrôle Image
                this.UseLayoutRounding = true;
           
                image.UseLayoutRounding = false;
                image.Source = new CroppedBitmap(head, new Int32Rect(8, 8, 8, 8)); // Affichage de la source
            }));

    }
     

    III. Bonus

    Je tenais à partager le fait que Minotar peut également fournir d'autres modèles de tête.
    En voici les adresses :
    [ ] Tête 3D : https://minotar.net/cube/JOUEUR (cependant, je déconseille son utilisation, car cela ne rendrait pas bien avec un style plat, comme dans mon tutoriel sur le design d'un launcher)
    [ ] Tête avec son casque : https://minotar.net/helm/JOUEUR

    Minotar peut également fournir des tailles différentes d'image, en ajoutant simplement "/taille" à la fin de l'url.
    Exemple : https://minotar.net/avatar/Hawezo/64
    Je vous invite à vous rendre sur la page minotar.net pour vous renseigner.

    Voici comment ça rend, de mon côté :

    Rendu final (oui, moche).PNG
    Figure 1 - Rendu de mon skin


    Rendu cube (déconseillé).PNG
    Figure 2 - Rendu 3D, déconseillé



    [​IMG]


    Vous savez maintenant obtenir la tête de votre joueur.
    Pensez à bien gérer votre code, à ne pas bloquer l'interface utilisateur grâce à vos threads.
    Une bonne organisation est aussi de mise.
    Si vous avez des questions, n'hésitez pas.
     
    • J'aime J'aime x 3
    #1 Hawezo, 6 Mar 2016
    Dernière édition: 6 Mar 2016
  2. Pikachu

    Pikachu Mineur

    Inscrit:
    26 Avr 2014
    Messages:
    392
    Points:
    89
    Sexe:
    Homme
    Mais dafuq ?
    T'as le temps de faire autant de bon post en aussi peu de temps ?

    En tout cas, ça a l'air encore super.
     
    • J'aime J'aime x 1
  3. Polymeth

    Polymeth Mineur de Diamants

    Inscrit:
    16 Août 2014
    Messages:
    2 133
    Points:
    180
    Sexe:
    Homme
    Laisse moi faire des tutoriels .NET pour ce qui est des serveurs et des mods, s'il te plait, si cela ne te gêne pas ! :)

    Sinon, je crois qu'il y a encore plus simple, mais j'ai la flemme d'aller rechercher, honnêtement.
    PS: Bon tutoriel, aussi. o/
     
    • J'aime J'aime x 1
    • J'approuve J'approuve x 1
    #3 Polymeth, 7 Mar 2016
    Dernière édition: 7 Mar 2016
  4. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    J'avais pas mal de temps libre :)

    @Polymeth c'est-à-dire sur des serveurs ou des mods ? Des tools pour les gérer/créer tu veux dire ?

    Sinon, merci :)

    Envoyé de mon LT18i en utilisant Tapatalk
     
    • Informatif Informatif x 1
  5. Polymeth

    Polymeth Mineur de Diamants

    Inscrit:
    16 Août 2014
    Messages:
    2 133
    Points:
    180
    Sexe:
    Homme
    Je vais faire des tutoriels sur mon "API" (code que je vais transformer en API, plutôt) de serveur (et de mod, aussi)
    C'est à dire créer les serveurs, gérer les .properties, les plugins, etc.
     
    • Informatif Informatif x 1
  6. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Ah, je vois ^^
    Je comptais en faire dans ce genre-là, mais n'hésite pas :)
    EDIT : En fait, j'avais déjà commencé un truc dans le genre il y a un bon moment. J'avais arrêté à cause du DMCA de Bukkit, mais il n'y a absolument aucun soucis à ce que tu fasses des tutoriels sur ton interface/API, au contraire ^^
    Mais là on s'égare du sujet et on part en flood, donc on se parle par MP si besoin ^^

    Envoyé de mon LT18i en utilisant Tapatalk
     
    • Informatif Informatif x 2
    #6 Hawezo, 7 Mar 2016
    Dernière édition: 7 Mar 2016

Partager cette page