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.common
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 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.java
Voici 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() |
| { |
| |
| } |
| } |
| package tutoriel.proxy; |
| |
| import net.minecraftforge.client.MinecraftForgeClient; |
| |
| public class TutoClientProxy extends TutoCommonProxy |
| { |
| @Override |
| public void registerRender() |
| { |
| |
| } |
| } |
Voir sur github
Voilà, les choses ennuyeuses sont faites, vous allez pouvoir commencer vos premiers blocs et items.