Content Builder
Cree des items, des blocs, des recettes et des entites Minecraft en quelques lignes de code — sans ecrire de sous-classes ni de boilerplate.
Introduction
Le module Content Builder te permet de creer des items, des blocs et des entites Minecraft sans avoir a ecrire de classes Java complexes. Tout se fait via une Fluent API — tu chaines des methodes comme une phrase pour decrire ce que tu veux.
Normalement, creer un item dans Minecraft Forge demande d'ecrire une sous-classe d'Item,
de l'enregistrer dans l'event RegistryEvent, d'enregistrer le modele dans
ModelRegistryEvent... C'est beaucoup de code repetitif. EriAPI s'occupe de tout ca pour toi.
Ce que tu peux faire avec ce module
- Creer des items simples (gemmes, ressources, consommables)
- Creer des items alimentaires avec effets de potion
- Creer des outils (epee, pioche, hache...) avec stats personnalisees
- Creer des armures avec protection et solidite
- Creer des blocs avec materiau, durete, son, drops
- Definir des recettes avec forme, sans forme, ou au four
- Ajouter des comportements personnalises via des callbacks
Quand tu appelles .register() a la fin de ton builder, EriAPI se charge d'enregistrer
l'item ou le bloc dans les events Forge au bon moment. Tu n'as rien d'autre a faire.
// Un item simple
EriItem.create("monmod", "rubis")
.maxStackSize(16)
.rarity(EnumRarity.RARE)
.tooltip("&7Une gemme precieuse")
.register();
// Un bloc
EriBlock.create("monmod", "minerai_rubis")
.material(Material.ROCK)
.hardness(3.0f)
.drops(Items.DIAMOND, 1, 3)
.register();
// Une recette
EriRecipe.shaped("monmod", "bloc_rubis")
.pattern("RRR", "RRR", "RRR")
.key('R', monItemRubis)
.result(monBlocRubis, 1)
.register();
ContentRegistry
ContentRegistry est le moteur interne qui gere l'enregistrement de tous tes items et blocs
aupres de Forge. Tu n'interagis presque jamais directement avec lui — il est utilise automatiquement
en coulisse quand tu appelles .register().
Gestionnaire central qui ecoute les events Forge (RegistryEvent.Register<Item>,
RegistryEvent.Register<Block>, ModelRegistryEvent) et enregistre
automatiquement tout ce qui a ete declare via les builders.
-
Statiquevoid register(Object mod)Enregistre le
ContentRegistrycomme listener d'events Forge pour ton mod. A appeler une seule fois dans la methode annotee@Mod.EventHandlerde ta classe principale.
import fr.eri.eriapi.content.ContentRegistry;
@Mod(modid = "monmod", version = "1.0")
public class MonMod {
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
// Enregistre ContentRegistry pour qu'il capture les events Forge
ContentRegistry.register(this);
// Declare maintenant tes items et blocs
MonItems.init();
MonBlocs.init();
}
}
Appelle ContentRegistry.register(this) avant de declarer tes items et blocs.
Cela garantit que Forge recevra bien les registrations au bon moment du cycle de chargement.
Contextes d'action
Quand tu definis un comportement sur un item ou un bloc (via onRightClick, onBreak, etc.),
EriAPI te passe un objet contexte qui contient toutes les informations sur ce qui s'est passe.
Passe aux callbacks d'items (onRightClick, onLeftClick).
-
GetterEntityPlayer getPlayer()Le joueur qui a clique sur l'item.
-
GetterWorld getWorld()Le monde dans lequel l'action s'est produite.
-
GetterItemStack getItemStack()L'ItemStack de l'item utilise (avec son NBT, sa durabilite, etc.).
-
GetterEnumHand getHand()La main utilisee (
MAIN_HANDouOFF_HAND).
Passe aux callbacks de blocs (onBreak, onPlace, onWalk).
-
GetterEntityPlayer getPlayer()Le joueur qui a interagi avec le bloc (peut etre
nullsi casse par une machine). -
GetterWorld getWorld()Le monde ou se trouve le bloc.
-
GetterBlockPos getPos()La position (coordonnees X, Y, Z) du bloc dans le monde.
-
GetterIBlockState getBlockState()L'etat du bloc au moment de l'action (utile pour les blocs avec variants).
EriItem.create("monmod", "soin_rapide")
.onRightClick(ctx -> {
EntityPlayer joueur = ctx.getPlayer();
// Soigne le joueur de 4 points de vie (2 coeurs)
joueur.heal(4f);
// Envoie un message dans le chat du joueur
joueur.sendMessage(new TextComponentString("Tu as ete soigne !"));
// Consomme 1 item dans la main
ctx.getItemStack().shrink(1);
})
.register();
EriBlock.create("monmod", "bloc_piege")
.onWalk(ctx -> {
EntityPlayer joueur = ctx.getPlayer();
if (joueur != null) {
// Ralentit le joueur qui marche dessus
joueur.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 60, 2));
}
})
.register();
EriItem
EriItem est le point d'entree pour creer n'importe quel item. Tu commences toujours
par EriItem.create("modid", "nom"), tu chaines les methodes pour configurer l'item,
puis tu termines par .register().
Builder fluent pour creer et enregistrer des items Minecraft sans sous-classe.
-
StatiqueEriItem create(String modid, String name)Cree un nouveau builder d'item.
modidest l'identifiant de ton mod,nameest le nom de l'item (ex:"rubis"). Ce nom sera utilise comme registry name et pour trouver la texture dansassets/modid/textures/items/name.png. -
FluentEriItem maxStackSize(int size)Nombre maximum d'items empilables dans un slot d'inventaire. Par defaut : 64.
-
FluentEriItem maxDamage(int damage)Durabilite maximale de l'item. Mettre une valeur > 0 rend l'item damageable (comme un outil). Par defaut : 0 (non damageable).
-
FluentEriItem rarity(EnumRarity rarity)Rarete de l'item, qui affecte la couleur de son nom dans les tooltips. Valeurs :
COMMON(blanc),UNCOMMON(jaune),RARE(cyan),EPIC(violet). -
FluentEriItem creativeTab(CreativeTabs tab)L'onglet du mode creatif ou apparait l'item. Exemples :
CreativeTabs.MATERIALS,CreativeTabs.TOOLS,CreativeTabs.COMBAT. -
FluentEriItem glowing(boolean glowing)Si
true, l'item affiche l'effet d'enchantement brillant (comme les items enchantes), meme sans enchantement reel. -
FluentEriItem tooltip(String line)Ajoute une ligne de tooltip (le texte affiché quand le joueur survole l'item). Tu peux appeler cette methode plusieurs fois pour plusieurs lignes. Supporte les codes couleur Minecraft (
&7,&c, etc.). -
FluentEriItem onRightClick(Consumer<ItemActionContext> action)Callback execute quand le joueur fait un clic droit avec l'item en main (dans l'air ou sur un bloc). Recoit un
ItemActionContext. -
FluentEriItem onLeftClick(Consumer<ItemActionContext> action)Callback execute quand le joueur attaque (clic gauche) avec l'item en main.
-
Sous-builderFoodBuilder food()
-
Sous-builderToolBuilder tool()
-
Sous-builderArmorBuilder armor()
-
FluentEriItem animatedModel(String modelId)Configure l'item pour utiliser un modele 3D Blockbench anime en main et en inventaire. Le rendu est delegue a un
TileEntityItemStackRendererinterne.modelIdest au format"modid:item/nom"(ex:"eriniumfaction:item/faction_sword"). Le fichier JSON Blockbench doit etre dansassets/{modid}/models/item/{nom}.json. -
TerminalItem register()Finalise et enregistre l'item aupres de Forge. Retourne l'instance
Itemcree, que tu peux stocker dans une variable pour l'utiliser dans des recettes.
import fr.eri.eriapi.content.EriItem;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.EnumRarity;
import net.minecraft.item.Item;
public class MonItems {
public static Item RUBIS;
public static Item EPEE_RUBIS;
public static void init() {
RUBIS = EriItem.create("monmod", "rubis")
.maxStackSize(16)
.rarity(EnumRarity.RARE)
.glowing(true)
.tooltip("&7Une gemme precieuse")
.tooltip("&cTres rare")
.onRightClick(ctx -> ctx.getPlayer().heal(2f))
.creativeTab(CreativeTabs.MATERIALS)
.register();
}
}
Item simple — modele et texture
Pour un item classique en 2D, tu dois fournir deux fichiers dans
src/main/resources/assets/monmod/ : le modele JSON et la texture PNG. EriAPI enregistre
la resource location du modele via ModelLoader.setCustomModelResourceLocation(), mais les
fichiers JSON (modeles et blockstates) doivent etre fournis par le developpeur dans
src/main/resources/. Ces fichiers sont inclus dans le JAR du mod a la compilation.
EriItem.create("monmod", "rubis")
.maxStackSize(64)
.register();
// -> Texture attendue : assets/monmod/textures/items/rubis.png (16x16 ou 64x64)
// -> Modele JSON attendu : assets/monmod/models/item/rubis.json
Fichier modele a creer manuellement dans src/main/resources/assets/monmod/models/item/rubis.json :
{
"parent": "item/generated",
"textures": {
"layer0": "monmod:items/rubis"
}
}
Pour un item qui doit etre tenu correctement en main (style outil), utilise
"parent": "item/handheld" a la place de "item/generated" dans le JSON
du modele.
Item 3D anime — animatedModel() + AnimatedItemController
La methode .animatedModel(String modelId) permet d'afficher l'item avec un
modele Blockbench 3D (type Java Block/Item) au lieu d'une simple texture 2D.
Le rendu passe par un TileEntityItemStackRenderer interne et les animations se jouent
via AnimatedItemController cote client.
Fichiers requis
assets/modid/models/item/nom.json— modele Blockbench exporte (format Java Block/Item)assets/modid/animations/item/nom.erianim.json— fichier d'animations (optionnel si l'item n'anime pas)- Les textures referencees dans le JSON Blockbench, placees a l'emplacement attendu
import fr.eri.eriapi.anim.AnimatedItemController;
import fr.eri.eriapi.content.EriItem;
import net.minecraft.item.EnumRarity;
// Declaration
EriItem.create("monmod", "epee_animee")
.maxStackSize(1)
.rarity(EnumRarity.EPIC)
.animatedModel("monmod:item/epee_animee") // Modele Blockbench 3D
.onRightClick(ctx -> {
if (ctx.world.isRemote) {
// Joue l'animation "use" du fichier monmod:item/epee_animee.erianim.json
AnimatedItemController.play("monmod:item/epee_animee", "use");
}
})
.register();
// Jouer une animation (animFileId = modelId par defaut)
AnimatedItemController.play("monmod:item/epee_animee", "idle");
// Jouer avec un animFileId explicite (2e parametre)
AnimatedItemController.play("monmod:item/epee_animee", "monmod:item/epee_anims", "swing");
// Arreter l'animation en cours
AnimatedItemController.stop("monmod:item/epee_animee");
// Verifier si une animation est en cours
boolean enCours = AnimatedItemController.isPlaying("monmod:item/epee_animee");
animFileIdLe 2e parametre optionnel de play() resout vers
assets/modid/animations/path.erianim.json. S'il est omis, EriAPI utilise
modelId comme animFileId. L'etat de lecture est partage par
modelId : tous les items rendus avec le meme modele jouent la meme animation
en meme temps.
FoodBuilder
FoodBuilder est un sous-builder accessible depuis EriItem.food().
Il configure les proprietes alimentaires d'un item — combien il restaure de faim,
quel effet de potion il donne, s'il peut etre mange meme quand la faim est pleine, etc.
Une fois configure, appelle .done() pour revenir au builder principal EriItem.
Configure les proprietes alimentaires d'un item. Retourne via .done().
-
FluentFoodBuilder hunger(int points)Nombre de demi-jambons restaures (1 point = une demi-cuisse de poulet dans la barre de faim). Un steak vanilla restaure 8 points.
-
FluentFoodBuilder saturation(float saturation)Modificateur de saturation. Multiplie les points de faim pour calculer la saturation reelle. Une valeur de
1.2fdonne une saturation elevee (comme la pomme en or). -
FluentFoodBuilder alwaysEdible(boolean always)Si
true, l'item peut etre mange meme quand la barre de faim est pleine (comme la pomme en or). -
FluentFoodBuilder effect(PotionEffect effect, float probability)Ajoute un effet de potion applique en mangeant.
probabilityest la probabilite d'application (entre0.0fet1.0f;1.0f= toujours). Peut etre appele plusieurs fois. -
RetourEriItem done()Termine la configuration alimentaire et retourne au builder
EriItemparent.
import fr.eri.eriapi.content.EriItem;
import net.minecraft.init.MobEffects;
import net.minecraft.potion.PotionEffect;
Item POMME_MAGIQUE = EriItem.create("monmod", "pomme_magique")
.food()
.hunger(6)
.saturation(1.2f)
.alwaysEdible(true)
.effect(new PotionEffect(MobEffects.REGENERATION, 100, 1), 1.0f)
.effect(new PotionEffect(MobEffects.ABSORPTION, 200, 0), 0.5f)
.done()
.creativeTab(CreativeTabs.FOOD)
.register();
ToolBuilder
ToolBuilder est un sous-builder accessible depuis EriItem.tool().
Il configure le type d'outil (epee, pioche, hache, pelle, houe), ses degats, sa vitesse d'attaque
et sa durabilite. Appelle .done() pour revenir a l'EriItem.
Configure les proprietes d'outil d'un item. Retourne via .done().
-
FluentToolBuilder type(ToolType type)Type d'outil. Valeurs de l'enum
ToolType:SWORD,PICKAXE,AXE,SHOVEL,HOE. -
FluentToolBuilder damage(float damage)Degats de base infliges par l'outil (en demi-coeurs). Une epee en fer fait 6 degats (3 coeurs).
-
FluentToolBuilder durability(int durability)Durabilite de l'outil. Une epee en diamant a 1561 utilisations.
-
FluentToolBuilder speed(float speed)Vitesse d'attaque (attacks per second). La valeur par defaut vanilla pour une epee est
1.6f. Une hache est plus lente (0.9f). -
RetourEriItem done()Termine la configuration de l'outil et retourne au builder
EriItemparent.
import fr.eri.eriapi.content.EriItem;
import fr.eri.eriapi.content.ToolType;
Item EPEE_RUBIS = EriItem.create("monmod", "epee_rubis")
.tool()
.type(ToolType.SWORD)
.damage(8f)
.durability(1500)
.speed(1.6f)
.done()
.rarity(EnumRarity.RARE)
.tooltip("&cEpee en rubis")
.creativeTab(CreativeTabs.COMBAT)
.register();
Item PIOCHE_RUBIS = EriItem.create("monmod", "pioche_rubis")
.tool()
.type(ToolType.PICKAXE)
.damage(5f)
.durability(2000)
.speed(1.2f)
.done()
.creativeTab(CreativeTabs.TOOLS)
.register();
ArmorBuilder
ArmorBuilder est un sous-builder accessible depuis EriItem.armor().
Il configure le slot d'armure (tete, torse, jambes, pieds), sa protection,
sa solidite et le nom du materiau. Appelle .done() pour revenir a l'EriItem.
Configure les proprietes d'armure d'un item. Retourne via .done().
-
FluentArmorBuilder slot(ArmorSlot slot)Slot ou l'armure s'equipe. Valeurs de l'enum
ArmorSlot:HEAD(casque),CHEST(plastron),LEGS(jambiere),FEET(bottes). -
FluentArmorBuilder protection(int points)Points de protection de la piece. Un plastron en diamant protege de 8 points. La protection totale d'un set en diamant est de 20.
-
FluentArmorBuilder toughness(float toughness)Solidite de l'armure (reduit les degats des coups puissants). L'armure en diamant vanilla a
2.0fde solidite par piece. La plupart des materiaux ont0.0f. -
FluentArmorBuilder materialName(String name)Nom du materiau d'armure. Utilise pour trouver la texture de l'armure sur le joueur (
assets/minecraft/textures/models/armor/[name]_layer_1.png). -
RetourEriItem done()Termine la configuration de l'armure et retourne au builder
EriItemparent.
import fr.eri.eriapi.content.EriItem;
import fr.eri.eriapi.content.ArmorSlot;
public static void initArmure() {
EriItem.create("monmod", "casque_rubis")
.armor()
.slot(ArmorSlot.HEAD)
.protection(3)
.toughness(2.0f)
.materialName("rubis")
.done()
.creativeTab(CreativeTabs.COMBAT)
.register();
EriItem.create("monmod", "plastron_rubis")
.armor()
.slot(ArmorSlot.CHEST)
.protection(8)
.toughness(2.0f)
.materialName("rubis")
.done()
.creativeTab(CreativeTabs.COMBAT)
.register();
EriItem.create("monmod", "jambiere_rubis")
.armor()
.slot(ArmorSlot.LEGS)
.protection(6)
.toughness(2.0f)
.materialName("rubis")
.done()
.creativeTab(CreativeTabs.COMBAT)
.register();
EriItem.create("monmod", "bottes_rubis")
.armor()
.slot(ArmorSlot.FEET)
.protection(3)
.toughness(2.0f)
.materialName("rubis")
.done()
.creativeTab(CreativeTabs.COMBAT)
.register();
}
Place les fichiers de texture a
assets/monmod/textures/models/armor/rubis_layer_1.png (corps + bras)
et assets/monmod/textures/models/armor/rubis_layer_2.png (jambieres).
Ces textures sont au format 64x32 pixels (meme format que l'armure vanilla).
EriBlock
EriBlock est le point d'entree pour creer des blocs. Comme pour les items,
tu commences par EriBlock.create("modid", "nom"), tu configures le bloc,
et tu termines par .register().
Builder fluent pour creer et enregistrer des blocs Minecraft sans sous-classe.
-
StatiqueEriBlock create(String modid, String name)Cree un nouveau builder de bloc. La texture sera cherchee dans
assets/modid/textures/blocks/name.png. -
FluentEriBlock material(Material material)Materiau du bloc, qui determine comment il se comporte (si les entites le traversent, s'il brule, etc.). Exemples :
Material.ROCK,Material.WOOD,Material.IRON,Material.GRASS,Material.GLASS. -
FluentEriBlock hardness(float hardness)Temps de minage du bloc.
0.0f= instantane,-1.0f= indestructible. La pierre vanilla a1.5f, l'obsidienne a50.0f. -
FluentEriBlock resistance(float resistance)Resistance aux explosions. La pierre a
10.0f, l'obsidienne a6000.0f. En general, utilisehardness * 5pour une valeur coherente. -
FluentEriBlock harvestTool(String tool, int level)Outil requis pour miner le bloc et le niveau minimum.
tool:"pickaxe","axe","shovel".level: 0=bois, 1=pierre, 2=fer, 3=diamant. -
FluentEriBlock soundType(SoundType sound)Son emis quand le bloc est mine, place ou marche dessus. Exemples :
SoundType.STONE,SoundType.WOOD,SoundType.METAL,SoundType.GLASS. -
FluentEriBlock drops(Item item, int min, int max)Ce que le bloc drope quand il est mine.
minetmaxdefinissent la plage aleatoire de la quantite droppee. Si non specifie, drope le bloc lui-meme. -
FluentEriBlock creativeTab(CreativeTabs tab)L'onglet creatif ou apparait l'item-bloc.
-
FluentEriBlock onBreak(Consumer<BlockActionContext> action)Callback execute quand le bloc est mine. Recoit un
BlockActionContext. -
FluentEriBlock onPlace(Consumer<BlockActionContext> action)Callback execute quand le bloc est place par un joueur. Le callback est declenche dans
onBlockPlacedBy, ce qui garantit quectx.getPlayer()retourne toujours le joueur qui a place le bloc (jamaisnull). -
FluentEriBlock onWalk(Consumer<BlockActionContext> action)Callback execute chaque tick qu'une entite marche sur le dessus du bloc.
-
FluentEriBlock hitbox(AxisAlignedBB box)Definit une hitbox unique (selection + collision). Remplace la hitbox plein-bloc par defaut. Desactive automatiquement
isFullCubeetisOpaque. Les coordonnees sont en blocs : 1.0 = 1 bloc = 16 pixels.
Exemple :new AxisAlignedBB(0, 0, 0, 1, 0.5, 1)= demi-bloc. -
FluentEriBlock hitboxes(AxisAlignedBB... boxes)Definit plusieurs hitboxes independantes. Chaque boite est utilisee separement pour la collision. La selection (outline au survol) affiche l'union englobante de toutes les boites. Desactive automatiquement
isFullCubeetisOpaque. Recommande : max 6-8 boites pour ne pas impacter les TPS sur serveur charge. -
FluentEriBlock renderLayer(BlockRenderLayer layer)Definit la couche de rendu client du bloc. Utilise pour les blocs translucides, a trous (feuilles, plantes, verre), ou transparents. Valeurs courantes :
SOLID(defaut) — bloc opaque pleinCUTOUT— alpha binaire (plantes, grilles)CUTOUT_MIPPED— alpha binaire avec mipmaps (feuilles)TRANSLUCENT— transparence alpha continue (verre teinte, glace)
-
FluentEriBlock onEntityWalk(TriConsumer<World, BlockPos, Entity> action)Callback execute chaque tick qu'une entite marche sur le bloc (equivalent Forge
onEntityWalk). Contrairement aonWalk(Consumer<BlockActionContext>), cette version donne acces direct au monde, a la position et a l'entite, pratique pour appliquer des effets de mouvement ou des degats de zone. -
FluentEriBlock onEntityCollision(TriConsumer<World, BlockPos, Entity> action)Callback execute chaque tick qu'une entite traverse le bloc (entite a l'interieur de la hitbox). Equivalent Forge
onEntityCollision. Utile pour les plantes qui infligent des degats au passage, les blocs de ralentissement, ou les pieges a detection. -
FluentEriBlock logLike()Transforme le bloc en tronc d'arbre (
BlockRotatedPillar) avec la proprieteAXIS(X, Y, Z). Le bloc s'oriente automatiquement selon la face ou il est place (debout, couche nord/sud, couche est/ouest). Le blockstate JSON doit gerer les 3 variantsaxis=x,axis=y,axis=z. -
FluentEriBlock leavesLike(Block sapling)Transforme le bloc en feuilles d'arbre (
BlockLeaves) avec les proprietesCHECK_DECAYetDECAYABLEvanilla. Les feuilles se desintegrent automatiquement quand elles sont coupees d'un tronc. Force la couche de renduCUTOUT_MIPPED. Le parametresaplingest droppe avec une probabilite de 5% lors de la decomposition naturelle (peut etrenullpour desactiver).
Overload :leavesLike()equivaut aleavesLike(null). -
FluentEriBlock plantLike()Transforme le bloc en plante decorative :
- Hitbox reduite (
0.15, 0, 0.15a0.85, 0.9, 0.85) - Pas de collision (les entites traversent le bloc)
- Couche de rendu
CUTOUTautomatique isOpaque=false,isFullCube=false
block/crosspour l'affichage en X (comme les fleurs vanilla). - Hitbox reduite (
-
TerminalBlock register()Finalise et enregistre le bloc aupres de Forge. Retourne l'instance
Blockcreee.
import fr.eri.eriapi.content.EriBlock;
import net.minecraft.block.material.Material;
import net.minecraft.block.SoundType;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.init.Items;
import net.minecraft.util.math.AxisAlignedBB;
public class MonBlocs {
public static Block MINERAI_RUBIS;
public static Block BLOC_RUBIS;
public static Block DEMI_BLOC;
public static Block MACHINE;
public static void init() {
MINERAI_RUBIS = EriBlock.create("monmod", "minerai_rubis")
.material(Material.ROCK)
.hardness(3.0f)
.resistance(15.0f)
.harvestTool("pickaxe", 2) // Necessite une pioche en fer minimum
.soundType(SoundType.STONE)
.drops(Items.DIAMOND, 1, 3) // Drope entre 1 et 3 diamants
.creativeTab(CreativeTabs.BUILDING_BLOCKS)
.onBreak(ctx -> System.out.println("Minerai de rubis mine !"))
.register();
BLOC_RUBIS = EriBlock.create("monmod", "bloc_rubis")
.material(Material.IRON)
.hardness(5.0f)
.resistance(30.0f)
.harvestTool("pickaxe", 2)
.soundType(SoundType.METAL)
.creativeTab(CreativeTabs.BUILDING_BLOCKS)
.register();
// Hitbox simple : demi-bloc (8 pixels de haut)
// 1.0 = 1 bloc = 16 pixels
DEMI_BLOC = EriBlock.create("monmod", "demi_bloc")
.material(Material.ROCK)
.hardness(2.0f)
.hitbox(new AxisAlignedBB(0, 0, 0, 1, 0.5, 1))
.register();
// Plusieurs hitboxes : socle + pilier central
MACHINE = EriBlock.create("monmod", "machine")
.material(Material.IRON)
.hardness(4.0f)
.hitboxes(
new AxisAlignedBB(0, 0, 0, 1, 0.25, 1), // socle plat
new AxisAlignedBB(0.25, 0.25, 0.25, 0.75, 1, 0.75) // pilier central
)
.register();
}
}
Place la texture a src/main/resources/assets/monmod/textures/blocks/minerai_rubis.png
(16x16 px). Tu dois aussi fournir manuellement le blockstate et le modele dans
src/main/resources/assets/monmod/blockstates/minerai_rubis.json et
src/main/resources/assets/monmod/models/block/minerai_rubis.json. EriAPI enregistre
uniquement la resource location du modele via ModelLoader — il ne genere aucun fichier
JSON. Voir la section Bloc cube — Textures et modele JSON pour le
contenu des fichiers.
Bloc cube — Textures et modele JSON
Quand tu enregistres un EriBlock cubique, EriAPI enregistre la resource location du
modele aupres de Forge via ModelLoader.setCustomModelResourceLocation(), mais
aucun fichier JSON n'est genere automatiquement. Tu dois fournir toi-meme le
blockstate, le modele de bloc et le modele d'item dans src/main/resources/assets/<modid>/.
Ces fichiers sont inclus dans le JAR du mod a la compilation.
EriBlock.create("monmod", "mon_bloc")
.material(Material.ROCK)
.hardness(3.0f)
.register();
Cas 1 — Une seule texture pour toutes les faces
Place une texture PNG et fournis le blockstate + le modele de bloc + le modele d'item. C'est le cas le plus frequent.
src/main/resources/assets/monmod/textures/blocks/mon_bloc.png— la texture (16x16, ou 64x64 recommande)src/main/resources/assets/monmod/blockstates/mon_bloc.json— a creer manuellementsrc/main/resources/assets/monmod/models/block/mon_bloc.json— a creer manuellementsrc/main/resources/assets/monmod/models/item/mon_bloc.json— a creer manuellement (pour l'item en inventaire)
{
"variants": {
"normal": { "model": "monmod:mon_bloc" }
}
}
{
"parent": "block/cube_all",
"textures": {
"all": "monmod:blocks/mon_bloc"
}
}
{
"parent": "monmod:block/mon_bloc"
}
Cas 2 — Une texture differente par face
Pour avoir un haut, un bas et des cotes distincts (ex : four, sapin, minerai texture), fournis le
fichier models/block/mon_bloc.json avec les six faces.
{
"parent": "block/cube",
"textures": {
"up": "monmod:blocks/mon_bloc_top",
"down": "monmod:blocks/mon_bloc_bottom",
"north": "monmod:blocks/mon_bloc_side",
"south": "monmod:blocks/mon_bloc_side",
"east": "monmod:blocks/mon_bloc_side",
"west": "monmod:blocks/mon_bloc_side",
"particle": "monmod:blocks/mon_bloc_side"
}
}
Fichiers attendus dans ce cas :
src/main/resources/assets/monmod/textures/blocks/mon_bloc_top.pngsrc/main/resources/assets/monmod/textures/blocks/mon_bloc_bottom.pngsrc/main/resources/assets/monmod/textures/blocks/mon_bloc_side.png
EriAPI ne genere aucun fichier JSON. Il enregistre uniquement la resource
location du modele aupres de Forge. Tous les fichiers (blockstates/,
models/block/, models/item/, textures/) doivent etre
fournis manuellement dans src/main/resources/assets/<modid>/.
Bloc 3D anime (EriAnimBlock)
EriAnimBlock permet de creer un bloc avec un modele Blockbench 3D
et des animations. Sous le capot, il utilise un TileEntity + un
TESR (Tile Entity Special Renderer) enregistres automatiquement par EriAPI.
Workflow de creation
- Modeliser le bloc dans Blockbench (type de projet Java Block/Item).
- Exporter le modele en JSON dans
assets/modid/models/block/nom.json. - Creer le fichier d'animations
assets/modid/animations/block/nom.erianim.json. - Enregistrer le bloc en Java via
EriAnimBlock.create().
Fichiers requis
assets/modid/models/block/nom.json— modele Blockbench exporteassets/modid/animations/block/nom.erianim.json— fichier d'animations- Les textures referencees dans le JSON Blockbench
Builder fluent pour creer un bloc anime avec modele 3D et animations.
-
StatiqueEriAnimBlock create(String modid, String name)Cree un nouveau builder de bloc anime.
-
FluentEriAnimBlock material(Material mat)Materiau du bloc (
Material.IRON,Material.WOOD, etc.). -
FluentEriAnimBlock hardness(float hardness)Temps de minage du bloc.
-
FluentEriAnimBlock resistance(float resistance)Resistance aux explosions.
-
FluentEriAnimBlock animation(String animFileId)Obligatoire. ID du fichier
.erianim.jsonau format"modid:path/nom"(sans l'extension). Resout versassets/modid/animations/path/nom.erianim.json. -
FluentEriAnimBlock tileEntity(Class<?> teClass)TileEntity custom (optionnel). Doit etendre
AnimatedBlockTileEntityet avoir un constructeur public sans argument. Si non specifie, EriAPI utiliseAnimatedBlockTileEntityGeneric(suffisant pour 90% des cas).
Utilise cette option quand tu as besoin de logique custom : reagir a un event d'animation a une frame precise, enchainer plusieurs animations conditionnellement, sauvegarder un etat NBT propre au bloc, synchroniser des donnees vers le client, etc. -
FluentEriAnimBlock onRightClick(Consumer<BlockActionContext> handler)Callback execute quand le joueur fait un clic droit sur le bloc.
-
TerminalBlock register()Finalise et enregistre le bloc + le TileEntity + le TESR associes. Retourne l'instance
Block.
import fr.eri.eriapi.anim.AnimatedBlockTileEntity;
import fr.eri.eriapi.anim.EriAnimBlock;
import net.minecraft.block.material.Material;
EriAnimBlock.create("monmod", "coffre_special")
.material(Material.WOOD)
.hardness(2.5f)
.animation("monmod:block/coffre_special")
.onRightClick(ctx -> {
AnimatedBlockTileEntity te = (AnimatedBlockTileEntity)
ctx.world.getTileEntity(ctx.pos);
if (te != null && !te.isAnimating()) {
te.playAnimation("open");
}
})
.register();
TileEntity custom : AnimatedBlockTileEntity
Quand tu passes .tileEntity(MonTile.class) au builder, EriAPI utilise ta classe au lieu
de AnimatedBlockTileEntityGeneric. Ta classe doit etendre AnimatedBlockTileEntity
et avoir un constructeur public sans argument.
Base class a etendre pour un comportement custom. Les 3 methodes ci-dessous sont conçues pour etre surchargees.
Methodes a surcharger (protected)
-
Overridevoid onAnimationEvent(AnimationEvent event)Appele pour chaque event declenche par l'animation (keyframes de type
effect,sound,particle,custom). Utile pour spawner un son/particle a une frame precise. -
Overridevoid onAnimationComplete(String animName)Appele quand une animation se termine (atteint la derniere keyframe en mode
ONCE/HOLD/HIDE, ou apres une boucle complete pourLOOP_N). Idaal pour chainer plusieurs animations. -
Overridevoid onAnimationCallback(String callbackName)Appele specifiquement pour les keyframes de type callback avec le nom du callback (defini dans le JSON animation). Permet de nommer des points precis de l'animation (ex:
"chest_opened") et de reagir en Java.
Utilitaires publics (a appeler)
-
Publicvoid playAnimation(String animName)Joue l'animation nommee avec le
EndBehaviordefini dans le JSON (par defaut). -
Publicvoid playAnimation(String animName, EndBehavior endBehaviorOverride)Joue l'animation en forçant un
EndBehaviorcustom (ONCE,LOOP,HOLD,HIDE,LOOP_N). -
Publicvoid pauseAnimation()Met l'animation en pause a la frame courante (synchronise client+serveur).
-
Publicvoid resumeAnimation()Reprend une animation mise en pause.
-
Publicvoid resetAnimation()Retourne a la pose initiale (interpolation fluide).
-
Publicvoid resetAnimation(boolean instant)Retourne a la pose initiale ;
instant=truesaute l'interpolation (snap immediat). -
Publicvoid stopAnimation()Arrete l'animation courante (reste a la frame courante sans revenir a la pose de base).
-
Publicvoid setTexture(String target, String value)Remplace a la volee une texture du modele.
targetest la clef de texture du JSON Blockbench,valueest le chemin de la nouvelle texture (ex:"monmod:blocks/core_active"). Synchronise vers le client. -
Publicvoid clearTexture(String target)Supprime l'override de texture sur
target(retour a la texture originale du modele). -
Publicvoid clearAllTextures()Supprime tous les overrides de texture d'un coup.
-
Publicboolean isAnimating()Retourne
truesi une animation est en cours. -
PublicString getCurrentAnimation()Nom de l'animation courante, ou
nullsi aucune n'est active. -
Publicfloat getAnimationProgress()Progression de l'animation courante, de
0.0a1.0. -
Publicvoid setBlockYRotation(float rotation)Rotation du bloc autour de l'axe Y (degres). Synchronise vers le client.
import fr.eri.eriapi.anim.AnimatedBlockTileEntity;
import fr.eri.eriapi.anim.AnimationEvent;
public class TileEntityCoffreSpecial extends AnimatedBlockTileEntity {
public TileEntityCoffreSpecial() {
super("monmod:block/coffre_special", "monmod:block/coffre_special");
}
@Override
protected void onAnimationEvent(AnimationEvent event) {
// Ex: jouer un son a une frame precise
if ("creak".equals(event.getValue())) {
world.playSound(null, pos, SoundEvents.BLOCK_CHEST_OPEN,
SoundCategory.BLOCKS, 1.0f, 1.0f);
}
}
@Override
protected void onAnimationComplete(String animName) {
// Ex: chainer une autre animation
if ("open".equals(animName)) {
playAnimation("idle_open", EndBehavior.LOOP);
}
}
@Override
protected void onAnimationCallback(String callbackName) {
// Ex: spawner le loot a un point precis
if ("spawn_loot".equals(callbackName) && !world.isRemote) {
spawnLootAt(pos);
}
}
}
// Enregistrement :
EriAnimBlock.create("monmod", "coffre_special")
.material(Material.WOOD)
.animation("monmod:block/coffre_special")
.tileEntity(TileEntityCoffreSpecial.class)
.onRightClick(ctx -> {
TileEntityCoffreSpecial te = (TileEntityCoffreSpecial)
ctx.world.getTileEntity(ctx.pos);
if (te != null && !te.isAnimating()) {
te.playAnimation("open");
}
})
.register();
Pour des comportements plus complexes (callbacks sur events d'animation, enchainements conditionnels,
logique tick), cree une sous-classe de AnimatedBlockTileEntity et passe-la via
.tileEntity(TileCustom.class). Voir la page
Animation System pour le detail complet.
EriRecipe
EriRecipe permet de definir des recettes de craft et de fusion de maniere declarative.
Il supporte trois types de recettes : avec forme (shaped), sans forme
(shapeless) et au four (smelting).
Enregistre tes recettes apres avoir initialise tes items et blocs. Tu peux les placer dans une methode
appelee depuis @Mod.EventHandler public void init(FMLInitializationEvent event).
Recette avec forme — EriRecipe.shaped()
Une recette avec forme (shaped recipe) necessite que les ingredients soient places dans un ordre precis dans la grille de craft. C'est le type le plus courant (epees, outils, etc.).
-
StatiqueShapedBuilder shaped(String modid, String name)Cree un builder de recette avec forme.
nameest un identifiant unique pour la recette. -
FluentShapedBuilder pattern(String... rows)Definit le patron de la recette avec des chaines de caracteres representant les lignes de la grille 3x3. Chaque caractere est un ingredient (ou un espace pour une case vide).
-
FluentShapedBuilder key(char key, Item item)Associe un caractere du patron a un item. Peut etre appele plusieurs fois pour plusieurs caracteres.
-
FluentShapedBuilder key(char key, Block block)Variante qui accepte un
Blockcomme ingredient. -
FluentShapedBuilder result(Item item, int count)L'item produit par la recette et sa quantite.
-
FluentShapedBuilder result(Block block, int count)Variante qui produit un bloc.
-
Terminalvoid register()Enregistre la recette dans Forge.
// Patron de craft :
// R R R
// R R R
// R R R
EriRecipe.shaped("monmod", "bloc_rubis")
.pattern("RRR", "RRR", "RRR")
.key('R', MonItems.RUBIS)
.result(MonBlocs.BLOC_RUBIS, 1)
.register();
// Patron epee :
// R
// R
// B (baton)
EriRecipe.shaped("monmod", "epee_rubis")
.pattern(" R ", " R ", " B ")
.key('R', MonItems.RUBIS)
.key('B', Items.STICK)
.result(MonItems.EPEE_RUBIS, 1)
.register();
Recette sans forme — EriRecipe.shapeless()
Une recette sans forme (shapeless recipe) ne requiert aucun arrangement particulier des ingredients dans la grille — il suffit qu'ils soient tous presents. Utile pour les conversions simples.
-
StatiqueShapelessBuilder shapeless(String modid, String name)Cree un builder de recette sans forme.
-
FluentShapelessBuilder ingredient(Item item)Ajoute un ingredient a la recette. Peut etre appele plusieurs fois.
-
FluentShapelessBuilder ingredient(Block block)Variante qui accepte un
Blockcomme ingredient. -
FluentShapelessBuilder result(Item item, int count)L'item produit et sa quantite.
-
Terminalvoid register()Enregistre la recette dans Forge.
// 1 bloc de rubis → 9 rubis (ordre non important)
EriRecipe.shapeless("monmod", "rubis_depuis_bloc")
.ingredient(MonBlocs.BLOC_RUBIS)
.result(MonItems.RUBIS, 9)
.register();
Recette de fusion — EriRecipe.smelting()
Une recette de fusion (smelting recipe) definit ce que produit un item ou bloc quand il est chauffe dans un four. Tu peux aussi specifier les points d'experience gagnes.
-
StatiqueSmeltingBuilder smelting(String modid, String name)Cree un builder de recette de fusion.
-
FluentSmeltingBuilder input(Item item)L'item a fondre.
-
FluentSmeltingBuilder input(Block block)Variante qui accepte un
Blockcomme input. -
FluentSmeltingBuilder result(Item item)L'item produit par la fusion (toujours 1 exemplaire).
-
FluentSmeltingBuilder xp(float xp)Points d'experience gagnes par fusion. Le minerai de fer vanilla donne
0.7f, le diamant1.0f. -
Terminalvoid register()Enregistre la recette de fusion dans Forge.
// Minerai de rubis → rubis (avec 1.0 XP)
EriRecipe.smelting("monmod", "rubis_fusion")
.input(MonBlocs.MINERAI_RUBIS)
.result(MonItems.RUBIS)
.xp(1.0f)
.register();
Exemple complet — Un mod avec un minerai
Voici un exemple complet qui cree un set de contenu coherent : un minerai, un item gemme, un bloc compresse, une epee, et toutes les recettes associees.
@Mod(modid = "monmod", name = "Mon Mod", version = "1.0")
public class MonMod {
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
ContentRegistry.register(this); // 1. Initialise le registre EriAPI
// 2. Cree les items et blocs
MonItems.init();
MonBlocs.init();
}
@Mod.EventHandler
public void init(FMLInitializationEvent event) {
// 3. Enregistre les recettes (apres les items et blocs)
MonRecettes.init();
}
}
public class MonItems {
public static Item RUBIS;
public static Item EPEE_RUBIS;
public static void init() {
RUBIS = EriItem.create("monmod", "rubis")
.maxStackSize(64)
.rarity(EnumRarity.RARE)
.tooltip("&7Gemme precieuse extraite du sol")
.creativeTab(CreativeTabs.MATERIALS)
.register();
EPEE_RUBIS = EriItem.create("monmod", "epee_rubis")
.tool()
.type(ToolType.SWORD)
.damage(8f)
.durability(1500)
.speed(1.6f)
.done()
.rarity(EnumRarity.RARE)
.tooltip("&cForge dans le feu du rubis")
.creativeTab(CreativeTabs.COMBAT)
.register();
}
}
public class MonBlocs {
public static Block MINERAI_RUBIS;
public static Block BLOC_RUBIS;
public static void init() {
MINERAI_RUBIS = EriBlock.create("monmod", "minerai_rubis")
.material(Material.ROCK)
.hardness(3.0f)
.resistance(15.0f)
.harvestTool("pickaxe", 2)
.soundType(SoundType.STONE)
.drops(MonItems.RUBIS, 1, 2)
.creativeTab(CreativeTabs.BUILDING_BLOCKS)
.register();
BLOC_RUBIS = EriBlock.create("monmod", "bloc_rubis")
.material(Material.IRON)
.hardness(5.0f)
.resistance(30.0f)
.harvestTool("pickaxe", 2)
.soundType(SoundType.METAL)
.creativeTab(CreativeTabs.BUILDING_BLOCKS)
.register();
}
}
public class MonRecettes {
public static void init() {
// Bloc de rubis depuis 9 rubis
EriRecipe.shaped("monmod", "bloc_rubis_craft")
.pattern("RRR", "RRR", "RRR")
.key('R', MonItems.RUBIS)
.result(MonBlocs.BLOC_RUBIS, 1)
.register();
// Defaire le bloc → 9 rubis
EriRecipe.shapeless("monmod", "rubis_depuis_bloc")
.ingredient(MonBlocs.BLOC_RUBIS)
.result(MonItems.RUBIS, 9)
.register();
// Fondre le minerai → rubis
EriRecipe.smelting("monmod", "rubis_fusion")
.input(MonBlocs.MINERAI_RUBIS)
.result(MonItems.RUBIS)
.xp(1.0f)
.register();
// Craft de l'epee de rubis
EriRecipe.shaped("monmod", "epee_rubis_craft")
.pattern(" R ", " R ", " B ")
.key('R', MonItems.RUBIS)
.key('B', Items.STICK)
.result(MonItems.EPEE_RUBIS, 1)
.register();
}
}
EriEntity v2.0
EriEntity est le builder fluent pour enregistrer des entites custom avec un modele
Blockbench anime. Il fonctionne de pair avec AnimatedEntityRenderer et l'interface
IAnimatedEntity pour le rendu anime des entites.
Depuis v1.4.0, EriEntity.register() enregistre automatiquement l'entite dans
Forge via un pool de 32 slots pre-compiles (GeneratedEntitySlot0…GeneratedEntitySlot31).
Le mod n'a plus besoin de gerer l'EntityEntry ou le renderer manuellement.
Un maximum de 32 types d'entites EriEntity peut etre enregistre par mod.
Classes principales
| Classe | Package | Role |
|---|---|---|
EriEntity | fr.eri.eriapi.content | Builder fluent pour definir une entite |
EntityDefinition | fr.eri.eriapi.content | POJO contenant la configuration de l'entite |
EntitySeat | fr.eri.eriapi.content | Definition d'un siege passager |
AnimatedEntityRenderer | fr.eri.eriapi.anim | Renderer d'entite utilisant des modeles Blockbench |
IAnimatedEntity | fr.eri.eriapi.anim | Interface pour les entites avec animation |
Methodes du builder EriEntity
-
FactoryEriEntity create(String modId, String registryName)Cree un nouveau builder d'entite. Methode statique.
-
FluentEriEntity model(String modelId)Definit le modele Blockbench (ex:
"eriniumfaction:entity/monstre"). -
FluentEriEntity texture(String key, String path)Associe une cle de texture du modele a un chemin de ResourceLocation.
-
FluentEriEntity animation(String name, String animId)Associe un nom d'animation (ex: "idle", "walk") a un identifiant d'animation .erianim.
-
FluentEriEntity hitbox(float width, float height)Definit les dimensions de la hitbox (defaut: 0.6 x 1.8).
-
FluentEriEntity seat(float x, float y, float z)Ajoute un siege passager simple aux coordonnees Blockbench donnees.
-
FluentEriEntity seat(float x, float y, float z, String attachedGroup)Ajoute un siege attache a un groupe du modele (suit les animations du groupe).
-
FluentEriEntity seat(float x, float y, float z, float yawOffset, String attachedGroup, boolean lockCamera)Ajoute un siege complet avec rotation yaw, groupe attache et verrouillage camera.
-
FluentEriEntity spawnEgg(int primary, int secondary)Active un spawn egg avec les couleurs primaire et secondaire (format 0xRRGGBB).
-
FluentEriEntity creativeTab(String tabName)Definit l'onglet creatif pour le spawn egg.
-
TerminalEriEntity register()Enregistre la definition dans le ContentRegistry ET enregistre automatiquement l'EntityEntry, le renderer, le spawn egg et les regles de spawn dans Forge via le pool de 32 slots (v1.4.0).
Methodes avancees (v1.4.0)
-
FluentEriEntity name(String displayName)Nom d'affichage de l'entite.
-
FluentEriEntity health(double health)PV max de l'entite (defaut: 20.0).
-
FluentEriEntity armor(double armor)Valeur d'armure (defaut: 0).
-
FluentEriEntity armorToughness(double toughness)Robustesse de l'armure (defaut: 0).
-
FluentEriEntity attackDamage(double damage)Degats au corps a corps (defaut: 2.0).
-
FluentEriEntity movementSpeed(double speed)Vitesse de deplacement (defaut: 0.25).
-
FluentEriEntity followRange(double range)Portee de detection des cibles (defaut: 16).
-
FluentEriEntity knockbackResistance(double resist)Resistance au knockback, 0.0–1.0 (defaut: 0).
-
FluentEriEntity immuneToFire()L'entite est immunisee au feu.
-
FluentEriEntity immuneToKnockback()L'entite est immunisee au knockback.
-
FluentEriEntity canSwim(boolean swim)Definit si l'entite peut nager (defaut: true).
-
FluentEriEntity experienceDrop(int min, int max)XP droppee a la mort (valeur aleatoire entre min et max).
-
FluentEriEntity ambientSound(SoundEvent sound)Son ambiant.
-
FluentEriEntity hurtSound(SoundEvent sound)Son de degats.
-
FluentEriEntity deathSound(SoundEvent sound)Son de mort.
-
FluentEriEntity stepSound(SoundEvent sound)Son de pas.
-
FluentEriEntity ambientSoundInterval(int ticks)Intervalle entre sons ambiants (defaut: 80 ticks).
-
FluentEriEntity aiPreset(AiPreset preset)Comportement IA predefini. Valeurs :
PASSIVE,HOSTILE_MELEE,HOSTILE_RANGED,NEUTRAL,BOSS. -
FluentEriEntity ai(Consumer<PathfinderBuilder> config)Configuration IA custom via
PathfinderBuilder(voir section dediee ci-dessous). -
FluentEriEntity drop(ItemStack stack, float chance)Drop d'item a la mort (chance: 0.0–1.0).
-
FluentEriEntity drop(Item item, int min, int max, float chance)Drop aleatoire entre min et max items.
-
FluentEriEntity rareDrop(ItemStack stack, float chance)Drop rare (chance divisee par looting level).
-
FluentEriEntity spawn(Consumer<EriSpawner> config)Regles de spawn naturel (voir section
EriSpawner). -
FluentEriEntity tracker(int range, int freq, boolean velocity)Parametres de tracking reseau (defaut: 64, 3, true).
-
FluentEriEntity onSpawn(Consumer<EntityLivingBase> cb)Callback appele au spawn initial.
-
FluentEriEntity onDeath(BiConsumer<EntityLivingBase, DamageSource> cb)Callback a la mort.
-
FluentEriEntity onUpdate(Consumer<EntityLivingBase> cb)Callback chaque tick (
onLivingUpdate). -
FluentEriEntity onAttack(BiConsumer<EntityLivingBase, Entity> cb)Callback quand l'entite attaque.
-
FluentEriEntity onHurt(BiConsumer<EntityLivingBase, DamageSource> cb)Callback quand l'entite recoit des degats.
-
FluentEriEntity onInteract(BiConsumer<EntityLivingBase, EntityPlayer> cb)Callback quand un joueur clic droit sur l'entite.
AnimatedEntityRenderer
Le renderer d'entite qui affiche un modele Blockbench avec animations. Le pipeline de rendu
(groupes, elements, faces, UV) est identique a AnimatedBlockTESR.
-
FactoryIRenderFactory<T> factory(String modelId)Cree une factory pour
RenderingRegistry.registerEntityRenderingHandler(). -
FactoryIRenderFactory<T> factory(String modelId, float shadowSize)Factory avec taille d'ombre personnalisee.
IAnimatedEntity
Interface que les entites doivent implementer pour supporter le rendu anime. Le renderer verifie cette interface pour obtenir la pose d'animation.
-
AnimationPose getCurrentPose(float partialTicks)Retourne la pose interpolee courante, ou
nullsi aucune animation n'est active. -
AnimState getAnimState()Retourne l'etat d'animation courant de l'entite.
EntitySeat
Chaque entite peut avoir un ou plusieurs sieges pour les passagers. Les coordonnees sont en pixels Blockbench (meme espace de coordonnees que le modele).
| Champ | Type | Description |
|---|---|---|
x, y, z | float | Position du siege en pixels Blockbench (local a l'entite). |
yawOffset | float | Rotation yaw du passager en degres (defaut: 0). |
attachedGroup | String | Nom du groupe du modele auquel le siege est attache (peut etre null). Le siege suit les animations du groupe. |
lockCamera | boolean | Si true, la camera du joueur assis est verrouillee (defaut: false). |
// Dans preInit() — auto-enregistrement complet
EriEntity.create("monmod", "garde_elite")
.model("monmod:entity/garde")
.texture("body", "monmod:textures/entity/garde_body")
.animation("idle", "monmod:entity/garde_idle")
.animation("walk", "monmod:entity/garde_walk")
.animation("attack", "monmod:entity/garde_attack")
.hitbox(0.7f, 2.0f)
.name("Garde Elite")
.health(40).attackDamage(6).armor(4).movementSpeed(0.28)
.hurtSound(SoundEvents.ENTITY_ZOMBIE_HURT)
.deathSound(SoundEvents.ENTITY_ZOMBIE_DEATH)
.aiPreset(AiPreset.HOSTILE_MELEE)
.ai(ai -> ai.swim().meleeAttack(1.1, false).wander(0.8).watchPlayers(16f).lookIdle().targetPlayers().hurtByTarget(true))
.drop(new ItemStack(Items.IRON_SWORD), 0.05f)
.drop(Items.IRON_INGOT, 0, 2, 0.4f)
.experienceDrop(5, 15)
.spawn(s -> s.type(EnumCreatureType.MONSTER).weight(8).group(1, 3).lightLevel(0, 7).dimension(0))
.spawnEgg(0x2C2C2C, 0xFFD700)
.onDeath((entity, src) -> EriniumFaction.LOGGER.info("Garde tue par {}", src.getDamageType()))
.register();
// C'est tout ! Pas de EntityEntry manuel, pas de RenderingRegistry manuel.
PathfinderBuilder v2.0
Builder fluent pour configurer les AI tasks d'une entite EriEntity. Utilise dans
EriEntity.ai(Consumer<PathfinderBuilder>). Les tasks sont appliquees
dans l'ordre d'appel.
Goal tasks
-
FluentPathfinderBuilder swim()Permet a l'entite de nager quand elle est dans l'eau.
-
FluentPathfinderBuilder meleeAttack(double speed, boolean longMemory)Attaque au corps a corps.
longMemorycontinue de poursuivre la cible meme perdue de vue. -
FluentPathfinderBuilder wander(double speed)Deplacement aleatoire en idle.
-
FluentPathfinderBuilder watchClosest(Class<EntityLivingBase> target, float distance)L'entite regarde l'entite cible la plus proche dans la distance donnee.
-
FluentPathfinderBuilder watchPlayers(float distance)Raccourci : regarde le joueur le plus proche.
-
FluentPathfinderBuilder lookIdle()Regard aleatoire en idle.
-
FluentPathfinderBuilder panicOnHurt(double speed)L'entite panique et fuit quand elle est blessee.
-
FluentPathfinderBuilder leapAtTarget(float motionY)L'entite saute sur sa cible avec la vitesse verticale donnee.
-
FluentPathfinderBuilder avoidEntity(Class cls, float distance, double walkSpeed, double sprintSpeed)Evite les entites de la classe donnee (fuite a
walkSpeed, sprint asprintSpeed). -
FluentPathfinderBuilder openDoors(boolean closeBehind)L'entite peut ouvrir les portes.
closeBehindles referme derriere elle.
Target tasks
-
FluentPathfinderBuilder targetPlayers()Cible les joueurs a portee.
-
FluentPathfinderBuilder targetClass(Class cls)Cible une classe d'entite specifique.
-
FluentPathfinderBuilder hurtByTarget(boolean callForHelp)Riposte contre l'attaquant.
callForHelpappelle les allies du meme type.
Tasks custom
-
FluentPathfinderBuilder task(EntityAIBase ai)Ajoute un goal task custom deja instancie.
-
FluentPathfinderBuilder targetTask(EntityAIBase ai)Ajoute un target task custom deja instancie.
-
FluentPathfinderBuilder task(Function<EntityLiving, EntityAIBase> factory)Factory qui construit le goal task a partir de l'instance de l'entite.
-
FluentPathfinderBuilder targetTask(Function<EntityLiving, EntityAIBase> factory)Factory qui construit le target task a partir de l'instance de l'entite.
EriEntity.create("monmod", "garde")
.health(30).attackDamage(4)
.aiPreset(AiPreset.HOSTILE_MELEE)
.ai(ai -> ai
.swim()
.meleeAttack(1.0, false)
.wander(0.8)
.watchPlayers(12f)
.lookIdle()
.targetPlayers()
.hurtByTarget(true))
.register();
EriSpawner v2.0
Builder fluent pour configurer les regles de spawn naturel d'une entite. Utilise dans
EriEntity.spawn(Consumer<EriSpawner>). Les regles sont enregistrees
automatiquement dans Forge via EntityRegistry.addSpawn().
Methodes du builder
-
FluentEriSpawner type(EnumCreatureType type)Categorie de creature :
MONSTER,CREATURE,AMBIENT,WATER_CREATURE. -
FluentEriSpawner weight(int weight)Poids du spawn (plus eleve = plus frequent).
-
FluentEriSpawner group(int min, int max)Taille du groupe au spawn (valeur aleatoire entre min et max).
-
FluentEriSpawner dimension(int... ids)Dimensions autorisees (0 = Overworld, -1 = Nether, 1 = End).
-
FluentEriSpawner biome(Biome... biomes)Biomes autorises pour le spawn.
-
FluentEriSpawner excludeBiome(Biome... biomes)Biomes interdits pour le spawn.
-
FluentEriSpawner lightLevel(int min, int max)Plage de niveau de lumiere pour le spawn (0–15).
-
FluentEriSpawner heightRange(int min, int max)Plage d'altitude Y pour le spawn.
-
FluentEriSpawner maxPerChunk(int max)Nombre maximum d'entites de ce type par chunk.
-
FluentEriSpawner despawnDistance(int blocks)Distance (en blocks) au-dela de laquelle l'entite despawn.
EriEntity.create("monmod", "zombie_garde")
.health(20).attackDamage(3)
.aiPreset(AiPreset.HOSTILE_MELEE)
.spawn(s -> s
.type(EnumCreatureType.MONSTER)
.weight(10)
.group(2, 4)
.lightLevel(0, 7)
.dimension(0)
.maxPerChunk(8))
.register();
EriProjectile v2.0
Builder fluent pour enregistrer des projectiles custom avec physique, combat, visuel et
callbacks d'impact. Auto-enregistrement Forge via un pool de 32 slots
(GeneratedProjectileSlot0…GeneratedProjectileSlot31) : pas besoin
de sous-classer EntityThrowable ou d'enregistrer manuellement l'EntityEntry.
Factory
-
FactoryEriProjectile create(String modId, String registryName)Cree un nouveau builder de projectile. Methode statique.
Physique
-
FluentEriProjectile velocity(float velocity)Vitesse initiale du projectile.
-
FluentEriProjectile gravity(float gravity)Gravite appliquee par tick (0 = pas de gravite).
-
FluentEriProjectile inaccuracy(float inaccuracy)Imprecision aleatoire du tir.
-
FluentEriProjectile lifetime(int ticks)Duree de vie max du projectile en ticks.
-
FluentEriProjectile piercing(int maxEntities)Le projectile traverse jusqu'a N entites avant disparition.
-
FluentEriProjectile bouncing(int maxBounces)Le projectile rebondit N fois sur les blocs.
Combat
-
FluentEriProjectile damage(float damage)Degats infliges a l'impact.
-
FluentEriProjectile damageType(DamageSource type)Type de degats custom (defaut: thrown).
-
FluentEriProjectile knockback(float knockback)Force de knockback a l'impact.
-
FluentEriProjectile setFire(int seconds)Met le feu a l'entite touchee pendant N secondes.
Visuel
-
FluentEriProjectile texture(ResourceLocation texture)Texture du projectile.
-
FluentEriProjectile renderAsItem(ItemStack stack)Rend le projectile comme un item 3D au lieu d'une texture plate.
-
FluentEriProjectile scale(float scale)Echelle de rendu.
-
FluentEriProjectile glowing(boolean glow)Le projectile brille (fullbright).
-
FluentEriProjectile trailParticle(EnumParticleTypes particle)Particules laissees dans le sillage du projectile.
-
FluentEriProjectile trailColor(int argb)Couleur de la trainee (format ARGB).
Callbacks & effets d'impact
-
FluentEriProjectile onHitEntity(BiConsumer<Entity, Entity> cb)Callback (projectile, cible) quand le projectile touche une entite.
-
FluentEriProjectile onHitBlock(BiConsumer<Entity, BlockPos> cb)Callback (projectile, pos) quand le projectile touche un bloc.
-
FluentEriProjectile onExpire(Consumer<Entity> cb)Callback quand le projectile expire (lifetime ecoule).
-
FluentEriProjectile explosionOnImpact(float power, boolean fire)Declenche une explosion a l'impact.
-
FluentEriProjectile potionOnImpact(PotionEffect effect, float radius)Eclaboussure de potion dans un rayon donne.
-
FluentEriProjectile aoeOnImpact(float radius, float damage)Degats de zone dans un rayon (pas d'explosion, pas de destruction).
Spawn egg & tracker
-
FluentEriProjectile spawnEgg(int primary, int secondary)Active un spawn egg (format 0xRRGGBB).
-
FluentEriProjectile tracker(int range, int freq, boolean velocity)Parametres de tracking reseau (defaut: 64, 10, true).
Enregistrement & tir
-
TerminalEriProjectile register()Enregistre le projectile dans Forge via le slot pool et retourne le builder (utilisable ensuite pour
spawn()). -
ActionEntity spawn(World world, Entity shooter)Instancie et tire le projectile depuis une entite (position et direction du shooter).
-
ActionEntity spawnAt(World world, double x, double y, double z, float yaw, float pitch)Tire le projectile depuis des coordonnees et une direction precises.
EriProjectile fireball = EriProjectile.create("monmod", "fireball")
.velocity(1.8f)
.gravity(0.02f)
.damage(6.0f)
.setFire(3)
.knockback(0.5f)
.texture(new ResourceLocation("monmod", "textures/entity/fireball"))
.explosionOnImpact(2.0f, true)
.onHitEntity((proj, target) -> target.setFire(60))
.register();
// Tirer depuis une entite
fireball.spawn(world, shooterEntity);
// Tirer depuis coordonnees
fireball.spawnAt(world, x, y, z, yaw, pitch);
EntityDataSync / @SyncParam v2.0
Gestion automatique des DataParameter d'une entite via annotations. Declare un champ
avec @SyncParam, appelle EntityDataSync.register(this) dans
entityInit(), puis utilise get() / set() type-safe sans
reflexion en hot path. Persistence NBT automatique pour les champs marques
persistent = true.
@SyncParam
-
@interface SyncParamAnnotation a placer sur un champ d'entite pour l'inclure dans la synchronisation client/serveur.
-
boolean persistent() default trueSi
false, le champ n'est pas sauvegarde en NBT (perdu au restart). -
String nbtKey() default ""Cle NBT custom. Si vide, le nom du champ Java est utilise.
EntityDataSync
-
Staticvoid register(EntityLiving entity)A appeler dans
entityInit()apressuper.entityInit(). Scanne les champs@SyncParampar reflexion (une seule fois par classe) et cree lesDataParametercorrespondants. -
StaticT get(EntityLiving entity, String fieldName)Lit la valeur synchronisee d'un champ. Zero reflexion au runtime.
-
Staticvoid set(EntityLiving entity, String fieldName, Object value)Ecrit la valeur synchronisee d'un champ (propage automatiquement au client).
-
Staticvoid writeNBT(EntityLiving entity, NBTTagCompound tag)A appeler dans
writeEntityToNBT(). Serialise tous les champspersistent = true. -
Staticvoid readNBT(EntityLiving entity, NBTTagCompound tag)A appeler dans
readEntityFromNBT(). Deserialise tous les champspersistent = true.
Types supportes
boolean, int, float, String,
ItemStack, BlockPos, ITextComponent.
public class EntityGarde extends EntityMob {
@SyncParam private boolean isEnraged = false;
@SyncParam private int variant = 0;
@SyncParam(persistent = false) private float animBlend = 0f;
@SyncParam(nbtKey = "rage_level") private int rageLevel = 0;
@Override
protected void entityInit() {
super.entityInit();
EntityDataSync.register(this);
}
public void setEnraged(boolean v) { EntityDataSync.set(this, "isEnraged", v); }
public boolean isEnraged() { return EntityDataSync.get(this, "isEnraged"); }
@Override
public void writeEntityToNBT(NBTTagCompound tag) {
super.writeEntityToNBT(tag);
EntityDataSync.writeNBT(this, tag);
}
@Override
public void readEntityFromNBT(NBTTagCompound tag) {
super.readEntityFromNBT(tag);
EntityDataSync.readNBT(this, tag);
}
}
EriEntityBase v1.5.0
EriEntityBase est la classe de base a etendre quand tu veux une entite
avec une logique Java custom (override de methodes, champs synchronises, NBT
specifique) tout en gardant l'auto-configuration EriEntity (stats, AI, sons, drops, callbacks).
Sans cette classe, EriAPI genere l'entite dans un slot pre-compile du pool
GeneratedEntitySlots (limite a 32). Avec .entityClass(MonEntite.class),
ta classe est enregistree directement dans Forge — tu peux donc surcharger n'importe quelle methode
de EntityMob / EntityLivingBase.
Classe de base a etendre pour une entite custom. Mirrors la logique de GeneratedEntity mais permet le sous-classement.
Contrat d'extension
- Extend
EriEntityBase - Avoir un constructeur public :
public MyEntity(World world) { super(world); } - Si tu utilises
@SyncParam, appelleEntityDataSync.register(this)dansentityInit()apressuper.entityInit() - Tu peux surcharger n'importe quelle methode ; appelle
superpour conserver les comportements EriEntity (sons, drops, callbacks...)
Champs proteges accessibles
-
protectedEntityDefinition eriDefLa definition qui pilote l'entite. May be null si misconfigure.
-
protectedString eriDefIdId canonique (
modId:registryName) utilise pour la restauration NBT.
Accesseurs publics
-
PublicEntityDefinition getEriDef()Retourne la
EntityDefinitionqui pilote cette entite. -
PublicString getEriDefId()Retourne l'id canonique (
modId:registryName).
-
FluentEriEntity entityClass(Class<? extends EriEntityBase> clazz)Specifie une classe Java custom. Quand cette methode est appelee, EriAPI enregistre directement ta classe dans Forge au lieu d'utiliser un slot pre-compile. La classe doit etendre
EriEntityBaseet avoir un constructeurpublic MyEntity(World world).
import fr.eri.eriapi.content.*;
import net.minecraft.world.World;
public class EntityBoss extends EriEntityBase {
@SyncParam public boolean isEnraged = false;
@SyncParam public int phase = 1;
public EntityBoss(World world) {
super(world);
}
@Override
protected void entityInit() {
super.entityInit();
EntityDataSync.register(this);
}
@Override
public void onLivingUpdate() {
super.onLivingUpdate();
// Passe en phase 2 sous 50% de vie
if (!world.isRemote && phase == 1 && getHealth() < getMaxHealth() * 0.5f) {
EntityDataSync.set(this, "phase", 2);
EntityDataSync.set(this, "isEnraged", true);
}
}
}
// Enregistrement :
EriEntity.create("monmod", "boss")
.health(200).attackDamage(12).armor(10)
.aiPreset(AiPreset.BOSS)
.entityClass(EntityBoss.class) // ← classe custom
.spawnEgg(0x8B0000, 0xFF4500)
.register();
Utilise EriEntityBase quand tu as besoin de champs synchronises
(@SyncParam), de NBT custom, d'override de onLivingUpdate()
ou d'autres methodes vanilla. Pour les entites simples (stats + AI + drops), les callbacks du builder
(onSpawn, onUpdate, onDeath, etc.) suffisent — pas besoin de
creer une classe.
EriProjectileBase v1.5.0
EriProjectileBase est la classe de base a etendre quand tu veux un projectile
avec une logique Java custom (trajectoire speciale, effets custom a l'impact, homing)
tout en gardant l'auto-configuration EriProjectile (velocite, gravite, piercing, bouncing, explosion,
AOE, potion).
Classe de base a etendre pour un projectile custom.
Contrat d'extension
- Extend
EriProjectileBase - Constructeur obligatoire :
public MyProjectile(World world) { super(world); } - Constructeur optionnel :
public MyProjectile(World world, EntityLivingBase thrower) - Appelle
superdans tes overrides pour conserver piercing, bouncing, AOE, etc.
Champs proteges accessibles
-
protectedProjectileDefinition eriDefLa definition qui pilote ce projectile.
-
protectedString eriDefIdId canonique (
modId:registryName) utilise pour le log NBT. -
protectedint pierceCountNombre d'entites que ce projectile a deja percees.
-
protectedint bounceCountNombre de blocs sur lesquels ce projectile a deja rebondi.
-
protectedint ticksAliveNombre de ticks depuis le spawn du projectile.
-
FluentEriProjectile projectileClass(Class<? extends EriProjectileBase> clazz)Specifie une classe Java custom. Quand cette methode est appelee, EriAPI enregistre directement ta classe dans Forge au lieu d'utiliser un slot pre-compile de
GeneratedProjectileSlots.
import fr.eri.eriapi.content.*;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.world.World;
public class ProjectileMissile extends EriProjectileBase {
public ProjectileMissile(World world) { super(world); }
public ProjectileMissile(World world, EntityLivingBase thrower) {
super(world, thrower);
}
@Override
public void onUpdate() {
super.onUpdate();
// Tete chercheuse : corrige la trajectoire vers la cible la plus proche
if (!world.isRemote && ticksExisted % 5 == 0) {
EntityLivingBase target = findNearestTarget();
if (target != null) {
double dx = target.posX - posX;
double dy = target.posY + target.height * 0.5 - posY;
double dz = target.posZ - posZ;
double len = Math.sqrt(dx*dx + dy*dy + dz*dz);
double speed = 0.4;
motionX = dx / len * speed;
motionY = dy / len * speed;
motionZ = dz / len * speed;
}
}
}
private EntityLivingBase findNearestTarget() {
AxisAlignedBB aabb = new AxisAlignedBB(posX-16, posY-16, posZ-16,
posX+16, posY+16, posZ+16);
EntityLivingBase nearest = null;
double best = Double.MAX_VALUE;
for (EntityLivingBase e : world.getEntitiesWithinAABB(EntityLivingBase.class, aabb)) {
if (e == getThrower()) continue;
double d = e.getDistanceSq(this);
if (d < best) { best = d; nearest = e; }
}
return nearest;
}
}
// Enregistrement :
EriProjectile.create("monmod", "missile")
.damage(8f).velocity(1.2f).gravity(0f).lifetime(200)
.explosionOnImpact(2.0f, false)
.projectileClass(ProjectileMissile.class) // ← classe custom
.register();
EriItemBase v1.5.0
EriItemBase est la classe de base a etendre quand tu veux un item avec
une logique Java custom (NBT persistant, cooldowns complexes, rendu conditionnel,
interactions speciales) tout en gardant l'auto-configuration EriItem (tooltip, rarity, glow, stack size,
durability).
Utilise les sous-builders .tool() et .armor() plutot que
.itemClass() — EriAPI genere des classes specialisees (GeneratedTool,
GeneratedArmor) qui gerent correctement les mechaniques d'outils et d'armure. Utilise
.itemClass() pour les items simples qui ont besoin de logique custom.
Classe de base a etendre pour un item custom.
Contrat d'extension
- Extend
EriItemBase - Constructeur obligatoire :
public MyItem() { super(); }(aucun argument) - Tu peux surcharger
onItemRightClick,onItemUse,onUpdate, etc. - Appelle
superdans les overrides pour conserver le callback.onRightClick()du builder
Champs proteges accessibles
-
protectedItemDefinition eriDefLa definition qui pilote cet item. Contient tooltip, rarity, glow, etc.
-
FluentEriItem itemClass(Class<? extends EriItemBase> clazz)Specifie une classe Java custom. Quand cette methode est appelee, EriAPI enregistre directement ta classe dans Forge au lieu de
GeneratedItem.
import fr.eri.eriapi.content.*;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.*;
import net.minecraft.world.World;
public class ItemPortail extends EriItemBase {
public ItemPortail() { super(); }
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
ItemStack stack = player.getHeldItem(hand);
NBTTagCompound nbt = stack.getOrCreateSubCompound("Portail");
if (!nbt.hasKey("X")) {
// Premier clic : memorise la position
nbt.setInteger("X", (int) player.posX);
nbt.setInteger("Y", (int) player.posY);
nbt.setInteger("Z", (int) player.posZ);
if (!world.isRemote) {
player.sendMessage(new TextComponentString("Position memorisee !"));
}
} else {
// Deuxieme clic : teleporte
player.setPositionAndUpdate(
nbt.getInteger("X"),
nbt.getInteger("Y"),
nbt.getInteger("Z"));
stack.removeSubCompound("Portail");
}
return new ActionResult<>(EnumActionResult.SUCCESS, stack);
}
}
// Enregistrement :
EriItem.create("monmod", "portail")
.maxStackSize(1).glowing(true).rarity(EnumRarity.RARE)
.tooltip("&7Clic droit : memorise la position")
.tooltip("&7Deuxieme clic droit : teleporte")
.itemClass(ItemPortail.class) // ← classe custom
.register();