Professeur

Membre
  • Compteur de contenus

    35
  • Inscription

  • Dernière visite

  • Days Won

    2

Professeur last won the day on 14 août 2015

Professeur had the most liked content!

Réputation sur la communauté

18 Réputation

1 abonné

À propos de Professeur

  • Rang
    242 de Q.I
  • Date de naissance
  1. 2. Mécaniques des entités 2.1 Types d'entités Il existe, bien sûr, plusieurs types d'entités, chacun représenté par une classe qui étend Entity. De manière générale, on pourrait les classer en 3 catégories : Les effets visuels (météo, particules, etc.) ; Les joueurs ; Le reste (monstres, animaux, flèches, items au sol, etc.). Ce découpage n'est pas fruit du hasard, il est effectué en fonction de la gestion client/serveur dont bénéficient les entités de chaque catégorie (les effets visuels ne sont pas synchronisés, les créatures et les joueurs apparaissent grâce à des packets différents) -- nous y reviendrons. Ces types d'entités sont enregistrés dans une classe nommée EntityList, qui enregistre, pour chaque type d'entité : Un numéro (unique) ; Un nom ; La classe de ce type. Chaque entité est une instance d'une des classes enregistrées dans cette liste, et ce côté client comme serveur, à l'exception des joueurs. 2.1.1 Le cas des joueurs Le modèle se complexifie un peu pour le joueurs. Alors que toutes les entités sont instance d'une classe portant le même nom et ayant sensiblement les même effets côté client comme serveur, on s'aperçoit que, côté client, les joueurs sont traités différemment ; il existe 2 classes filles d'AbstractClientPlayer : EntitityPlayerSP et EntityOtherPlayerMP. La nomination des classes est assez explicite : côté client, un joueur peut être celui qui est contrôlé par l'utilisateur, ou un autre joueur présent dans le monde. Côté serveur, c'est plus simple : tous les joueurs sont instances de EntityPlayerMP. Note : la présence dans les sources du client d'une classe EntityPlayerMP n'est due qu'à celle du serveur intégré, le client proprement dit ne s'en sert pas. 2.2 Création et suppression Comme nous l'avons dit, un numéro, un nom et une classe qui étend Entity sont liés dans la classe EntityList. Lors du chargement d'un monde, côté serveur donc, les données des entités sont lues depuis des fichiers au format NBT compressés. Une entité est instanciée, en utilisant le constructeur prenant en argument un monde (qui doit obligatoirement être présent dans toutes les classes filles d'Entity), puis ses informations (position, vie, déplacement, inventaire, etc.) sont lues depuis un NBTTagCompound récupéré du fichier de stockage. Lorsqu'une entité meurt (information relayée par le booléen Entity::isDead), elle est automatiquement supprimée du monde par le serveur. Pour toute question, avis, suggestion, merci de vous rendre sur ce topic Merci à Wytrem pour sa contribution.
  2. 1. Introduction Les entités, au même titre que les blocs, constituent un système absolument central de Minecraft. Tout, dans dans un monde, est soit une entité soit bloc (en considérant les TileEntities comme des blocs). On pourra par citer, comme exemples d'entités : Joueurs Cochons Particules Foudre Flèches Tableaux ... La compréhension des mécaniques qui régissent le système d'entités est donc fondamentale au modding (on pourra sauvagement faire le parallèle suivant : si les entités représentent la moitié des objets présents dans un monde, alors vous allez passer 50% de votre temps de moddeur à en coder). Pour toute question, avis, suggestion, merci de vous rendre sur ce topic Merci à Wytrem pour sa contribution.
  3. Les entités Sommaire Introduction Mécaniques des entités Types d'entités Création et suppression Déplacements Collisions Avec les autres entités Avec le monde Intéraction Synchronisation client/serveur Rendu des entités Introduction sur l'organisation du système de rendu Les modèles Les animations Vous pouvez proposer des améliorations sur ce topic
  4. Le professeur y ramènera sa science à travers chacun de vous.
  5. Le build n'est clairement pas la chose la plus compliquée, il faut cependant modifier le fichier build.gradle se trouvant à la racine du projet. version = "1.0" group= "fr.zeamateis.tutoriel_ic" // http://maven.apache.org/guides/mini/guide-naming-conventions.html archivesBaseName = "tutoriel_ic" Rien de bien méchant, simplement la version, le domaine et le MODID à définir. Note #1 : Si vous avez des dépendances c'est également dans ce fichier qu'il faut les déclarer, je vous laisse chercher un peu si vous en avez besoin. Lorsque vous avez terminé, lancez un terminal / un invité de commande. Entrez la commande suivante : gradlew build Votre mod compilé se trouve dans le dossier build/bin Astuce : Si vous souhaitez lancer le jeu en mode débug avec vos identifiants Mojang, rien de plus simple ! Dans les arguments de lancement du jeu, et dans l'encadré "Program arguments" déclarez votre username et votre password comme ceci: --username=Pseudo/Mail --password=VotreMDP Pour toute question, avis, suggestion, merci de vous rendre sur le topic d'aide. Merci à Dren pour sa contribution.
  6. Voici à quoi ressemble le projet par défaut. La première chose à faire c'est de renommer le package"com.example.examplemod"(raccourci Alt + Shift + R). Par convention, les nom de package doivent avoir un sens et se forment par l'abréviation de votre pays puis votre pseudo / organisation suivi par le nom du projet, le tout séparé par des points (exemple fr.zeamateis.xxx). Pensez également à renommer la classe principale afin qu'elle colle à votre projet et à sa fonction. 1]La Classe Principale La classe principale est comme son nom l'indique la classe principale, elle sert de "cerveau" aux "mods", chacun d'eux en ont un, seulsles "coremods" dérogent à cette règle mais nous y reviendront dans un autre tutoriel. Ouvrons la et "zieutons" son contenu : @Mod(modid = TutorielCore.MODID, version = TutorielCore.VERSION) public class TutorielCore { public static final String MODID = "exemplemod"; public static final String VERSION = "1.0"; @EventHandler public void init(FMLInitializationEvent event) { // some example code System.out.println("DIRT BLOCK >> "+Blocks.dirt.getUnlocalizedName()); } } La première chose que vous allez changer c'est le MODID, c'est l'identifiant unique de votre mod, il sert à éviter les conflits avec les autres et défini le dossier dans lequel ranger vos assets, ici nous allons utiliser"tutoriel_ic". Note #1: Le MODID doit toujours être en minuscules, aucunes majuscules et ne doit pas contenir d'espaces Pensez à ajouter un nom à votre projet, c'est plus sympa. Notez que le nom du mod accepte les espaces, accents et majuscules, tout le contraire du MODID. La valeur deVERSIONdépends de vos mises à jours, vous l'organisez comme vous le voulez, le but étant que ce soit clair pour identifier chaque versions. 2] Le MCMod.info Pour modifier les informations du mod (auteur(s), description, etc...), il faut modifier le fichier mcmod.info, qui ce trouve dans le dossier "src/main/resources" Le contenu est assez explicite mais je vous laisse quand même un exemple de fichier complété : [ { "modid": "tutoriel_ic", "name": "Tutoriel IronCraft", "description": "Oh la la , je suis une description pour le mod tutoriel d'IronCraft", "version": "1.0", "mcversion": "1.7.10", "url": "", "updateUrl": "", "authorList": ["ZeAmateis", "IronCraft", "MinecraftForgeFrance"], "credits": "Ironcraft pour accepter ce tutoriel", "logoFile": "/assets/tutoriel_ic/logoDuMod.png", "screenshots": [], "dependencies": [] } ] 3]Les Proxies Les proxies, sont utilisés pour permettre "l'universalité" des mods, pour qu'ils puissent fonctionner côté client ou côté serveur, et c'est là le gros avantage de forge. Créez un nouveau package, je l'ai personnellement nommé proxy et créez deux classes. La classe CommonProxy : package fr.zeamateis.tutoriel_ic.proxy; public class CommonProxy { public void init() { } } La classe ClientProxy : package fr.zeamateis.tutoriel_ic.proxy; public class ClientProxy extends CommonProxy { public void init() { registerRender(); } private void registerRender() { // some code } } Ajoutez ensuite une nouvelle annotation dans la classe principale : @SidedProxy(clientSide = "fr.zeamateis.tutoriel_ic.proxy.ClientProxy", serverSide = "fr.zeamateis.tutoriel_ic.proxy.CommonProxy") public static CommonProxy proxy; Appelez ensuite votre fonction init du proxydans la fonction init de la classe principale: public void init(...) { proxy.init(); } A l'heure actuelle les proxys sont fonctionnels, mais ne seront utiles que lorsque vous ajouterez des entités par exemple. 4]Les Assets La gestion des ressources est très simple ! Il suffit de créer un dossier assetspuis un dossier portant votre modid. Création du dossier assets via Eclipse: > Clic droit sur le dossier src/main/resources, New, Other, General, Folder: Entrez simplement le nom du dossierdans le champ de texte Folder name Répétez cette opération sur le nouveau dossier assets: Vous vous retrouverez ensuite avec quelque chose ressemblant à ceci : Répétez encore cette opération pour le dossier textures et lang Note: Cette opération remplace le traditionnel Clic droit > Nouveau Dossier de l'explorateur Windows par exemple. Vous devez vous retrouver avec ceci : Vous pourrez créer d'autres dossiers pour différents types d'assets comme les sounds par exemple. 4.1]Les Langues Dans le dossier lang il vous faudra créer des fichiers de traductions avec l'extension .lang. Voici une petite liste des définitions des langues : en_US : Anglais (USA) en_GB : Anglais (United Kingdom) fr_FR : Français (France) fr_CA : Français (Canadien/Québécois ?) es_ES : Espagne (Espagnol) it_IT : Italie (Italien) Vous trouverez les autres ici : http://minecraft.gamepedia.com/Language Donc pour les futures traduction en français et en anglais par exemple, il vous faudra les fichier fr_FR.lang et en_US.lang Pour toute question, avis, suggestion, merci de vous rendre sur le topic d'aide. Merci à MinecraftForgeFrance et TheAmateiis pour leurs contributions.
  7. Avant de commencer, je vais considérer que si vous utilisez un système UNIX, vous savez ce qu'est un terminal, naviguer dans les dossier et comment lancer un programme via celui-ci. Par conséquent les explications seront décrites pour Windows et uniquement si nécessaire sur d'autres systèmes. Ceci dit, rien ne vous empêche de préparer un paragraphe spécifique que j'ajouterais au tutoriel. 1]Le JDK Rendez-vous sur la page de téléchargement d'Oracle, choisissez la version appropriée puis télécharger là. Lancez le programme ainsi obtenu, décompressez le avant si nécessaire, et suivez les étapes jusqu'au bout. Ajoutez les lignes ci-dessous dans la variable d'environnementpath si elles n'existent pas C:\ProgramData\Oracle\Java\javapath; C:\Program Files\Java\jdk1.7.0_75\bin; Créez également les variables utilisateur JAVA et JAVA_HOME comme décrites sur l'image Note #1: Bien entendu vous devez changer la version du jdk et celle du jre par celle que vous avez installé, si vous avez un doute, parcourez le chemin manuellement. 2]Eclipse Pour installer eclipse, rien de plus simple, rendez-vous sur le site d'eclipse, choisissez la version que vous avez besoin, téléchargez la puis installez là. 3]Minecraft Forge Je vous invite à vous rendre sur le site de Minecraft Forge, choisissez votre version et téléchargez le formatsrc de celle-ci. Décompressez l'archive où vous souhaitez et placez vous dans le dossierfraîchement obtenu. Lancez un terminal / un invité de commande Entrez la commande suivante : gradlew setupDecompWorkspace & gradlew eclipse Attention, si le dossier est amené à bouger ou à être renommé, vous devrez relancer la commande gradlew eclipse. Choisissez le dossier eclipse contenu dans votre projet comme étant votre workspace soit au lancement d'eclipse, soit via file->switch workspace. Pour toute question, avis, suggestion, merci de vous rendre sur le topic d'aide. Merci à Dren pour sa contribution.
  8. Sommaire Par quoi je commence ? Dossier : Tout savoir sur l'installation. Premier mod Les meilleurs mods commencent comme ça. Allo ? Est-ce que ça marche ? Premier build et distribution. Vous pouvez proposer des améliorations sur le topic de discussion.
  9. Un peu de théorie Le code de Minecraft peut être divisé en 2 « côtés » : le Client et le Serveur. Le côté Serveur est chargé de la gestion du monde partagé par les clients connectés : rafraîchissement des blocs et des entités basé sur les packets qu'il reçoit du client, et envoi des informations mises à jour à tous les clients.Le côté Client est là pour être à l'écoute du des actions du joueur (clics souris, clavier, etc.) et pour dessiner la fenêtre.Il n'y a qu'un seul serveur, et plusieurs clients qui se connectent dessus. Même en mode solo, le serveur et le client tournent simultanément (dans des Threads séparés). Certaines parties du code sont « communes » : elles sont utilisées à la fois par le client et par le serveur. Mais alors, comment savoir depuis un code qu'on écrit à la fois pour le Client et le Serveur qui l'a appelé ? Depuis presque n'importe où dans le jeu, on peut avoir accès à un objet World (passé en field ou paramètre dans la plupart des cas). Dans ce cas là, il suffira de tester le booléen World.isRemote : Si World.isRemote vaut true : on est côté Server.Si World.isRemote vaut false : on est côté Client.Quand le Client et le Serveur ont besoins d'être synchronisés, ils échangent des informations par le réseau (LAN ou non).Même quand on est en mode solo, les deux côtés du jeu sont complètement séparés et n'accèdent pas aux objets de l'autre. Si le code executé (par exemple) côté Serveur tente d'accéder à des objets du côté Client, vous aurez affaire à des crash aléatoires ou des comportements étranges. Et de toute manière, votre mod ne pourra pas du tout fonctionner sur un serveur dédié (en multijoueur). Le communication Client <--> Server en vanilla passe par des « packets », qui sont envoyés et reçus depuis les classe NetHandlerPlayClient et NetHandlerPlayServer, respectivement côté Client et Serveur. Un packet est un ensemble de données, qui peuvent être échangées entre le Client et le Serveur. Il en existe beaucoup, de différents types, et qui servent à des choses très différentes : Les packets envoyé depuis le Client vers le Serveur servent à :Transmettre la position du joueur et ses mouvements, ainsi que ses intéractions avec l'environnement (casser un bloc, clic sur une entité, etc.)Envoyer des messages chatLes packets envoyé depuis le Serveur vers le Client sont beaucoup plus nombreux, et servent à :Informer le client des mouvements des entitésInformer le client des changements de blocsGérer les interfaces graphiques pour les containersEt plein d'autres trucs utilesIl est essentiel de noter que :Les packets envoyés depuis le Client vers le Serveur commencent avec un C, par exemple C07PacketPlayerDigging.Les packets envoyés depuis le Server vers le Client commencent avec un S, par exemple S06PacketUpdateHealth.Il est possible de créer des packets déjà présents dans Minecraft à la main et de les envoyer directement en utilisant le NetHandler, mais ce n'est presque jamais nécessaire. Si on connais les bonnes méthodes vanilla, elles enverront les packets pour nous (par exemple, appeler ServerConfigurationManager.sendChatMsg() à la place de S02PacketChat).Communiquer via le réseau avec nos propres packets Pour envoyer un packet, l'entité réseau (Client ou Serveur) utilise les sockets. Elle écrit le packet sur le flux de sortie en utilisant la classe PacketBuffer, comme nous le renseigne l'interface Packet : package net.minecraft.network; import java.io.IOException; public interface Packet { /** * Utilisé pour lire le contenu d'un packet que l'on reçoit. */ void readPacketData(PacketBuffer data) throws IOException; /** * Utilisé pour écrire le contenu d'un packet que l'on envoie. */ void writePacketData(PacketBuffer data) throws IOException; /** * Appelé lors de la réception du packet. * @param handler Objet INetHandler qui contient toutes les méthodes de déléguation (ex : handleChat, handleEntity...). */ void processPacket(INetHandler handler); } Chaque packet reçu (ou envoyé) est identifié par son numéro ID unique. Depuis la version 1.7, le système de packets a été beaucoup amélioré, de fait que maintenant, on ne manipule plus directement les IDs.Dans le thread d'écoute d'une entité réseau, seulement l'ID du packet reçu est lue directement. Ensuite, le système récupère une instance du packet correspondant grâce à la méthode EnumConnectionState.getPacket(EnumPacketDirection, int). Ensuite est appelée Packet.readPacketData(PacketBuffer) sur cette instance fraîchement obtenue, puis le packet est délégué. L'enregistrement de toutes les sortes de packets se fait dans la classe EnumConnectionState, qui représente le stade de connexion d'un client à son serveur. Chaque stade correspond à une phase du jeu : Le « handshaking », qui vérifie que la version du client est compatible avec celle du serveur ;Le « play » (lorsque le client est en jeu), qui sert à envoyer les informations évoquées ci-dessus (entités, changements de map, etc.)Le « status », qui sert à effectuer des requêtes sur le serveur, comme le ping ou l'information du nombre de connectés ;Le « login », qui sert à s'authentifier lors de la connexion au serveur.Nous allons, pour notre exemple, enregistrer un packet qui enverra au client un texte à afficher sur son écran. Ceci se passera dans la phase de jeu, on ajoute donc l'enregistrement de notre packet dans EnumConnectionState, en dessous de la déclaration du « play » : // [...] this.registerPacket(EnumPacketDirection.CLIENTBOUND, S48PacketResourcePackSend.class); this.registerPacket(EnumPacketDirection.CLIENTBOUND, S49PacketUpdateEntityNBT.class); // L'enum EnumPacketDirection sert à définir de quel côté le packet arrive. Ici, le client. this.registerPacket(EnumPacketDirection.CLIENTBOUND, S50PacketDisplayText.class); // [...] La classe S50PacketDisplayText n'est pas trouvée ? Alors créons là ! package net.minecraft.network.play.server; import java.io.IOException; import net.minecraft.network.INetHandler; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; public class S50PacketDisplayText implements Packet { public S50PacketDisplayText() {} // L'implémentation de Packet nous oblige à implémenter ses méthodes @Override public void readPacketData(PacketBuffer data) throws IOException { } @Override public void writePacketData(PacketBuffer data) throws IOException { } @Override public void processPacket(INetHandler handler) { } } Nous avons expliqué ci-dessus que la réception des packets se fait en en créant une instance nouvelle. C'est pourquoi il faut laisse un constructeur sans arguments ! Nous pouvons maintenant ajouter les fields qui vont contenir les informations qu'on souhaite faire transiter. Dans notre cas, il n'y en aura qu'un : private String displayText; Et pour la commodité, ajouter un constructeur qui permette directement de renseigner la chaîne de caractères : public S50PacketDisplayText(String text) { this.displayText = text; } Ainsi qu'une méthode pour récupérer le texte : public String getDisplayText() { return this.displayText; } Puis, il faut remplir les méthodes writePacketData et readPacketData, respectivement en y écrivant et lisant nos fields : @Override public void readPacketData(PacketBuffer data) throws IOException { // Le 256 est la taille maximum de la chaîne de caractères this.displayText = data.readStringFromBuffer(256); } @Override public void writePacketData(PacketBuffer data) throws IOException { data.writeString(this.displayText); } Notre packet est presque terminé ! Il manque l'appel de la délégation lors de son arrivée. Dans l'interface INetHandlerPlayClient, on créée donc la méthode : void handleDisplayText(S50PacketDisplayText packetDisplayText); Nous serons obligés de l'ajouter également dans les classes qui l'implémentent, c'est à dire NetHandlerPlayClient : @Override public void handleDisplayText(S50PacketDisplayText packetDisplayText) { System.out.println("Packet reçu avec le texte : " + packetDisplayText.displayText); } Et enfin, il nous reste à modifier la méthode processPacket(INetHandler) de notre S50PacketDisplayText : @Override public void processPacket(INetHandler handler) { ((INetHandlerPlayClient) handler).handleDisplayText(this); } Pour toute question, avis, suggestion, merci de vous rendre sur Merci à Wytrem pour sa contribution.
  10. Le rendu dans le monde Le rendu des blocs a considérablement changé par rapport aux versions antérieures. Cela a rendu la compréhension un peu plus compliquée mais a introduit beaucoup plus de flexibilité pour personnaliser l'apparence des blocs sans utiliser le code. Il y a quelques points clés à comprendre : Lorsque Minecraft rend un paysage, il faut d'abord rassembler les informations sur les blocs (emplacement, apparence, etc) dans une liste d'instructions que le moteur graphique peut exécuter. Typiquement, cela signifie une itération sur chaque bloc que le joueur pourrait voir et une conversion de chaque partie du bloc en une série de rectangles texturées. Un simple bloc comme la pierre dispose de six places, une pour chaque face. Les blocs plus complexes telles qu'une torche ou un piston sont constitués d'un plus grand nombre de faces rectangulaires, peut-être à des angles différents. Une fois la phase de rendu principale complète, Minecraft finit avec une liste d'instructions contenant la couleur, les coordonnées de texture et les informations d'éclairage qui peut être exécutée par le moteur graphique pour dessiner les blocs. La plupart des blocs dans un paysage sont statiques, c'est à dire qu'ils ne changent pas de forme ou de position au fil du temps. Cela permet à Minecraft de pré-compiler une liste d'instructions de rendu puis d'appeler le moteur graphique pour l'exécuter à plusieurs reprises, une fois par trame. C'est beaucoup plus rapide que la compilation des instructions de rendu à partir de zéro chaque trame. En général, les instructions ne sont recompilées que lorsque des blocs changent. Les blocs dans un paysage sont rendus de quatre manières différentes (voir photo ci-dessous). SOLID - La texture est totalement opaque, la valeur alpha est ignorée. CUTOUT_MIPPED - (test alpha) - Les textures du bloc ont des trous et le mip mapping est activé (Voir sur Google pour plus d'informations). CUTOUT - (test alpha) - Les textures du bloc ont des troussauf que le mip mapping est éteint. TRANSLUCENT- (mélange alpha) - Ces textures sont partiellement transparentes de sorte à voir d'autres blocs à travers. Si l'option graphique est sur "FAST", elles deviennent opaques. Les blocs blocs translucides sont relativement coûteux à rendre parce qu'ils doivent être pré-triés dans l'ordre de leur distance par rapport à la caméra, sinon ils ne rendront pas correctement. Un paysage est rendu en couches - tous les blocs SOLID sont établis en premier, puis les CUTOUT_MIPPED, puis CUTOUT, et enfin les TRANSLUCENT. Un bloc donné ne peut être rendu que dans l'une de ces quatre couches, spécifiée par Block.getBlockLayer(). Chaque bloc possède également un type de rendu, spécifié par Block.getRenderType() : -1 = Ne rend rien du tout, par exemple le bloc 'air'. 1 = Rend comme un liquide en écoulement (texture animée) en utilisant BlockFluidRenderer.genderFluid. 2 = N'utilise aucune couche de rendu des blocs maisuneTileEntitySpecialRenderer associé, par exemple le bloc 'chest'. 3 = Utilise unIBakedModel pour le rendu, BlockModelRenderer.renderModel. Ceci est décrit plus en détail ci-dessous. Il y a deux classes qui mettent en uvre l'interfaceIBakedModel,SimpleBakedModel et WeightedBakedModel. Elles sont toutes deux essentiellement identiques, sauf que la seconde choisit un modèle aléatoire à partir d'une liste de modèles alternatifs pondéré, en utilisant la position du bloc en tant que 'seed'. Cela permet pour certains blocs d'avoir une apparence différente selon l'endroit où ils sont placés. Le format BakedModel (utilisé par Minecraft pour presque tous ses blocs) est décrit ici. Il y a quelques considérations spéciales pour rendre les blocs transparents comme décrit ici. L'éclairage des blocs est décritici. Note : Certains blocs comme les fleurs utilisent la méthode Block.getOffsettype() pour déplacer de façon aléatoire la position du modèle (jusqu'à +/- 0,25 blocs). Pour toute question, avis, suggestion, merci de vous rendre sur Merci à Dren pour sa contribution.
  11. Textures les faces avec transparence A FAIRE
  12. Tuuuuutttooooosss

  13. Texturer les faces (quads) Les models des blocs sont utilisés par Minecraft pour relier les textured quads. La texture suit un système relativement strict, ça peut être difficile à maîtriser mais ce n'est vraiment pas difficile. Dans le diagramme ci-dessous, le bloc rouge pointe vers le sud (axe Z) et le bloc bleu pointe vers l'est (axe X). Texturer en utilisant les variables UV Les variables UV servent à découper l'image que nous souhaitons appliquer à une face. Le format [u1, V1, U2, V2] est utiliser pour sélectionner la zone à appliquer, U étant les coordonnées du point de départ etVcelles du point d'arrivé. Attention, Les faces sont toujours rendues dans le même sens, la direction dans laquelle vous regardez n'y change rien. Il vous faudra inverser U et V pour avoir une face opposée. La texture sera toujours affichée en direction du ciel pour les faces 2 à 5, du nord pour la 1 et du sud pour la 0. Je vous invite vivement à tester ce pack de ressourcesafin de bien visualiser le fonctionnement, la Stone et la Cobblestone sont utilisés. Il va de soit que le faire à la main pour un bloc complexe est difficilement réalisable, l'alternative consiste à utiliser un programme pour vous aider à faire ces models, BDcraft Cubik me semble le plus complet pour effectuer cette tâche mais il en existe d'autres. Pour toute question, avis, suggestion, merci de vous rendre sur Merci à TheShark34 pour sa contribution.