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 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.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 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 @NetworkModDans 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 chosepackage 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.
-
Super partie de tutoriel !!! J’adore et c’est super bien expliqué
J’espère une prochaine partie rapidement ^^Ps :
- Je n’ai pas bien compris la dernière partie “Les proxy”
- J’aime modder
-
C’est normal que tu n’as pas encore compris la parti proxy, elle n’est pas encore faite ^^
Le Todo est utilisé pour chose à faire, je me suis mis ça pour me retrouver plus tard -
Génial comme début de tuto. Mais il est pour la 1.5.2 non ? ce n´est pas écrit.
-
Il n’est pas nécessaire d’écrire pour quel version est ce tuto, car le système n’a pas vraiment changé entre temps… ^^
-
Oh, on sais jamais je parle de vécu. bon pas avec minecraft mais ça évite des regequits inutiles xd !
-
Super tuto, même si tu ne m’apprends rien, sinon
regequits
Je ne connais pas
-
J’attends avec impatience la prochaine partie de ce MAGNIFIQUE tutoriel
-
Donc un proxy pour le client, un autre pour le serveur.Normal
Mais , dans l’exemple tu mets registerRender() dans les 2 proxy,pourquoi?Si seul le coté client l’utilise.
Et les taches répétitives , géré par les 2 proxy ( si ça existe ) ça ce met en doublons?ou dans une autre class?pour info : il manque un petit mots au début de la partie sur les proxy (placer)
-
@Bialeck
Alors la ça me pose une sèche ‘-’.
je ne serai pas te répondre, mais ça doit être simple, attendons la réponse de robin4002.
Mais ça serai intéressent à savoir pour l’avenir. -
@‘Bialeck’:
pour info : il manque un petit mots au début de la partie sur les proxy (placer)
Ha en effet, corrigé.
Dans ta classe principale, tu as ça :
proxy.registerRender();
Cela revient à faire TutoCommonProxy.registerRender(); la seul différence est que nous avons instancier le common proxy avec ça : public static TutoCommonProxy proxy;
Et donc, comme c’est le commonproxy qui est instancier, il faut avoir aussi les méthodes dans le common proxy, et d’ailleurs il ne fait pas oublier le @Override, sinon le clientProxy ne suit pas la méthode.Pour les taches répétitives, tu les mets directement dans la classe principale
-
Bonjour.
Je commence a suivre vos tuto qui sont super. Juste 2 petite remarques :
Dans mon cas je vais l’appeler modtutoriel.common
Vous le nommez dans le class “package tutoriel.common;”. Cela ma perturbé car je suis vraiment novice la dedans le “mod” à été enlever sciemment ? Si oui, il faut corriger votre phrase
Ensuite, pour le package des proxy, je voulais seulement savoir si vous l’avez mit dans le package tutoriel.common ou simplement dans le dossier src ? Est-ce que cela à une importance ? Est-ce mieux niveau organisation du travail de le mettre dans le package principale de notre projet ?
Désolé pour toutes ces questions mineur mais je débute vraiment et c’est important pour moi de savoir ces choses.
Merci par avance.
-
Salut Sholla.
Pour ma par le dossier proxy je le mets juste a coté du dossier common, après il suffit juste de l’importer dans ta class principale:
import "package_de_ton_mod".proxy."le non du common proxy"
Et il est inutile d’importer “ton clien proxy” vu que c’est “ton common proxy” qui le support.
En espèrent t’avoir aidé pour ce point la, après ce que tu as dit un peu plus haut dans ta phrase, je suis pas sûr de comprendre, tu peux réexpliquer stp ? merci ^^.
-
@‘Sholla’:
Dans mon cas je vais l’appeler modtutoriel.common
Vous le nommez dans le class “package tutoriel.common;”. Cela ma perturbé car je suis vraiment novice la dedans le “mod” à été enlever sciemment ? Si oui, il faut corriger votre phrase
En effet, à nouveau une erreur d’inattention, merci de me l’avoir fait remarquer, c’est corrigé.
@‘Sholla’:
Ensuite, pour le package des proxy, je voulais seulement savoir si vous l’avez mit dans le package tutoriel.common ou simplement dans le dossier src ? Est-ce que cela à une importance ? Est-ce mieux niveau organisation du travail de le mettre dans le package principale de notre projet ?
Pour les proxy, soit dans le même package que la classe principale, soit dans un package à part, mais pas dans le dossier de source src, sinon ça va le mettre dans le “default package”
-
Mais de rien. D’ailleurs, vous avez fait la même erreur avec les noms des proxy
ClientProxy et CommonProxy => code java : TutoClientProxy et TutoCommonProxy
Et merci pour l’info de l’organisation des packages.
-
Je me sens inutile d’un coup ;(
-
Non, pour les proxy c’est voulu, tout les mods on un CommonProxy et un ClientProxy, que tu nomme différement en fonction du mods pour ne pas avoir 50 proxy du même nom.
-
Ah ok. Ben du coup, c’est l’inverse qui faut que vous modifiez Ce qui donnerais normalement “clientSide est le chemin de ma classe TutoClientProxy, et serverSide le chemin de ma classe TutoCommonProxy.” si je ne me trompe pas.
-
Oui, je vais modifier, ça sera plus clair comme ça.
-
Non, pour les proxy c’est voulu, tout les mods on un CommonProxy et un ClientProxy, que tu nomme différement en fonction du mods pour ne pas avoir 50 proxy du même nom.
Tout les mods n’ont pas de proxy, si tu ajoute un mob, il va avoir le model biped (celui par defaut), ça fonctionne sans proxy.