EdwinMindcraft

Membre
  • Compteur de contenus

    18
  • Inscription

  • Dernière visite

Réputation sur la communauté

1 Réputation

À propos de EdwinMindcraft

  • Rang
    Membre
  • Date de naissance

Contact

  • Site Web
    http://sites.google.com/site/minecraftmoddingfr/home
  • Skype
    Mindcraft233

Jeux

  • Minecraft
    Edwin233

Autres informations

  • Genre
    Male
  • Lieu
    Devant mon PC ou mon téléphone
  • Intérêts
    Java, la creation, critiquer, les explosions

Visiteurs récents du profil

431 visualisations du profil
  1. forge

    Lorsque l'on code, il y a un moment où l'on a un problème avec une fonction du jeu, par exemple le fait qu'il puisse neiger dans les biomes chaud comme le désert ou le nether (biome Hell)... Heureusement, forge a une fonctionnalité pour remédier a ce problème : les CoreMods. Attention : ce tutoriel nécessite un niveau convenable en java, il n'est en aucun cas pour les débutants ! A cause du fonctionnement de la librairie ASM, écrire un CoreMod peut être extrêmement dangereux pour la compatibilité de votre mod, si vous pouvais vous en passer, je vous conseille fortement de le faire. Je ne suis pas responsable si vous faites n'importe quoi avec les CoreMods. Prérequis : -Avoir lu ce tutoriel : Lien -Avoir un niveau convenable en java 1] Les CoreMods : c'est quoi ? Les CoreMods sont des mods qui vont être activé avant le lancement de minecraft, il vont vous permettre de changer des fonction dans certaines class pour les faire fonctionner comme vous le voulais. 2] Ecrire un CoreMod Un CoreMod est composé d'au minimum 2 classes pour la lisibilité, une classe qui va définir le mod, et une autre qui vas être le transformer 2.A] La classe du Mod La classe du mod sera défini de cette façon : public class NomDuCoreMod extends DummyModContainer implements IFMLLoadingPlugin DummyModContainer est ce qui dit a Forge que votre classe est un mod et IFMLLoadingPlugin est l'interface qui sert pour faire des transformation au code de minecraft. Dans les méthodes générées de cette façon, une seule nous intéresse dans ce tutoriel : public String[] getASMTransformerClass() Cette méthode vas nous permettre de donner le chemin a notre transformer. pour cela mettez y ce code : return new String[] {"package.NomDuTransformer"}; 2.B] La classe du transformer La classe du transformer est défini de cette façon : public class NomDuTransformer implements IClassTransformer Lorsque vous faite ainsi une méthode va apparaître : public byte[] transform(String name, String transformedName, byte[] basicClass) La première chose a faire pour éviter d’empêcher le jeu de marcher est d'ajouter a la fin du code : return basicClass; 3] ASM L'ASM est une libraire de manipulation du bytecode des classes pendant l’exécution de l'application (Site Officiel) Pour commencer, nous allons devoir importer certains packages : import static org.objectweb.asm.Opcodes.*; import org.objectweb.asm.*; import org.objectweb.asm.tree.*; Ces trois package vous permettrons d'avoir toutes les classes dont vous avez besoin. 3.A] Accéder a une classe Accéder a une classe est la première chose a faire (pour des question de lisibilité, je vous conseille de faire une méthode par classe transformée) pour cela, nous allons ajouter ce code a la méthode transform : if (transformedName.equals("package.Class")) { return transformClass(basicClass); } Nous allons donc utiliser une méthode transformClass définie de cette façon : private byte[] transformClass(byte[] basicClass) 3.B] Lecture et écriture d'une classe Pour lire le code d'une classe, nous allons utiliser ClassReader (org.objectweb.asm.ClassReader) : ClassReader cr = new ClassReader(basicClass); ClassNode cn = new ClassNode(); cr.accept(cn, 0); Ce code vas stocker la classe dans la variable cn (ClassNode) et vas nous permettre de l'utiliser. Lorsque vous aurez fini, ajouter ce code a la fin : ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cn.accept(cw); return cw.toByteArray(); Celui-ci va réécrire la classe pour avec les modification que vous lui aurez apporté. 3.C] Accéder a une méthode Attention, si vous trouviez que ce tutoriel était dur jusqu’à présent vous n'avez surement pas le niveau nécessaire pour ce tutoriel, car la ça devient vraiment le bazar. Alors les methodes... le gros probleme c'est qu'elles ont 2 noms : un nom donné par MCP pour que vous puissiez comprendre a quoi elle sert et un nom donné par Mojang sous la forme a, b, c, d, e ou autre. Pour connaitre ces noms vous allez devoir ouvrir un fichier situé dans ou <mapping> est soit stable, soit snapshot et <version> est la version du mapping (voir build.gradle) Maintenant, pour acceder a la methode, nous allons devoir faire ceci : //Exemple de getFloatTemperature dans BiomeGenBase en 1.9 for (MethodNode mn : cn.methods) { if ((mn.name.equals("a") || mn.name.equals("getFloatTemperature")) && (mn.desc.equals("(Lcj;)F") || mn.desc.equals("(Lnet/minecraft/util/math/BlockPos;)F"))) { } } mn.name est le nom de la méthode et mn.desc représente ses paramètres. 3.D] Instructions (ou la partie avec le nom le moins recherché mais en fait c'est la plus importante) Une instruction permet de dire au code ce qu'il doit faire, ce sont ces instruction qui vont être exécutées par la JVM. 3.D.1] Variables Bon... je pense que tout le monde sait ce qu'est une variable... //Pour charger une variable utiliser ce code new VarInsnNode(<TYPE>LOAD, <ID>) //Pour enregister une variable utiliser ce code new VarInsnNode(<TYPE>STORE, <ID>) 3.D.2] Return Pour faire l’équivalent de return, il vous faudra utiliser : new InsnNode(<TYPE>RETURN) 3.D.3] Methodes Bon pareil les méthodes c'est le bazar : insn.add(new MethodInsnNode(<TypeDInvoke>, "<package/Class>", <name>, <desc>, <classEstUneInterface>)); <TypeDInvoke> peut être : INVOKEVIRTUAL, pour les methodes d'un objet INVOKEINTERFACE, pour les methodes d'une interface INVOKESTATIC, pour les methode statics 3.D.4] Fields Les fields sont les variables de classe, pour les appeler il faut faire ceci : new FieldInsnNode(<GETFIELD ou GETSTATIC>, <package/Class>, <name>, <desc>) 3.E] Utiliser des instructions C'est bien de savoir définir des instructions mais c'est mieux si on peut les utiliser, pour cela il y a 2 solution, soit les insérer une par une, soit créer une InsnList et insérer cette dernière. Une InsnList fonctionne exactement comme une list, donc je ne vais pas l'expliquer. Pour insérer les instruction vous pouvais soit en ajouter soit les replacer. La seconde solution est plus simple mais moins plus incompatible. 3.E.1] Insertion L'insertion nécessite une position, que l'on peut obtenir en allant a travers le instructions (mn.instructions) de la méthode, je vous conseille d'allez voir le code de minecraft pour ce système, lorsque vous avez votre position vous n'avez plus qu'a faire ceci : mn.instructions.insert(position, instruction); ou mn.instructions.insertBefore(position, instruction); le premier insert après et le second avant la position. 3.E.2] Remplacement C'est tout de suite plus simple, faite juste mn.instructions = <InsnList> 4] Charger le CoreMod Pour que Forge sache qu'il faut loader ce CoreMod ajouter dans les arguments JVM ceci : -Dfml.coreMods.load=package.ClassDuMod et ajouter : jar { manifest { attributes 'FMLCorePlugin': 'package.ClassDuMod', 'FMLCorePluginContainsFMLMod': 'true' } } et voila, vous avez un CoreMod fonctionel !
  2. C'est quasiment impossible car il y aura toujours un petit malin qui va faire un mod pour lui meme
  3. for (BiomeGenBase biome : BiomeGenBase.getBiomeGenArray()) { biome.setTemperatureRainfall(0.0F, 0.5F); } Ce code devrait faire l'affaire
  4. forge

    J'ai fini le tuto donc si il y a plus a faire demandez moi
  5. forge

    Introduction Dans Minecraft, les mods qui ajoutes des block ou des items sont bien mais... Ils sont surtout très limités. Dans ce tutoriel, je vais tenter de vous expliquer les Inventaire (IInventory) et les Containers et GUIs Prerequis : 1- Avoir une installation de forge 1.7.10 2-Avoir suivi ce tutoriel 3- Savoir faire un block 4- Savoir faire un TileEntity Sommaire 1] Block et Tile Entity 2] Sauvegarde 3] Ticking du block 4] Enregistrement 5] Container 6] GUI 7]Finalisation 1] Block et TileEntity Voila, on est au bases de l’inventaire. Pour commencer faites un block simple. Pas trop de travail hein… Votre block doit avoir extends BlockContainer Changez return null; dans createNewTileEntity par return new TileInventoryTuto(); et creer TileInventoryTuto en precisant : public class TileInventoryTuto extends TileEntity implements IInventory Lorsque vous corrigerais l'erreur, vous verrez beaucoup de méthodes apparaître. Ne vous en faite pas elle ne sont pas compliquées a complétées A] getSizeInventory() Bon… là pas grand-chose à expliqué : mettez le nombre de stack que votre block peut stocker. B] getStackInSlot(int slot) Ah, c’est un tout petit peu plus compliqué là… Pour cette méthode : introduction d’une nouvelle variable : stack, c'est cette variable qui vas contenir l'inventaire de votre block, c'est une liste d'ItemStack public ItemStack[] stack = new ItemStack[X]; Avec X = getSizeInventory() Après, c’est juste return stack[slot]; Ce code va juste prendre le stack a la position slot. C] devrStackSize(int slot, int num) public ItemStack decrStackSize(int slot, int num) { if (this.stack[slot] != null) { ItemStack itemstack; if (this.stack[slot].stackSize <= num) { itemstack = this.stack[slot]; this.stack[slot] = null; } else { itemstack = this.stack[slot].splitStack(num); if (this.stack[slot].stackSize == 0) { this.stack[slot] = null; } } return itemstack; } else { return null; } } Voilà le code, c’est le même dans 90 % des inventaires et c'est celui que l'on va utiliser. Il vérifie d'abord que l'item dans le slot existe, ensuite il regarde si le nombre à enlever est supérieur ou égal à la taille du stack. Si oui alors il vas enlever l'item du slot après en avoir fait un copies et va le return. Sinon, il vas couper le stack en 2 et il vas garder une des deux parties qu'il vas return. D] getItemStackOnSlotClosing(int slot) @Override public ItemStack getStackInSlotOnClosing(int slot) { if (this.stack[slot] != null) { ItemStack itemstack = this.stack[slot]; this.stack[slot] = null; return itemstack; } else { return null; } } Meme chose qu'au dessus, le meme code est utilisé dans tout les inventaires, il verifie d'abord que le stack dans le slot "slot" n'est pas null et dans ce cas, il return ce stack après l'avoir supprimer de l'inventaire. E] setInventorySlotContents(int slot, ItemStack input) public void setInventorySlotContents(int slot, ItemStack input) { this.stack[slot] = input; if (input != null && input.stackSize > this.getInventoryStackLimit()) { input.stackSize = this.getInventoryStackLimit(); } this.markDirty(); } Comme les deux precedents, celui si met un stack dans un slot et verifie que le stack en entre n'est pas trop grand. F] getInventoryName() et hasCustomInventoryName() @Override public String getInventoryName() { return "tileInventoryTuto"; } @Override public boolean hasCustomInventoryName() { return false; } Pour cette partie, changer "tileInventoryTuto" par le nom de votre block, c'est le nom de votre inventaire G]Les autres @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUseableByPlayer(EntityPlayer player) { return true; } @Override public void openInventory() { } @Override public void closeInventory() { } @Override public boolean isItemValidForSlot(int slot, ItemStack stack) { return true; } Pour l'instant laisser ce code tout seul, vous en avez pas vraiment besoin 2] La sauvegarde La sauvegarde des TileEntity s'appelle writeToNBT, vous allez devoir y mettre ce code @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); NBTTagList nbttaglist = new NBTTagList(); for (int i = 0; i < this.stack.length; ++i) { if (this.stack[i] != null) { NBTTagCompound tmp = new NBTTagCompound(); tmp.setByte("Slot", (byte)i); this.stack[i].writeToNBT(tmp); nbttaglist.appendTag(tmp); } } nbt.setTag("Inventory", nbttaglist); this.markDirty(); } Pour faire simple, ce code passe a travers la totalités des items stockés dans stack, si cet item n'est pas vide, les donnés de cet item sont stocké dans tmp puis mis dans la list. Finalement le la list est placée dans le nbt. Bon maintenant que on peut sauvegarder, il faudrait pouvoir relire les données. Pour cette fonctionnalité , minecraft nous offre readFromNBT: public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); NBTTagList nbttaglist = nbt.getTagList("Inventory", 10); this.stack = new ItemStack[this.getSizeInventory()]; for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound1 = nbttaglist.getCompoundTagAt(i); int j = nbttagcompound1.getByte("Slot") & 255; if (j >= 0 && j < this.stack.length) { this.stack[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1); } } } Ici, on s'occupe de passer a travers la liste et de remettre les items dans stack. La chose qui peut être difficile a comprendre est le "& 255" : il permet de passer d'un unsigned byte a un byte et donc à ne pas avoir un nombre aberrant dans "Slot". 3] Ticking du block Un inventaire c'est bien mais si il ne tick pas, il ne marche pas. pour cela nous avons 2 methodes @Override public Packet getDescriptionPacket() { NBTTagCompound nbt = new NBTTagCompound(); writeToNBT(nbt); return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, nbt); } @Override public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { readFromNBT(pkt.func_148857_g()); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); super.onDataPacket(net, pkt); } getDescriptionPacket est le code qui s’exécute avant l'update d'un block, on lui dit ici d’écrire l'inventaire dans le NBT et d'envoyer ce NBT, qui est ensuite reçu par onDataPacket qui s'occupe de le lire est de dire que le block doit s'update. 4]Enregistrement Bien, nous avons un block et un inventaire mais vous ne les trouverais jamais en jeu... Vous allez donc devoir les enregistrer dans forge. public static final Block inventoryTuto = new BlockInventoryTuto().setBlockName("tuto").setCreativeTab(CreativeTabs.tabDecorations); Ce code permet de créer le block et de le mettre dans la tab Decorations du menu creatif. Dans preInit GameRegistry.registerBlock(inventoryTuto, "tuto"); GameRegistry.registerTileEntity(TileInventoryTuto.class, "TileEntityInventoryTuto"); Ce code est la base de la base, registerBlock dit a forge "ce block existe et il a l'ID tuto" et registerTileEntity fait la meme chose avec les tileEntities Nous avons donc un inventaire mais... il n'est accessible que par des hopper... donc il ne marcheras pas pour les personnes qui adoooooooore le vanilla... 5]Le Container J'en vois déjà certain "On s'en fiche du container puis ça sert a quoi d'abord ton truc ?"... Pour faire simple, le container est le lien entre le GUI est la Tile Entity, c'est lui qui défini les positions des Slots dans votre Objet. Vous comprendrez donc que c'est le plus important dans l'histoire... Bien pour commencer, un Container extends la class Container. Jusque là tout le monde suit... Lors de l'ajout des méthodes, vous verrez apparaître canInteractWith qui ne sert que lorsque vous avez un inventaire comme un coffre (ne s'ouvre pas s'il y a un bloc solide au dessus). Par défaut laisser la donc a true Pour le constructeur, je vous conseille ce format : public ContainerTuto(InventoryPlayer player, TileInventoryTuto tile) { } Il permet d'avoir accès à la TileEntity et donc de faciliter certaines interactions. A]Les slots Les slots sont les endroits où vous pouvez ranger vous items, pour en ajouter, allez dans le constructeur Pour commencer, il y a 2 type de slot : Les slots du block Les slots du joueur On vas commencer par le joueur : int decalage = 84; for (int j = 0; j < 3; ++j) { for (int k = 0; k < 9; ++k) { this.addSlotToContainer(new Slot(player, k + j * 9 + 9, 8 + k * 18, j * 18 + decalage)); } } for (int j = 0; j < 9; ++j) { this.addSlotToContainer(new Slot(player, j, 8 + j * 18, 58 + decalage)); } Le décalage servira plus tard pour cadrer l'inventaire dans le GUI comme vous pouvez le voir, on ajoute d'abord les slot inventaire puis hotbar. Pour les slot du block voici le code basique, vous n'aurez qu'a le répéter autant de fois que vous avez de slot dans votre inventaire this.addSlotToContainer(new Slot(tile, id, x, y)); avec id qui vas de 0 a votre nombre de slot -1 x la position en X y la position en Y NB : pour placer vous slot vous pourrez utiliser le Debug Mode d'clipse qui vous permet de faire des modification en temps réel. B] Shift Click Eh oui vous avez bien compris, car pour l'instant Shift-Click = Crash pour remedier a ce probleme il faut override la methode transferStackInSlot @Override public ItemStack transferStackInSlot(EntityPlayer player, int slot) { ItemStack itemstack = null; Slot slotItem = (Slot) this.inventorySlots.get(slot); if (slotItem != null && slotItem.getHasStack()) { ItemStack itemstack1 = slotItem.getStack(); itemstack = itemstack1.copy(); if (slot < <NBSlotInventaire>) { if (!this.mergeItemStack(itemstack1, <NBSlotInventaire+1>, this.inventorySlots.size(), true)) { return null; } } else if (!this.mergeItemStack(itemstack1, 0, <NBSlotInventaire>, false)) { return null; } if (itemstack1.stackSize == 0) { slotItem.putStack((ItemStack) null); } else { slotItem.onSlotChanged(); } slotItem.onPickupFromSlot(player, itemstack1); } return itemstack; } Voila le code, c'est barbare, il regarde d'abord si le slot est un slot de l'inventaire du block, si oui il tente d'abord de placer les items dans la hotbar, puis si ça échoue, il le tente de le placer dans l'inventaire en lui meme. Dans le cas ou le joueur a shift-click un object dans l'inventaire, il tente de le mettre dans l'inventaire du block. C'est quasiment du copier coller a chaque fois donc... n’oublier juste pas de remplacer les <NBSlotInventaire> par le nombre de slot total de votre inventaire. Bon.. On en a fini pour le container maintenant le GUI. 6]GUI J'ai garder le plus simple pour la fin : le GUI votre classe devra juste extends GUIContainer pour le constructeur faite ceci : public GUITuto(InventoryPlayer player, TileInventoryTuto tile) { super(new ContainerTuto(player, tile)); } Cette méthode vous permettra d’accéder au tileEntity sans trop de problème et d'obtenir les informations des progress bars par exemple (Feu dans le four, les bulles du stand d'alchimie...) puis dans drawBackgroundImage Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(Tutorial.MODID, "<CheminDeLaTexture(textures/X.png)>")); int k = (this.width - this.xSize) / 2; int l = (this.height - ySize) / 2; drawTexturedModalRect(k, l, 0, 0, xSize, ySize); pour faire simple : On dit a minecraft met la texture dans la mémoire, calcule le coin X et le coin Y de la texture, affiche la texture en k, l en commençant par le pixel 0x et 0y de la taille xSize et ySize. Et voila vous avez un Gui presque fonctionnel. 7] Finalisation Pour cette dernière étape, il va falloir ajouter quelque choses dans le block , dans le mod et dans les proxies. A]Mod NetworkRegistry.INSTANCE.registerGuiHandler(this, proxy); Ce code vas dire à minecraft que votre proxy vas gérer les GUI de votre mod. B]Common Proxy implements IGuiHandler ajouter ceci, cela vas vous donner accès a 2 nouvelles methodes, getServerGuiElement et getClientGuiElement. Le serveur est toujours le container et le client le GUIContainer dans la methode getServerGuiElement ajoutez if (ID == <IDDuGUI>) return new ContainerTuto(player.inventory, (TileInventoryTuto)world.getTileEntity(x, y, z)); où <IDDuGUI> est une valeur différent a chaque GUI. Ce code vas associer a l'id <IDDuGUI> le container correspondant. C]Client Proxy ajouter un override de la méthode getClientGuiElement et ajoutez if (ID == <IDDuGUI>) return new GUITuto(player.inventory, (TileInventoryTuto)world.getTileEntity(x, y, z)); Ce code vas associer a l'id <IDDuGUI> le gui correspondant, dans les deux cas, <IDDuGUI> est la même D]Le Block Dans le block, dans la méthode onBlockActivated, ajoutez TileEntity tileEntity = world.getTileEntity(x, y, z); if (tileEntity == null || player.isSneaking()) { return false; } player.openGui(Tutorial.instance, <IDDuGUI>, world, x, y, z); return true; Cette partie de code va vérifier si le joueur n'est pas accroupi, si ce n'est pas le cas, il va ouvrir le GUI avec l'id <IDDuGUI> pour le joueur. et voila, vous avez un inventaire qui stocke des items. J’espère que ce tutoriel vous aura aidé
  6. Normalement il y a une variable temperature dans la classe BiomeGenBase
  7. C'est une question bete mais c'est quoi le probleme avec les APIs? Parce que moi la seule chose que je vois c'est : "Mon mod il sera compatible avec que dalle. Na!" ou sinon c'est "en faite j'arrive pas a installer les API et je prefere ne pas demander de tuto" P.S.: Pour la 2eme solution tu copie les sources de l'API dans le dossier common de forge.
  8. Bonjour/Bonsoir, Question bète et idiote, ça utilise l'OreDictionary? parce que ça pourrai etre pas mal pour FTB
  9. Utilise les sources de railcraft (les rails). Je pense que ça peut aider
  10. Pour la gaine essai de faire comme le bundled cable de redpower. Sinon il faudrait aussi une possibilite de changer la distance de communication du wifi (via le mod.cfg)