Mettre à jour un mod 1.6.4 vers la 1.7.2
-
Ce tutoriel est également disponible en vidéo.
Sommaire
Introduction
Dans ce tutoriel nous allons apprendre à mettre à jour un mod 1.6.4 vers la 1.7.2. Le mod que je vais mettre à jour tout au long de ce tutoriel est le mod tutoriel créé à travers les différents tutoriels 1.6.4.
Pré-requis
Pour suivre ce tutoriel, il vous faut déjà les sources de votre mod en 1.6.4 et des compétences en programmation (la base de java).
Si le mod que vous souhaitez mettre à jour ne vous appartiens pas, la tâche sera plus compliqué (logique comme vous allez vous retrouver devant un code qui n’est pas le votre) et il vous faudra aussi l’autorisation de l’auteur original du mod.Il vous faudra aussi un espace de travail avec les sources de forge 1.7.2 (tutoriel ici).
Transférer votre code
Pour commencer, récupérez dans votre ancien espace de travail les sources de votre mod.
Si vous avez une installation avec les scripts python et mcp (tous les build de forge 1.6.4 sauf les versions de 9.11.1.960 à 9.11.1.964), aller dans <ancien forge>/mcp/src/minecraft et récupérez le dossier assets. Copiez-le dans le dossier <nouveau forge>/src/main/resources/ de votre nouvelle installation 1.7.2.
Faite la même chose avec l’autre dossier qui contient vos sources (celui qui porte le nom de votre package dans eclipse) mais copiez-le dans le dossier <nouveau forge>/src/main/java/.
Si vous avez une installation avec forge gradle (forge 9.11.1.960 à 9.11.1.964) il vous suffit de copier le dossier src de votre ancienne installation dans la nouvelle installation.Mettre à jour votre code
La classe principale :
C’est une des classes où vous allez avoir le plus d’erreurs. Pas de panic, les erreurs sont plutôt simple à corriger (c’est très répétitif).
Pour commencer, supprimer la ligne avec l’annotation @NetworkMod, elle n’existe plus et n’est plus nécessaire en 1.7 (donc pas de remplacement).
Vous pouvez faire aussi un ctrl + shift + o pour organiser les importations comme certaines classes ont changé de package. Pour Configuration, importez net.minecraftforge.common.config.Configuration.
Au niveau des matériaux d’outils et d’armures, EnumArmorMaterial et simplement devenu ArmorMaterial et EnumToolMaterial et devenu ToolMaterial (passez la souris sur l’erreur et prenez la deuxième correction “change to ‘ArmorMaterial’/‘ToolMaterial’”. Si vous avez enlevé “Enum” à la main, pensez à importer net.minecraft.item.ItemArmor.ArmorMaterial et net.minecraft.item.Item.ToolMaterialConcernant les ids, supprimez tout ce qui est en rapport avec. Depuis la 1.7, les ids ne sont plus gérés de la même façon. Avant la 1.7, les ids étaient tous initialisés lors du lancement du jeu, pour les modifier il fallait donc faire un fichier de configuration. Pour se connecter à un serveur moddé, il fallait aussi avoir les mêmes ids que la configuration du serveur. Cela causait beaucoup de problèmes, les conflits d’ids entre plusieurs mods (certaines personnes ne sont pas capable de modifier un fichier configuration …) et des problèmes de connexions aux serveurs moddés. Avec la 1.7, tout ceci est fini, c’est d’ailleurs pour ça que la 1.7 cause autant de changement côté code. Maintenant, lorsque vous lancez votre jeu, tous les blocs et items sont enregistrés avec un nom. (sous la forme modid:nom). Et lorsque vous allez rejoindre un serveur où vous connectez à un monde, un id va être associer à chaque nom. Cela permet donc d’avoir une synchronisation client <-> serveur des ids. Plus de conflit d’id non plus puisque le jeu va automatiquement attribuer des ids libres. Donc maintenant dans votre code il ne devrait plus avoir aucune référence aux ids. Le nom qui permet de reconnaître les blocs et items, c’est celui que avez mit dans GameRegistry.registerBlock(objet du bloc, “nom”) et GameRegistry.registerItem(objet du bloc, “item”). Il est donc important de ne pas changer ce nom, sinon la conversion va mal se passer et des blocs / items vont être perdu dans les mondes des utilisateurs de votre mod.
Maintenant que tout ce qui concerne les ids a été retiré de la classe principale, nous allons nous occuper de l’initialisation des blocs. Beaucoup de méthodes et de fields ont changé de nom :
setUnlocalizedName -> setBlockName
setTextureName -> setBlockTextureName
soundStoneFootstep -> soundTypeStone
soundClothFootstep -> soundTypeCloth
Même chose pour tous les autres sons de bloc.Pour un bloc lié à un fluide :
if(votreFluid.getBlockID() == -1)
devient :
if(votreFluid.getBlock() == null)
et
fluidTutorial.setBlockID(blockFluidTutorial); } else { blockFluidTutorial = Block.blocksList[fluidTutorial.getBlockID()]; }
devient :
fluidTutorial.setBlock(blockFluidTutorial); } else { blockFluidTutorial = fluidTutorial.getBlock(); }
Il vous restera des erreurs sur le constructeur des blocs, elles vont se corriger lorsque nous allons nous occuper des classes des blocs.
Concernant les items, il n’y a plus rien à faire dans la classe principale, vous avez normalement déjà enlevé l’id dans le constructeur, il n’y a rien d’autre à changer. Les erreurs restantes se corrigerons lorsque nous allons nous occuper des classes des items.
GameRegistry.registerWorldGenerator a changé, il faut maintenant ajouter un poids. Les générateurs avec un nombre faible seront exécuté plus tôt que ceux qui ont un nombre élevé. Par exemple :
GameRegistry.registerWorldGenerator(new WorldGeneratorTutoriel());
devient donc :
GameRegistry.registerWorldGenerator(new WorldGeneratorTutoriel(), 1);
Petit changement aussi avec l’enregistrement de gui handler :
NetworkRegistry.instance().registerGuiHandler(this.instance, new GuiHandlerTutorial());
Il faut juste remplacer instance() par INSTANCE.
Les fonctions MinecraftForge.setToolClass n’existe plus, elles ont été déplacés dans la classe item, nous verrons ça plus tard.
Côté recette, les objets des blocs et items de minecraft qui ont changés de classe donc :
Item. devient Items. (importez net.minecraft.init.Items)
Block. devient Blocks. (importez net.minecraft.init.Blocks)
La plupart des noms des blocs et items ont aussi changé de nom, par exemple Item.dyePowder est devenu Items.dye, Block.blockLapis est devenu Blocks.lapis_block, etc … vous pouvez facilement retrouver le nom en ouvrant les classes Blocks et Items.Une dernière chose dans la classe principale, vous pouvez retirer l’enregistrement de l’event sound, il n’est plus nécessaire.
Et voila, c’est tout pour la classe principale. Je rappelle que je me sers comme exemple le mod conçu à travers les tutoriels 1.6.4, vous n’avez donc pas exactement la même chose que moi. Vous avez peut-être des codes que je n’ai pas traité ici, si c’est le cas et que vous êtes bloqué, n’hésitez pas à exposer votre problème, on vous aidera !
Les items :
Nous allons nous occuper de toutes les classes des items. Pour commencer, dans toutes les classes enlever id du constructeur et pour ceux qui ont juste l’id dans le constructeur, supprimez son constructeur. Par exemple :
package tutoriel.common; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.world.World; public class ItemTutorial extends Item { public ItemTutorial(int id) { super(id); } public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { world.playSoundAtEntity(player, "modtutoriel:explosion", 1.0F, 1.0F); return stack; } }
Devient :
package tutoriel.common; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.world.World; public class ItemTutorial extends Item { public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) { world.playSoundAtEntity(player, "modtutoriel:explosion", 1.0F, 1.0F); return stack; } }
Pour les armures et les outils, il faut aussi changer EnumToolMaterial par ToolMaterial et EnumArmorMaterial par ArmorMaterial.
Dans le constructeur des outils, ajoutez setHarvestLevel(“pickaxe/axe/shovel”, niveau), c’est le remplaçant de MinecraftForge.setToolClass. Exemple pour une hache :public TutorialAxe(ToolMaterial toolMaterial) { super(toolMaterial); this.setHarvestLevel("axe", 3); }
Dans la classe de l’armure, la fonction getArmorTexture n’a plus les mêmes arguments :
public String getArmorTexture(ItemStack stack, Entity entity, int slot, String type)
Le reste de la fonction est identique sauf si vous avez une comparaison d’id. Dans ce cas, if(stack.itemID == ClassePrincipale.item.itemID) devient if(stack.getItem() == ClassePrincipale.item).
De façon général, voici ce qui a changé dans la classe d’un item :
Icon est devenu IIcon
La fonction :public void registerIcons(IconRegister iconregister)
est devenue :
public void registerIcons(IIconRegister iconregister)
Pensez à faire un ctrl + shift + o pour organiser vos importations.
La fonction :public void getSubItems(int id, CreativeTabs creativeTabs, List list)
est devenue :
public void getSubItems(Item item, CreativeTabs creativeTabs, List list)
et en conséquence list.add(new ItemStack(id, 1, metadata)); devient list.add(new ItemStack(item, 1, metadata));
Et pour finir la fonction :public Icon getIconFromDamage(int metadata)
est désormais :
public IIcon getIconFromDamage(int metadata)
Pour les disques de musique, supprimez la fonction getRecordTitle, cela passe désormais par le fichier de langage. (ajoutez item.record.<le nom que vous avez mit dans le constructeur>.name=Nom du disque dans votre fichier de langage).
Aussi, ajoutez cette fonction pour le son à jouer :public ResourceLocation getRecordResource(String name) { return new ResourceLocation("modid:records.nom"); }
Le son joué sera donc modid:records.nom (remplacez modid par votre modid), nous verrons plus tard comment l’enregistrer.
Pour les seaux, il faut juste remplacer int fluidId par Block fluid dans le constructeur.
Les blocs :
Pour tous les classes de blocs, il faut retirer le paramètre id.
Il faut remplacer tous les Icon par IIcon. La fonction :public void registerIcons(IconRegister iconRegister)
est devenue :
public void registerBlockIcons(IIconRegister iiconRegister)
La fonction
public Icon getBlockTexture(IBlockAccess blockaccess, int x, int y, int z, int side)
est devenue :
public IIcon getIcon(IBlockAccess blockaccess, int x, int y, int z, int side)
La fonction getBlockTileEntity(x, y, z) est devenu juste getTileEntity(x, y, z)
getEntityName() et pour toutes les entités est devenu getCommandSenderName()
La fonction addChatMessage(“message sous forme de String”) n’existe plus, il faut maintenant un composant de chat. Exemple :
player.addChatMessage(new ChatComponentText("message sous forme de String));
Et pour passer par les fichiers de lang :
player.addChatMessage(new ChatComponentTranslation(“nom.non.localisé”));La fonction breakBlock à aussi changer d’arguments, l’int id est devenu un bloc :
public void breakBlock(World world, int x, int y, int z, int id, int metadata)
devient donc :
public void breakBlock(World world, int x, int y, int z, Block block, int metadata)
Dans la fonction getSubBlock le premièr paramètre qui était avant l’id est maintenant un item :
@SideOnly(Side.CLIENT) public void getSubBlocks(Item item, CreativeTabs creativeTabs, List list) { for(int metadata = 0; metadata < type.length; metadata++) { list.add(new ItemStack(item, 1, metadata)); } }
Concernant les dalles, l’extends a changé, c’est maintenant BlockSlab. Il faut aussi ajouter dans le constructeur le matériel du bloc.
Le field isDoubleSlab n’a pas encore été mappé, il s’appelle pour l’instant field_150004_a
La fonction isBlockSingleSlab non plus, elle s’appelle func_150003_a et sans les ids ressemble à ça :private static boolean func_150003_a(Block block) { return block == ClassePrincipale.laDalleSimple; }
La fonction idPicked a aussi changé de nom :
@SideOnly(Side.CLIENT) public Item getItem(World world, int x, int y, int z) { return func_150003_a(this) ? Item.getItemFromBlock(ClassePrincipale.laDalleSimple) : Item.getItemFromBlock(ClassePrincipale.laDalleDouble); }
idDropped a été renommé getItemDropped :
public Item getItemDropped(int metadata, Random rand, int fortune) { return Item.getItemFromBlock(ClassePrincipale.laDalleSimple); }
(ce changement est aussi valable pour les autres blocs, pas que les dalles).
Dans la fonction getSubBlocks pour comparer l’item avec le bloc, il faut utiliser if(item != Item.getItemFromBlock(ClassePrincipale.laDalleDouble))Et pour finir, getFullSlabName n’est pas mappé non plus, elle s’appelle du coup func_150002_b.
Dernière chose, si vous rencontrez world.getBlockMetarial(x, y, z) (par exemple dans le gâteau), il faut maintenant utiliser world.getBlock(x, y, z).getMaterial().
Le générateur :
Dans la classe du générateur de monde (WorldGenerator en anglais), il faut supprimer toutes les références aux ids. Il suffit de retirer tous les .blockID. Il faut aussi changer le bloc de minecraft, je rappelle qu’il faut remplacer Block. par Blocks. et que certains blocs ont changés de nom (exemple Block.whiteStone -> Blocks.end_stone, Block.slowSand -> Block.soul_sand, etc …)
Les onglets créatifs :
Quelques petits changements ici, la fonction getIconItemStack n’est plus nécessaire car il y a maintenant getTabIconItem et func_151243_f. Exemple :
@Override public Item getTabIconItem() { return ClassePrincipale.item; } @Override public int func_151243_f() { return metadata voulu; }
La première fonction donne l’item (pour un bloc, utilisez return Item.getItemFromBlock(ClassePrincipale.bloc);). La deuxième fonction défini le metadata. Inutile de la mettre si le metadata est 0.
Les événements :
@ForgeSubscribe a été remplacé par @SubscribeEvent. Il faut aussi enlever toutes les références aux ids, donc :
world.getBlockId(x, y, z) devient world.getBlock(x, y, z), plus de .blockID ni de .itemID (à remplacer par getItem() pour les ItemStack), etc …Les commandes :
Un seul changement qui va se répéter par tout, sender.sendChatToPlayer(ChatMessageComponent.createFromTranslationKey(“message non localisé”)); est maintenant notifyAdmins(sender, “message non localisé”);
Si vous avez des arguments :sender.sendChatToPlayer(ChatMessageComponent.createFromTranslationWithSubstitutions("message non localisé", argument1, argument2));
Il faut utiliser :
notifyAdmins(sender, "message non localisé", new Object[]{argument1, argument2});
Les items de blocs :
Dans les items de blocs, il faut remplacer le paramètre id par un bloc dans le constructeur :
public NomItemBlock(int id) { super(id); ...
devient donc :
public NomItemBlock(Block block) { super(block); ...
Pour l’itemBlock d’une dalle, il y a plus de chose à remplacer :
Remplacer la condition if(id -256 = ClassePrincipale.votreDalleDouble.blockID) par if(block = ClassePrincipale.votreDalleDouble)
Tous les Icon devienent aussi IIcon, et dans la fonction getIconFromDamage, remplacez Block.blocksList[this.itemID] par this.field_150939_a.
Dans la fonction getUnlocalizedName, getFullSlabName est actuellement nommé func_150002_b
Et pour finir, dans la fonction onItemUse et la fonction canPlaceItemBlockOnSide (qu’il faut renommer func_150936_a), remplacez les int i1 = world.getBlockId(x, y, z) par Block i1 = world.getBlock(x, y, z), et enlevez les .blockIDLes entités de bloc / les container / les gui :
Du côté des inventaires, beaucoup de fonction ont été renommées.
onInventoryChanged est devenue markDirty
getInvName est devenue getInventoryName
isInvNameLocalized est devenue hasCustomInventoryName
openChest est devenue openInventory
et closeChest est devenue closeInventoryAutres changements, dans la fonction readFromNBT :
NBTTagList nbttaglist = nbttag.getTagList("Items");
nécessite un int en plus :
NBTTagList nbttaglist = nbttag.getTagList("Items", Constants.NBT.TAG_COMPOUND);
et nbttaglist.tagAt(i); a été renommé nbttaglist.getCompoundTagAt(i);
Vous utilisez aussi sûrement ce code dans votre tile entity pour communiquer le nbt tag du tile entity au client :
public Packet getDescriptionPacket() { NBTTagCompound nbttagcompound = new NBTTagCompound(); this.writeToNBT(nbttagcompound); return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 4, nbttagcompound); } public void onDataPacket(INetworkManager net, Packet132TileEntityData pkt) { this.readFromNBT(pkt.data); }
Désormais, il faut utiliser :
public Packet getDescriptionPacket() { NBTTagCompound nbttagcompound = new NBTTagCompound(); this.writeToNBT(nbttagcompound); return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 3, nbttagcompound); } public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { this.readFromNBT(pkt.func_148857_g()); }
Dans les gui, fontRender est devenu fontRenderObj, et comme dans les tile entity : getInvName est devenu getInventoryName et isInvNameLocalized est devenu hasCustomInventoryName.
Aussi I18n.getString s’appelle maintenant I18n.formatLes rendus :
Dans les TESR, this.setTileEntityRenderer(TileEntityRenderer.instance); est maintenant this.func_147497_a(TileEntityRendererDispatcher.instance);
Côté ISBRH, la fonction shouldRender3DInInventory() à maintenant un argument en plus :public boolean shouldRender3DInInventory(int modelId)
Les sons :
Les sons ont entièrement changés en 1.7. Maintenant il n’y a plus de code, tout passe par un fichier json.
Rendez-vous dans le dossier forge/src/main/resources/assets/<votre modid>/
Dans ce dossier, créez un fichier nommé sounds.json. Ajoutez aussi un s au dossier sound (sound devient donc sounds). Si vous avez un dossier records, déplacez-le dans le dossier sounds.
Le fichier sounds.json sera automatiquement détecté, et tous les sons seront enregistrés avec “<votre modid>:nom du son” car le sounds.json se trouve dans le dossier assets/<votre modid>/
Pour ajouter un son, il suffit d’ajouter ceci dans le fichier json :"nom du son": { "category": "categorie", "sounds": [ "chemin depuis le dossier sounds vers le son sans le .ogg", "deuxième chemin depuis le dossier sounds vers le son sans le .ogg", "troisième chemin depuis le dossier sounds vers le son sans le .ogg" ] }
nom du son : le nom du son (non sans blague x)), le nom final pour le jouer sera : <votre modid>:nom du son
categorie : la catégorie du son, player pour un joueur, neutral pour un mob passif, hostile pour un mob agressif, block pour un bloc, record pour un disque … je vous conseil de jeter un coup d’œil au fichier sounds.json de minecraft (.minecraft/assets/virtual/legacy/sounds.json).
sounds : le chemin vers le son à jouer depuis le dossier sounds sans l’extension ogg. Vous pouvez en mettre un seul, si il y en a plusieurs, un des sons sera prit aléatoirement lorsque le son sera joué. Donc si mon fichier s’appelle son1.ogg et qu’il se trouve dans le dossier assets/<modid>/sounds/, je dois mettre directement “son1” dans cette case. Si le son se trouve dans assets/<modid>/sounds/exemple/, je dois mettre exemple/son1. Cela permet donc de trier les sons dans des sous dossiers.Pour ceux qui ont jamais fait des fichiers json, ce type de fichier commence toujours par une ouverture d’accolades, et se finit par une fermeture d’accolades, et une virgule veut dire qu’il y a quelque chose après.
Voici un exemple de fichier sounds.json valide :
{ "explosion": { "category": "player", "sounds": [ "explosion1", "explosion2", "explosion3" ] }, "records.tuto": { "category": "record", "sounds": [ { "name": "records/tuto", "stream": true } ] } }
Pour jouer mon premier son, il faut donc que j’utilise modtutoriel:explosion et les 3 fichiers ogg se trouvent directement dans le dossier sounds. Pour jouer mon second son, j’utilise modtutoriel:records.tuto, le fichier ogg se trouve dans le sous dossier sounds/records/. “stream” : true indique que le son est une musique, et donc plus long.
Petit site très utile pour valider tous vos fichiers json : http://jsonlint.com/
Concernant le code, les méthodes pour jouer les sons n’ont pas changé.
Résultat
Et voila, nous en avons fini avec cette mise à jour. N’hésitez pas à poser des questions et demander de l’aide à la suite du tutoriel.
Voir le commit sur github
Le commit sur github montre clairement où ont été placés les fichiers, ainsi que ce qui a été ajouté et retiré dans le fichier.En vidéo
https://www.youtube.com/watch?v=OsD1JE1IGa0
https://www.youtube.com/watch?v=uIXybCZ_dYc
Crédits
Rédaction :
Correction :
Ce tutoriel de Minecraft Forge France est mis à disposition selon les termes de la licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International -
Bonjour. J’ai un petit soucis. quand je transfère mon code depuis la version 1.6.4 à la version 1.6.2, j’ai un bug avec le rendu de blocs fait par ISBRH. En effet, le bloc est bien là, mais son rendu ne se fait pas. Le seul moyen pour que le bloc apparaisse, c’est de poser un autre bloc (soit venant directement de Minecraft vanilla, soit un bloc avec un système de rendu TESR pouvant venir du mod) dans un rayon d’environ 5 bloc autour du bloc invisible. A ce moment là, le rendu apparaît.
voyez plutôt :
Help please
-
Si tu ne donnes pas tes codes, comment veux-tu qu’on t’aide?
-
Je n’ai pas le code 1.7.2. Ce mod est fait en groupe avec d’autres personnes. Moi je code en 1.6.4 et mon collegue lui code en 1.7.2. Je vais essayer de vous trouver les codes.
(Quelle class il faudrait que je poste d’après toi ? Sachant que ça fait ça sur tout les blocs que l’on ajoute via le système de rendu ISBRH)
-
Sans les codes on ne peut vraiment rien faire.
-
Je peux avoir les codes. mais j’ai besoin de savoir les class que je dois vous envoyer.
Je pense qu’avec la class d’un bloc, le renderBloc asocié et la class principale ça suffira non ? (je pourrais vous envoyer les codes demain)
-
Toutes celles qui concerne le bloc (client proxy, classe du bloc, tile entité, classe principale, tile entity special renderer et l’autre classe pour le rendu en main).
-
Bonjour bonjour après avoir réussi à faire marcher eclypse j’ai voulu ramener toutes mes classes de mon mod 1.6.4 sauf que problème ils sont en .class et non en .java comment faire?
-
Heu tu n’as plus les .java ?
Car avec les .class on ne peut pas faire grand chose. -
Les .class sont les classes compilées de ton mod. Si tu n’as plus les sources, tu es dans la [Insérez mot ici]
-
@‘utybo’:
Les .class sont les classes compilées de ton mod. Si tu n’as plus les sources, tu es dans la [Insérez mot ici]
Oui j’ai réinitialiser mes disque et eclypse voulait pas se lancer je vais voir pour les récupérer a noté que je n’ai pas fait de recompil
-
Tu as dû récupéré ce qui se trouvait dans le dossier bin qui contient le cache des classes compilées par éclipse (il me semble)
-
-
-