La classe principale et les proxys
-
Maintenant que tout est prêt, nous allons pouvoir commencer à coder
Commencez par faire défiler le dossier src, vous pourrez voir qu’il y a de nombreux packages. En fait c’est FML qui réorganise les sources de Minecraft afin d’être mieux triées.
Par ailleurs vous avez aussi pu constater qu’il n’y a qu’un seul projet (à la place d’un pour le serveur et d’un pour le solo) car FML les a également regroupé. C’est grâce à ça que nous pouvons faire des mods “universal” (et surtout grâce au système de side, que nous verrons plus en détail plus tard).
Créez maintenant un package, car contrairement à ML, Forge permet de créer son mod dans son propre package. Dans mon cas je vais l’appeler tutoriel.commonLa classe principale
Dans le package que vous venez de créer, vous allez créer une première classe. Dans mon cas je vais l’appeler ModTutoriel. Avec ForgeModLoader, il est inutile de commencer le nom de sa classe par mod_
Nous allons compléter cette classe avec quelques interfaces qui se trouvent dans l’interface Mod (cpw.mods.fml.common.Mod)
Directement en dessous de la déclaration de package, nous allons ajouter @Mod. Vous allez avoir une erreur, passez la souris dessus, et cliquez sur import ‘Mod’ (cpw.mods.fml.common.Mod)
Normalement @Mod devrait changer de couleur, mais il y a toujours une erreur. Cliquez maintenant sur “Add missing attributes”. Après @Mod, il devrait s’ajouter ceci : (modid = “”)
Le modid correspond à l’id de votre mod, si FML détecte deux mods du même id, il va pensez que l’utilisateur a installé deux fois le même mod. Il est donc important d’utiliser un modid qui n’est pas utilisé par d’autres mods. Dans mon cas, je vais simplement reprendre le nom de ma classe principale :@Mod(modid = "ModTutoriel")
On peut ajouter de nombreuses choses à ce @Mod, en les séparant par des virgules. Je vais donc faire le tour de tout ce qui se trouve dans l’interface @Mod.
- String modid() c’est le mod id, il n’a pas de valeur par défaut, c’est pour ça que nous sommes obligés de le remplir
- String name() c’est le nom de votre mod, celui qui s’affiche dans la liste des mods. Dans mon cas je vais mettre “Mod Tutoriel”
- String version() c’est la version de votre mod, dans mon cas je vais mettre “1.0.0”
Voilà, ce sont les trois plus importants, ma classe principale ressemble maintenant à ça :
package tutoriel.common; import cpw.mods.fml.common.Mod; @Mod(modid = "ModTutoriel", name = "Mod Tutoriel", version = "1.0.0") public class ModTutoriel { }
Je vais quand même en décrire quelques autres, ça peut toujours être utile :
- String dependencies() Permet de faire des dépendances d’autres mods. Par exemple “required-after:Forge@[7.8.1,)” forcera l’utilisateur à avoir une version de forge supérieur au build 737 (Forge est le modid, si vous voulez le faire avec un autre mod, il faut aussi utiliser le modid
- boolean useMetadata() Soit true, soit false, par défaut false. Cela n’a rien à voir avec les metadatas de blocs ou d’items, s’il est en true, vous pourrez intégrer le mcmod.info à l’intérieur de votre classe principale, comme Forge ou FML.
- String acceptedMinecraftVersions() Ce sont les versions de Minecraft acceptées par votre mod. Il faut utiliser le “maven version range”, voir ici
- String certificateFingerprint() On peut l’utiliser pour faire un système de vérification, (par exemple dans le cas où vous avez Forestry et IndustrialCraft d’installés, Forestry va vérifier si IC2 n’est pas “trafiqué”, si jamais il est modifié votre jeu se coupera). En revanche, je ne sais pas comment le faire fonctionner, si quelqu’un a des informations là-dessus, je prends
- String modLanguage() par défaut java, on peut aussi créer des mods en scala
Dans la classe principale en dessous de @Mod, ajouter @NetworkMod.
Pour l’instant, nous allons juste utiliser les deux booleans clientSideRequired et serverSideRequired :@NetworkMod(clientSideRequired = true, serverSideRequired = false)
clientSideRequired signifie que le client doit avoir le mod pour rejoindre un serveur où le mod est installé. Il faut le mettre en true, sauf si votre mod n’ajoute que des choses qu’ajouterai un plugin (exemple, Dynmap Forge et Forge Essential on cette valeur sur false)
serverSideRequired signifie que le serveur doit avoir le mod pour être rejoint par un client qui possède ce mod. Il faut donc le mettre en false, sauf si vous voulez que les utilisateurs possédant le mod ne puissent se connecter à aucun serveur sauf ceux qui ont le mod.
Dans le @NetworkMod, vous pouvez aussi définir la version bound : versionBounds = “[1.0.0,1.2.0]” par exemple, fonctionne aussi avec le “maven version range”, avec cette exemple, un client en version 1.0.1 du mod pourra se connecter sur un serveur qui possède la version 1.1.2 du mod. Pour globaliser, toutes les versions comprises entre 1.0.0 et 1.2.0 pourra se connecter à un serveur qui possède le mod.Bon maintenant que nous avons rempli ces deux interfaces, nous allons créer quelques fonctions dans notre classe principale.
Pour ceux qui ont l’habitude de modloader, il ne faut surtout pas faire un extends BaseMod. Perdez cette habitude.
ForgeModLoader détecte déjà notre mod grâce à l’interface @Mod, et les void d’init seront détectés grâce aux events que nous avons vu plus haut.
Donc dans notre classe principale nous allons ajouter les trois méthodes importantes de FML, j’expliquerai plus bas à quoi elles servent. Voici le rendu final :package tutoriel.common; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.Mod.Instance; import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.network.NetworkMod; @Mod(modid = "ModTutoriel", name = "Mod Tutoriel", version = "1.0.0", acceptedMinecraftVersions = "[1.6.2,)") @NetworkMod(clientSideRequired = true, serverSideRequired = false) public class ModTutoriel { @Instance("ModTutoriel") public static ModTutoriel instance; @EventHandler public void PreInit(FMLPreInitializationEvent event) { } @EventHandler public void Init(FMLInitializationEvent event) { } @EventHandler public void PostInit(FMLPostInitializationEvent event) { } }
Il en existe d’autres, mais elles sont moins utilisées.
Vous pouvez voir en passant que j’ai ajouté l’instance de mon mod, elle ne vous sera pas forcément utile, en revanche vous l’utiliserez si vous créez des mobs dans une classe différente, ou des packets.
Dans le PreInit, nous allons placer les configurations, compléter et enregistrer nos blocs et items, et placer les achievements.
Dans le Init, nous allons enregistrer les tileEntity, les Entity, les rendu, etc…
Dans le PostInit, nous allons faire les dernières finissions, comme par exemple les enregistrements de langages ou de recettes.
(voir plus bas pour un exemple de où vont être chaque chose)Les proxys
Les proxys vont vous être utile pour toutes les méthodes à faire sur un seul side. Par exemple, si dans ma classe principale je mets une méthode qui n’existe qu’en client (par exemple quelques choses qui gèrent les rendus), le serveur va crasher au lancement avec une erreur de “NoClassDefFound”. Afin d’éviter ces problèmes, on utilise les proxys.
Dans votre classe principale, en dessous de
public class <nom de la classe> {
ajoutez ceci :@SidedProxy(clientSide = "tutoriel.proxy.TutoClientProxy", serverSide = "tutoriel.proxy.TutoCommonProxy") public static TutoCommonProxy proxy;
clientSide est le chemin de ma classe TutoClientProxy, et serverSide le chemin de ma classe TutoCommonProxy. Dans mon cas j’ai placé mes proxys dans le package tutoriel.proxy, mais vous pouvez le placer dans deux packages différents si vous le voulez, à chacun(e) sa façon de s’organiser :).
Maintenant allez dans votre classe ClientProxy, et faites un extends CommonProxy. Tous les void que vous placerez dans votre client proxy devrons être override. Au début, nous allons principalement utiliser les proxys pour faire quelque chose uniquement en solo, mais quand votre mod sera plus complexe, ils pourront ressembler à ça :
https://github.com/BuildCraft/BuildCraft/blob/master/common/buildcraft/core/proxy/CoreProxy.java
https://github.com/BuildCraft/BuildCraft/blob/master/common/buildcraft/core/proxy/CoreProxyClient.javaVoici le rendu final avec un exemple :
package tutoriel.common; import tutoriel.proxy.TutoCommonProxy; import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.Mod.EventHandler; import cpw.mods.fml.common.Mod.Instance; import cpw.mods.fml.common.SidedProxy; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.network.NetworkMod; @Mod(modid = "ModTutoriel", name = "Mod Tutoriel", version = "1.0.0", acceptedMinecraftVersions = "[1.6.2,)") @NetworkMod(clientSideRequired = true, serverSideRequired = false) public class ModTutoriel { @SidedProxy(clientSide = "tutoriel.proxy.TutoClientProxy", serverSide = "tutoriel.proxy.TutoCommonProxy") public static TutoCommonProxy proxy; @Instance("ModTutoriel") public static ModTutoriel instance; @EventHandler public void PreInit(FMLPreInitializationEvent event) { // Configuration // Blocks // Items // Achievements } @EventHandler public void Init(FMLInitializationEvent event) { // Registry // Mobs // Render< proxy.registerRender(); // NetWork // Recipe } @EventHandler public void PostInit(FMLPostInitializationEvent event) { // Intégration avec les autres mods } }
Dans ma méthode Init, j’ai mis proxy.registerRender, donc au chargement du mod le jeu va faire ce qu’il trouve dans le void registerRender qui se trouve dans mes proxy.
J’ai également ajouté en commentaire là où je vais mettre chaque chose .package tutoriel.proxy; public class TutoCommonProxy { public void registerRender() { // rien ici, les rendus ne se font que sur le client } }
package tutoriel.proxy; import net.minecraftforge.client.MinecraftForgeClient; public class TutoClientProxy extends TutoCommonProxy { @Override public void registerRender() { // ici mes futur client registry } }
Voilà, les choses ennuyeuses sont faites, vous allez pouvoir commencer vos premiers blocs et items.
-
Pour ceux qui n’ont pas envie de tout relire, voici la liste des changements entre ce tutoriel pour la 1.6.2 et l’ancien pour la 1.5.2 :
- @Init, @PreInit, @PostInit et tout les autres annotations sont obsolète, il faut maintenant utiliser @EventHandler
- J’ai enlevé les informations sur ce qui est obsolète (modExclusionList et bukkitPlugin)
- J’ai ajouté une information à propos du versionBounds dans @NetworkMod
Bref, pas de grand changement ici, il y a juste les @EventHandler à mettre.
-
Bonjour
D’abord merci pour ces tutos (en français ! )
je débute en java et en modding donc ne soyez pas étonné de la simplicité de mes questions :))
Dans la classe pincipale du tuto “ModTutoriel” sous @EventHandler les 3 méthodes suivantes sont utilisées :PreInit() Init() PostInit() ; tu parle de load à un moment : “Dans ma méthode load, j’ai mis proxy.registerRender…” .
Après recherche (Forge) j’ai vu 3 autres méthodes qui apparemment font la même chose , soit dans l’ordre : preInit() load() postInit() , (j’ai testé les 2 ensembles de méthodes dans le même code pas de différence apparemment).Qu’elle est la différence donc entre ces 2 ensembles MAJ d’anciennes méthodes? En gros lesquelles doit ont utiliser ?
-
Le nom de la méthode ne change rien, il faut juste que tu es l’event en argument et le @EventHandler au dessus.
-
J’ai modifier en “Dans ma méthode Init, j’ai mis proxy.registerRender…”, c’est plus compréhensible comme ça. (j’avais reprit de l’ancien tutoriel)
Comme kevin_68 l’a dit, le nom de la méthode ne change absolument rien, c’est l’annotation @EventHandler et l’argument FML(Post/Pre)InitializationEvent qui fait que la méthode va être chargé par FML. Tu peux mettre :
[code_java]@EventHandler
nimporteQuelNomDeMethode(FMLInitializationEvent event)
{}[/code_java]
Ça reviendra au même. -
Merci beaucoup pour cette réponse rapide et précise.
Obnubilé par le " @EventHandler " je n’avais pas capté que c’était nous qui créions ces méthodes; ces annotations " @quelquechose " ne me sont pas encore
vraiment compréhensibles.
Je sais que se sont des tags javadoc ,mais je pensais que cela ne concernait que le domaine des commentaires ,de la documentation du programme.
Apparemment cela va plus loin ; si l’on omet le " @EventHandler " àMarchePu ! Donc cela a une action sur : l’exécution du programme, la compilation du code ?
Je sais que cela relève de la connaissance de la programmation java , mais si vous aviez un début de réponse ou une piste à suivre pour cette utilisation spécifique de la javadoc ,je suis preneur ; les @quelquechose sont très utilisés dans le code minecraft.J’ai vu dans ‘cpw.mods.fml.common.Mod’ cette annotation :
- // Mark this method for receiving an {@link FMLEvent} (in this case, it’s the {@link FMLPreInitializationEvent})
- {@literal @}EventHandler public void preInit(FMLPreInitializationEvent event){}
J’en déduit(par recoupement) que ça crée un lien avec les ’ FMLEvent’ qu’on l’utilise comme ça : @EventHandler
public void preInit(FMLPreInitializationEvent event){}
Mais au niveau java j’aimerai trouver de la doc sur la syntaxe et le mécanisme de ce genre d’annotation; en faite je manque de mot clef pour faire une recherche sur internet . En gros comment s’appelle ce genre de technique en java ?
Ceci juste au cas ou quelqu’un aurait quelques éléments de réponse .
Et encore un grand merci pour les réponses à ma précédente question.
-
Tout ce que je peux te dire c’est qu’un @quelquehose est une annotation (ou @interface) et que l’annotation @EventHandler est elle-même sous deux autres annotations qui sont: @Retention(RetentionPolicy.RUNTIME) et @Target(ElementType.METHOD). Pour comprendre à quoi elles servent regarde ça:
http://adiguba.developpez.com/tutoriels/java/tiger/annotations/ -
Merci kevin_68 pour ta réponse super rapide j’ai de quoi m’occuper un moment
-
Pourquoi dans:
@Mod(modid = “ModTutoriel”, name = “Mod Tutoriel”, version = “1.0.0”, acceptedMinecraftVersions = “[1.6.1,)”)
acceptedMinecraftVersions est inférieur ou égal à 1.6.1 alors que le tuto est en 1.6.2?Sa ne devrait pas être:
@Mod(modid = “ModTutoriel”, name = “Mod Tutoriel”, version = “1.0.0”, acceptedMinecraftVersions = “[1.6.2,)”)ou encore:
@Mod(modid = “ModTutoriel”, name = “Mod Tutoriel”, version = “1.0.0”, acceptedMinecraftVersions = “[1.6.1]”)
vu que dans forge 1.6.2 on a remplacé - @Init, @PreInit, @PostInit par @EventHandler
les vieilles versions de forge (1.6.1 ou 1.5.2…) ne sont donc pas logiquement capable de comprendre un mod fait pour la 1.6.2! -
Le tuto a été rédigé en 1.6.1 la première fois et robin a oublié de changer ça.
-
[1.6.1,) = 1.6.1 et supérieurs pas inférieurs, relis la doc sur “maven version range”
Et oui, je pense que je vais remplacer par 1.6.2, car un mod 1.6.2 n’est pas compatible 1.6.1 si tu utilise la classe ResourceLocation (due à changement de package)
-
Bonjour j’ai un petit problème assez conséquent le problème est que je n’est pas le package cpw.mods.fml.common.Mod pourtant l’installation était un succès.
-
Il te manque juste ce package ou tout les packages en cpw.mods.fml ?
Vérifie aussi que tu as bien les packages en net.minecraftforge -
Il ne me manque que celui la il me semble.
:::
cpw.mods.fml.client
cpw.mods.fml.client.modloader
cpw.mods.fml.client.registry
cpw.mods.fml.common
cpw.mods.fml.common.asm
cpw.mods.fml.common.asm.transformers
cpw.mods.fml.common.asm.transformers.deobf
cpw.mods.fml.common.discovery
cpw.mods.fml.common.discovery.asm
cpw.mods.fml.common.event
cpw.mods.fml.common.functions
cpw.mods.fml.common.launcher
cpw.mods.fml.common.modloader
cpw.mods.fml.common.network
cpw.mods.fml.common.patcher
cpw.mods.fml.common.registry
cpw.mods.fml.common.toposort
cpw.mods.fml.common.versioning
cpw.mods.fml.relauncher
cpw.mods.fml.repackage.com.nothome.delta
cpw.mods.fml.server
ibxm
net.minecraft.block
net.minecraft.block.material
net.minecraft.client
net.minecraft.client.audio
net.minecraft.client.entity
net.minecraft.client.gui
net.minecraft.client.gui.achievement
net.minecraft.client.gui.inventory
net.minecraft.client.gui.mco
net.minecraft.client.main
net.minecraft.client.mco
net.minecraft.client.model
net.minecraft.client.multiplayer
net.minecraft.client.particle
net.minecraft.client.renderer
net.minecraft.client.renderer.culling
net.minecraft.client.renderer.entity
net.minecraft.client.renderer.texture
net.minecraft.client.renderer.tileentity
net.minecraft.client.resources
net.minecraft.client.resources.data
net.minecraft.client.settings
net.minecraft.client.stats
net.minecraft.command
net.minecraft.crash
net.minecraft.creativetab
net.minecraft.dispenser
net.minecraft.enchantment
net.minecraft.entity
net.minecraft.entity.ai
net.minecraft.entity.ai.attributes
net.minecraft.entity.boss
net.minecraft.entity.effect
net.minecraft.entity.item
net.minecraft.entity.monster
net.minecraft.entity.passive
net.minecraft.entity.player
net.minecraft.entity.projectile
net.minecraft.inventory
net.minecraft.item
net.minecraft.item.crafting
net.minecraft.logging
net.minecraft.nbt
net.minecraft.network
net.minecraft.network.packet
net.minecraft.network.rcon
net.minecraft.pathfinding
net.minecraft.potion
net.minecraft.profiler
net.minecraft.scoreboard
net.minecraft.server
net.minecraft.server.dedicated
net.minecraft.server.gui
net.minecraft.server.integrated
net.minecraft.server.management
net.minecraft.src
net.minecraft.stats
net.minecraft.tileentity
net.minecraft.util
net.minecraft.village
net.minecraft.world
net.minecraft.world.biome
net.minecraft.world.chunk
net.minecraft.world.chunk.storage
net.minecraft.world.demo
net.minecraft.world.gen
net.minecraft.world.gen.feature
net.minecraft.world.gen.layer
net.minecraft.world.gen.structure
net.minecraft.world.storage
net.minecraftforge.classloading
net.minecraftforge.client
net.minecraftforge.client.event
net.minecraftforge.client.event.sound
net.minecraftforge.client.model
net.minecraftforge.client.model.obj
net.minecraftforge.client.model.techne
net.minecraftforge.common
net.minecraftforge.common.network
net.minecraftforge.common.network.packet
net.minecraftforge.event
net.minecraftforge.event.brewing
net.minecraftforge.event.entity
net.minecraftforge.event.entity.item
net.minecraftforge.event.entity.living
net.minecraftforge.event.entity.minecart
net.minecraftforge.event.entity.player
net.minecraftforge.event.terraingen
net.minecraftforge.event.world
net.minecraftforge.fluids
net.minecraftforge.liquids
net.minecraftforge.oredict
net.minecraftforge.transformers
paulscode.sound.codecs:::
-
un Spoiler aurai étai bien …
Merci
-
Étrange, supprime le dossier forge/mcp et relance l’installation de forge.
Si le problème persiste, envoie-moi le fichier forge\mcp\logs\mcp.log -
Je t’ai envoyer un mp
-
J’ai exactement le même problème que blackswan Si le problème a était trouver entre temps merci de m’en faire part ^^
-
Prend la dernière version de forge, et réinstalle ton JDK ainsi que ton JRE
-
A vrai dire c’est exactement ce que je viens de faire, car je commence dans le modding ^^’ (Je vais quand même le faire au cas ou :P)
–—
Je vien de le refaire et toujours pas de cpw.mods.fml.common.Mod Est-ce que le ‘‘Mod’’ en question serais dans cpw.mods.fml.common MAIS en l’ouvrant ?