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 package. En fait c’est FML qui réorganise les sources de minecraft afin d’être mieux trié.
Par ailleurs vous avez aussi pu constater qu’il n’y a pas deux projets (un pour le serveur et un pour le solo), il y a un seul projet, 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, nous verrons ça plus en détail).
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
La 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 de nombreuses méthodes se trouvant 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)
Normallement @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 à 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 qu’il 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-ci va s’afficher 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 important, 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 pourra 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 metadata de bloc ou item, 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 bukkitPlugin() À l’origine créé pour le projet ForgeBukkit, actuellement inutile.
- String modExclusionList() Permet d’exclure un ou plusieurs mods, si il est détecté, le jeu se stoppera avec une erreur. Placer un + devant l’id du mod pour l’exclure. Vous pouvez utiliser -* pour interdire tout les mods, et continuer la liste avec des plus pour ajouter un mod autorisé. Par exemple: -*+f+IC2+IronChest, dans ce cas, mon mods ne fonctionnera avec aucun autre mod à part l’environnement de forge (forge & FML & mcp, défini par le +f), industrialcraft (+IC2) et Ironchest (+IronChest)
- 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’installer, 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 à des informations dessus, je prends.
- String modLanguage() par défaut java, apparemment on peut aussi créer un mod en scala O_o (The language the mod is authored in. This will be used to control certain libraries being downloaded. Valid values are currently “java”, “scala”)
- String asmHookClass() On l’utilise dans les core mods pour faire de la réflexion, mais une fois de plus je ne sais pas comment le faire fonctionner, je ne m’y suis pas encore intéressé.
Bien, maintenant cette partie expliquée, vous avez pu constater qu’il y a de nombreuses autres interfaces. Nous allons bientôt les utiliser.
Allez voir la classe FMLModContainer (dans le package cpw.mods.fml.common), et regardez la BiMap “modAnnotationTypes”
On peut constater que toutes ces annotations sont liés à un event. En effet, il y a un lien entre les deux. Nous allons le voir juste après, car avant nous allons regardez l’annotation @NetworkMod
Dans la classe principale en dessous de @Mod, ajouter @NetworkMod.
Pour l’instant, nous allons juste utiliser les deux boolean 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 ont 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 si ce dernier a 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 importantes méthodes 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.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.PostInit;
import cpw.mods.fml.common.Mod.PreInit;
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")
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class ModTutoriel
{
@Instance("ModTutoriel")
public static ModTutoriel instance;
@PreInit
public void preload(FMLPreInitializationEvent event)
{
}
@Init
public void load(FMLInitializationEvent event)
{
}
@PostInit
public void modloaded(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, il ne vous sera pas forcément utile, en revanche vous l’utilisez si vous créez des mobs dans une classe différente, ou des packets.
Dans le PreInit, nous allons placer les configurations, compléter nos blocs et items, et placer les achievements.
Dans le Init, nous allons enregistrer nos blocs, 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ù va être chaque chose)
Les proxy
Les proxy vont vous être utiles 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 proxy.
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 proxy 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. 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.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.PostInit;
import cpw.mods.fml.common.Mod.PreInit;
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.5.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;
@PreInit
public void preload(FMLPreInitializationEvent event)
{
// Configuration
// Blocks
// Items
// Achievements
}
@Init
public void load(FMLInitializationEvent event)
{
// Registry
// Mobs
// Render
proxy.registerRender();
// NetWork
}
@PostInit
public void modloaded(FMLPostInitializationEvent event)
{
// Language
// Recipe
}
}
Dans ma méthode load, j’ai mis proxy.registerRender, donc au chargement du mod, le jeu va faire ce qu’il se trouve dans le void registerRender qui se trouve dans mes proxy.
J’ai également ajouté en commentaire où je vais mettre chaque chose
package tutoriel.proxy;
public class TutoCommonProxy
{
public void registerRender()
{
// rien ici, les rendu se fond 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.