google-site-verification: google61fe8ba583a51912.html
Minecraft Modding with Forge: Complete Guide

Introduction

Minecraft Forge is the most popular modding framework for Minecraft, allowing developers to create custom content, mechanics, and features. This comprehensive guide covers everything from basic setup to advanced modding techniques.

Project Setup

Environment Preparation

Required Tools:

  • Java JDK 8, 11, or 17 (depending on Minecraft version)
  • IntelliJ IDEA (recommended) or Eclipse
  • Git
  • Minecraft Forge MDK

Build Configuration (build.gradle)

// build.gradle buildscript { repositories { maven { url = 'https://maven.minecraftforge.net/' } maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } jcenter() mavenCentral() } dependencies { classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' } } apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.spongepowered.mixin' apply plugin: 'eclipse' apply plugin: 'maven-publish' version = '1.0.0' group = 'com.yourname.yourmod' archivesBaseName = 'yourmod' java.toolchain.languageVersion = JavaLanguageVersion.of(17) minecraft { mappings channel: 'official', version: '1.19.2' runs { client { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' property 'forge.enabledGameTestNamespaces', 'yourmod' mods { yourmod { source sourceSets.main } } } server { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' property 'forge.enabledGameTestNamespaces', 'yourmod' mods { yourmod { source sourceSets.main } } } gameTestServer { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' property 'forge.enabledGameTestNamespaces', 'yourmod' mods { yourmod { source sourceSets.main } } } data { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' args '--mod', 'yourmod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') mods { yourmod { source sourceSets.main } } } } } sourceSets.main.resources { srcDir 'src/generated/resources' } repositories { maven { url "https://cursemaven.com" } } dependencies { minecraft 'net.minecraftforge:forge:1.19.2-43.2.0' // Example: JEI integration // compileOnly fg.deobf("mezz.jei:jei-1.19.2-common-api:11.5.0.297") // runtimeOnly fg.deobf("mezz.jei:jei-1.19.2-forge:11.5.0.297") } jar { manifest { attributes([ "Specification-Title": "yourmod", "Specification-Vendor": "yourname", "Specification-Version": "1", "Implementation-Title": project.name, "Implementation-Version": project.jar.archiveVersion, "Implementation-Vendor": "yourname", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") ]) } } jar.finalizedBy('reobfJar') publishing { publications { mavenJava(MavenPublication) { artifact jar } } repositories { maven { url "file://${project.projectDir}/mcmodsrepo" } } }

Core Mod Structure

Main Mod Class

package com.yourname.yourmod; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @Mod(YourMod.MODID) public class YourMod { public static final String MODID = "yourmod"; public static final String NAME = "Your Awesome Mod"; public static final String VERSION = "1.0.0"; public static final Logger LOGGER = LogManager.getLogger(); public YourMod() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); IEventBus forgeEventBus = MinecraftForge.EVENT_BUS; // Register items and blocks ModItems.register(modEventBus); ModBlocks.register(modEventBus); ModEntities.register(modEventBus); // Register event listeners forgeEventBus.register(this); forgeEventBus.register(new EventHandler()); // Register configuration ModConfig.register(); LOGGER.info("{} v{} initialized!", NAME, VERSION); } // Custom creative tab public static final CreativeModeTab MOD_TAB = new CreativeModeTab(MODID) { @Override public ItemStack makeIcon() { return new ItemStack(ModItems.EXAMPLE_ITEM.get()); } }; }

Mod Configuration

package com.yourname.yourmod.config; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.config.ModConfig; import org.apache.commons.lang3.tuple.Pair; public class ModConfig { public static final ClientConfig CLIENT; public static final ForgeConfigSpec CLIENT_SPEC; public static final CommonConfig COMMON; public static final ForgeConfigSpec COMMON_SPEC; static { final Pair<ClientConfig, ForgeConfigSpec> clientSpecPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new); CLIENT_SPEC = clientSpecPair.getRight(); CLIENT = clientSpecPair.getLeft(); final Pair<CommonConfig, ForgeConfigSpec> commonSpecPair = new ForgeConfigSpec.Builder().configure(CommonConfig::new); COMMON_SPEC = commonSpecPair.getRight(); COMMON = commonSpecPair.getLeft(); } public static void register() { ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, CLIENT_SPEC); ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, COMMON_SPEC); } public static class ClientConfig { public final ForgeConfigSpec.BooleanValue enableShinyEffects; public final ForgeConfigSpec.IntValue exampleItemColor; public ClientConfig(ForgeConfigSpec.Builder builder) { builder.push("client"); enableShinyEffects = builder .comment("Whether to enable shiny particle effects on custom items") .define("enableShinyEffects", true); exampleItemColor = builder .comment("Color for example item (RGB integer)") .defineInRange("exampleItemColor", 0xFF00FF, 0x000000, 0xFFFFFF); builder.pop(); } } public static class CommonConfig { public final ForgeConfigSpec.BooleanValue enableExampleFeature; public final ForgeConfigSpec.DoubleValue exampleSpawnChance; public final ForgeConfigSpec.ConfigValue<String> exampleString; public CommonConfig(ForgeConfigSpec.Builder builder) { builder.push("general"); enableExampleFeature = builder .comment("Enable the example feature") .define("enableExampleFeature", true); exampleSpawnChance = builder .comment("Chance for example entity to spawn (0.0 - 1.0)") .defineInRange("exampleSpawnChance", 0.1, 0.0, 1.0); exampleString = builder .comment("An example string configuration") .define("exampleString", "Hello World!"); builder.pop(); } } }

Custom Items

Basic Item Registration

package com.yourname.yourmod.core.init; import com.yourname.yourmod.YourMod; import net.minecraft.world.item.Item; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public class ModItems { public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, YourMod.MODID); // Basic Items public static final RegistryObject<Item> EXAMPLE_ITEM = ITEMS.register("example_item", () -> new Item(new Item.Properties().tab(YourMod.MOD_TAB))); public static final RegistryObject<Item> MAGIC_CRYSTAL = ITEMS.register("magic_crystal", () -> new Item(new Item.Properties() .tab(YourMod.MOD_TAB) .stacksTo(16) .fireResistant())); // Tool Items public static final RegistryObject<Item> EXAMPLE_SWORD = ITEMS.register("example_sword", () -> new SwordItem(ModTiers.EXAMPLE, 3, -2.4F, new Item.Properties().tab(YourMod.MOD_TAB))); public static final RegistryObject<Item> EXAMPLE_PICKAXE = ITEMS.register("example_pickaxe", () -> new PickaxeItem(ModTiers.EXAMPLE, 1, -2.8F, new Item.Properties().tab(YourMod.MOD_TAB))); // Food Items public static final RegistryObject<Item> EXAMPLE_FOOD = ITEMS.register("example_food", () -> new Item(new Item.Properties() .tab(YourMod.MOD_TAB) .food(ModFoods.EXAMPLE_FOOD))); // Special Items public static final RegistryObject<Item> TELEPORT_STAFF = ITEMS.register("teleport_staff", () -> new TeleportStaffItem(new Item.Properties() .tab(YourMod.MOD_TAB) .stacksTo(1) .durability(100))); public static void register(IEventBus eventBus) { ITEMS.register(eventBus); } }

Custom Item Classes

package com.yourname.yourmod.items; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; public class TeleportStaffItem extends Item { public TeleportStaffItem(Properties properties) { super(properties); } @Override public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (!level.isClientSide()) { // Calculate teleport position (8 blocks in front of player) Vec3 lookVec = player.getLookAngle(); Vec3 teleportPos = player.position().add(lookVec.x * 8, lookVec.y * 8, lookVec.z * 8); // Ensure safe teleport position if (isSafePosition(level, teleportPos)) { player.teleportTo(teleportPos.x, teleportPos.y, teleportPos.z); // Add cooldown and damage item player.getCooldowns().addCooldown(this, 60); // 3 second cooldown itemstack.hurtAndBreak(1, player, (p) -> p.broadcastBreakEvent(hand)); // Play sound level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENDERMAN_TELEPORT, player.getSoundSource(), 1.0F, 1.0F); } } return InteractionResultHolder.sidedSuccess(itemstack, level.isClientSide()); } private boolean isSafePosition(Level level, Vec3 pos) { // Check if position is safe (not inside blocks, not in lava, etc.) return level.getBlockState(new BlockPos(pos)).isAir() && level.getBlockState(new BlockPos(pos).above()).isAir(); } @Override public boolean isFoil(ItemStack stack) { return true; // Always show enchantment glint } }

Custom Tool Tiers

package com.yourname.yourmod.core.init; import net.minecraft.tags.BlockTags; import net.minecraft.world.item.Items; import net.minecraft.world.item.Tier; import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.common.ForgeTier; import java.util.function.Supplier; public class ModTiers { public static final Tier EXAMPLE = new ForgeTier( 3, // Harvest level (3 = diamond level) 1561, // Durability 8.0F, // Speed 3.0F, // Attack damage bonus 15, // Enchantability BlockTags.NEEDS_DIAMOND_TOOL, // Tag () -> Ingredient.of(ModItems.MAGIC_CRYSTAL.get()) // Repair material ); public static final Tier OBSIDIAN = new ForgeTier( 2, // Harvest level (2 = iron level) 250, // Durability 6.0F, // Speed 2.0F, // Attack damage bonus 14, // Enchantability BlockTags.NEEDS_IRON_TOOL, // Tag () -> Ingredient.of(Items.OBSIDIAN) // Repair material ); }

Custom Blocks

Block Registration

package com.yourname.yourmod.core.init; import com.yourname.yourmod.YourMod; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.material.Material; import net.minecraft.world.level.material.MaterialColor; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public class ModBlocks { public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, YourMod.MODID); // Basic Blocks public static final RegistryObject<Block> EXAMPLE_BLOCK = BLOCKS.register("example_block", () -> new Block(BlockBehaviour.Properties.of(Material.METAL, MaterialColor.COLOR_PURPLE) .strength(5.0f, 6.0f) .sound(SoundType.METAL) .requiresCorrectToolForDrops())); public static final RegistryObject<Block> MAGIC_ORE = BLOCKS.register("magic_ore", () -> new Block(BlockBehaviour.Properties.of(Material.STONE) .strength(3.0f, 3.0f) .sound(SoundType.STONE) .requiresCorrectToolForDrops() .lightLevel(state -> 7))); // Glowing ore // Functional Blocks public static final RegistryObject<Block> EXAMPLE_FURNACE = BLOCKS.register("example_furnace", () -> new ExampleFurnaceBlock(BlockBehaviour.Properties.of(Material.STONE) .strength(3.5f) .sound(SoundType.STONE) .requiresCorrectToolForDrops() .lightLevel(state -> state.getValue(ExampleFurnaceBlock.LIT) ? 13 : 0))); // Special Blocks public static final RegistryObject<Block> TELEPORTER_BLOCK = BLOCKS.register("teleporter_block", () -> new TeleporterBlock(BlockBehaviour.Properties.of(Material.METAL) .strength(4.0f, 6.0f) .sound(SoundType.METAL) .noOcclusion())); // Transparent block public static void register(IEventBus eventBus) { BLOCKS.register(eventBus); } }

Block Items Registration

package com.yourname.yourmod.core.init; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraftforge.registries.RegistryObject; import java.util.function.Supplier; public class ModBlockItems { // Helper method to register block items public static void registerBlockItems() { // Register block items for all blocks ModBlocks.BLOCKS.getEntries().forEach(blockRegistryObject -> { registerBlockItem(blockRegistryObject.getId().getPath(), blockRegistryObject); }); } private static void registerBlockItem(String name, Supplier<Block> block) { ModItems.ITEMS.register(name, () -> new BlockItem(block.get(), new Item.Properties().tab(YourMod.MOD_TAB))); } // Special block items with custom properties public static final RegistryObject<Item> TELEPORTER_BLOCK_ITEM = ModItems.ITEMS.register("teleporter_block", () -> new BlockItem(ModBlocks.TELEPORTER_BLOCK.get(), new Item.Properties() .tab(YourMod.MOD_TAB) .rarity(Rarity.UNCOMMON))); }

Custom Functional Block

package com.yourname.yourmod.blocks; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.phys.BlockHitResult; import org.jetbrains.annotations.Nullable; public class TeleporterBlock extends Block { public static final BooleanProperty ACTIVATED = BooleanProperty.create("activated"); public TeleporterBlock(Properties properties) { super(properties); this.registerDefaultState(this.stateDefinition.any().setValue(ACTIVATED, false)); } @Override protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { builder.add(ACTIVATED); } @Override public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) { if (!level.isClientSide()) { boolean hasRedstoneSignal = level.hasNeighborSignal(pos); if (hasRedstoneSignal != state.getValue(ACTIVATED)) { level.setBlock(pos, state.setValue(ACTIVATED, hasRedstoneSignal), 3); if (hasRedstoneSignal) { activateTeleporter(level, pos); } } } } private void activateTeleporter(Level level, BlockPos pos) { // Find all players within 10 blocks and teleport them level.getEntitiesOfClass(Player.class, new AABB(pos).inflate(10.0)).forEach(player -> { // Teleport player to a random nearby position BlockPos teleportPos = pos.offset( level.random.nextInt(21) - 10, // -10 to +10 X 0, level.random.nextInt(21) - 10 // -10 to +10 Z ); // Find safe Y position teleportPos = findSafeTeleportPosition(level, teleportPos); if (teleportPos != null) { player.teleportTo(teleportPos.getX() + 0.5, teleportPos.getY(), teleportPos.getZ() + 0.5); // Play teleport sound level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENDERMAN_TELEPORT, SoundSource.BLOCKS, 1.0F, 1.0F); // Add particle effects if (level instanceof ServerLevel serverLevel) { serverLevel.sendParticles(ParticleTypes.PORTAL, player.getX(), player.getY() + 1, player.getZ(), 50, 0.5, 1, 0.5, 0.1); } } }); } private BlockPos findSafeTeleportPosition(Level level, BlockPos pos) { // Find a safe position (air block with solid block below) for (int y = level.getMinBuildHeight(); y < level.getMaxBuildHeight(); y++) { BlockPos checkPos = new BlockPos(pos.getX(), y, pos.getZ()); if (level.getBlockState(checkPos).isAir() && !level.getBlockState(checkPos.below()).isAir()) { return checkPos; } } return null; } @Override public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) { if (state.getValue(ACTIVATED)) { // Spawn particles when activated for (int i = 0; i < 3; i++) { double x = pos.getX() + 0.5 + (random.nextDouble() - 0.5); double y = pos.getY() + 1.0; double z = pos.getZ() + 0.5 + (random.nextDouble() - 0.5); level.addParticle(ParticleTypes.REVERSE_PORTAL, x, y, z, 0, 0, 0); } } } }

World Generation

Custom Ore Generation

package com.yourname.yourmod.world; import com.yourname.yourmod.core.init.ModBlocks; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.data.worldgen.features.FeatureUtils; import net.minecraft.data.worldgen.features.OreFeatures; import net.minecraft.data.worldgen.placement.PlacementUtils; import net.minecraft.world.level.levelgen.VerticalAnchor; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration; import net.minecraft.world.level.levelgen.placement.*; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.RegistryObject; import java.util.List; public class ModWorldGeneration { public static final DeferredRegister<ConfiguredFeature<?, ?>> CONFIGURED_FEATURES = DeferredRegister.create(Registry.CONFIGURED_FEATURE_REGISTRY, YourMod.MODID); public static final DeferredRegister<PlacedFeature> PLACED_FEATURES = DeferredRegister.create(Registry.PLACED_FEATURE_REGISTRY, YourMod.MODID); // Configured Features public static final RegistryObject<ConfiguredFeature<?, ?>> ORE_MAGIC = CONFIGURED_FEATURES.register("ore_magic", () -> new ConfiguredFeature<>(Feature.ORE, new OreConfiguration( OreFeatures.STONE_ORE_REPLACEABLES, ModBlocks.MAGIC_ORE.get().defaultBlockState(), 9))); // Vein size // Placed Features public static final RegistryObject<PlacedFeature> ORE_MAGIC_PLACED = PLACED_FEATURES.register("ore_magic_placed", () -> new PlacedFeature(Holder.direct(ORE_MAGIC.get()), commonOrePlacement(7, // Veins per chunk HeightRangePlacement.triangle( VerticalAnchor.aboveBottom(-80), VerticalAnchor.absolute(80) )))); // Helper methods private static List<PlacementModifier> orePlacement(PlacementModifier count, PlacementModifier height) { return List.of(count, InSquarePlacement.spread(), height, BiomeFilter.biome()); } private static List<PlacementModifier> commonOrePlacement(int veinsPerChunk, PlacementModifier height) { return orePlacement(CountPlacement.of(veinsPerChunk), height); } public static void register(IEventBus eventBus) { CONFIGURED_FEATURES.register(eventBus); PLACED_FEATURES.register(eventBus); } }

Biome Modifiers

package com.yourname.yourmod.world; import com.mojang.serialization.Codec; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.levelgen.GenerationStep; import net.minecraft.world.level.levelgen.placement.PlacedFeature; import net.minecraftforge.common.world.BiomeModifier; import net.minecraftforge.common.world.ModifiableBiomeInfo; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public class ModBiomeModifiers { public static final DeferredRegister<Codec<? extends BiomeModifier>> BIOME_MODIFIERS = DeferredRegister.create(ForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, YourMod.MODID); public static final RegistryObject<Codec<AddOresBiomeModifier>> ADD_ORES_BIOME_MODIFIER = BIOME_MODIFIERS.register("add_ores", () -> AddOresBiomeModifier.CODEC); public record AddOresBiomeModifier(HolderSet<Biome> biomes, HolderSet<PlacedFeature> features) implements BiomeModifier { public static final Codec<AddOresBiomeModifier> CODEC = Codec... @Override public void modify(Holder<Biome> biome, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) { if (phase == Phase.ADD && this.biomes.contains(biome)) { this.features.forEach(feature -> builder.getGenerationSettings().addFeature(GenerationStep.Decoration.UNDERGROUND_ORES, feature)); } } @Override public Codec<? extends BiomeModifier> codec() { return CODEC; } } }

Event Handling

Event Handler Class

package com.yourname.yourmod.events; import com.yourname.yourmod.core.init.ModItems; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @Mod.EventBusSubscriber(modid = YourMod.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class EventHandler { @SubscribeEvent public static void onLivingHurt(LivingHurtEvent event) { // Example: Magic crystal provides damage reduction if (event.getEntity() instanceof Player player) { if (player.getInventory().contains(new ItemStack(ModItems.MAGIC_CRYSTAL.get()))) { // Reduce damage by 20% event.setAmount(event.getAmount() * 0.8f); } } } @SubscribeEvent public static void onRightClickBlock(PlayerInteractEvent.RightClickBlock event) { // Example: Special interaction with magic crystal Player player = event.getEntity(); ItemStack heldItem = player.getMainHandItem(); if (heldItem.getItem() == ModItems.MAGIC_CRYSTAL.get()) { // Prevent default action and do something special event.setCanceled(true); if (!player.level.isClientSide()) { // Spawn particles or do server-side logic player.level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.AMETHYST_BLOCK_CHIME, player.getSoundSource(), 1.0F, 1.0F); } } } @SubscribeEvent public static void onBlockBreak(BlockEvent.BreakEvent event) { // Example: Special drops when breaking blocks with example pickaxe Player player = event.getPlayer(); if (player.getMainHandItem().getItem() == ModItems.EXAMPLE_PICKAXE.get()) { // Chance to drop extra items if (event.getState().getBlock() == Blocks.DIAMOND_ORE) { if (player.level.random.nextFloat() < 0.1f) { // 10% chance popResource(player.level, event.getPos(), new ItemStack(ModItems.MAGIC_CRYSTAL.get())); } } } } @SubscribeEvent public static void onPlayerTick(net.minecraftforge.event.TickEvent.PlayerTickEvent event) { // Example: Continuous effects for players holding specific items if (event.phase == net.minecraftforge.event.TickEvent.Phase.END) { Player player = event.player; ItemStack mainHand = player.getMainHandItem(); if (mainHand.getItem() == ModItems.TELEPORT_STAFF.get()) { // Give player slow falling while holding teleport staff player.addEffect(new MobEffectInstance(MobEffects.SLOW_FALLING, 40, 0, true, false)); } } } }

Custom Entities

Entity Registration

package com.yourname.yourmod.core.init; import com.yourname.yourmod.YourMod; import com.yourname.yourmod.entities.ExampleEntity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobCategory; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public class ModEntities { public static final DeferredRegister<EntityType<?>> ENTITIES = DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, YourMod.MODID); public static final RegistryObject<EntityType<ExampleEntity>> EXAMPLE_ENTITY = ENTITIES.register("example_entity", () -> EntityType.Builder.of(ExampleEntity::new, MobCategory.MONSTER) .sized(0.6f, 1.95f) // Width, Height .clientTrackingRange(8) .build("example_entity")); public static void register(IEventBus eventBus) { ENTITIES.register(eventBus); } }

Custom Entity Class

package com.yourname.yourmod.entities; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.goal.*; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; public class ExampleEntity extends Monster { public ExampleEntity(EntityType<? extends Monster> type, Level level) { super(type, level); } public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes() .add(Attributes.MAX_HEALTH, 30.0D) .add(Attributes.MOVEMENT_SPEED, 0.3D) .add(Attributes.ATTACK_DAMAGE, 5.0D) .add(Attributes.ARMOR, 2.0D) .add(Attributes.FOLLOW_RANGE, 25.0D); } @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2D, false)); this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D)); this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } @Override protected SoundEvent getAmbientSound() { return SoundEvents.ENDERMAN_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource damageSource) { return SoundEvents.ENDERMAN_HURT; } @Override protected SoundEvent getDeathSound() { return SoundEvents.ENDERMAN_DEATH; } @Override public void aiStep() { super.aiStep(); // Custom AI behavior - spawn particles occasionally if (this.level.isClientSide && this.random.nextInt(100) == 0) { for (int i = 0; i < 2; i++) { this.level.addParticle(ParticleTypes.PORTAL, this.getRandomX(0.5D), this.getRandomY(), this.getRandomZ(0.5D), (this.random.nextDouble() - 0.5D) * 2.0D, -this.random.nextDouble(), (this.random.nextDouble() - 0.5D) * 2.0D); } } } }

Networking

Packet Handling

package com.yourname.yourmod.network; import com.yourname.yourmod.YourMod; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.network.NetworkDirection; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.PacketDistributor; import net.minecraftforge.network.simple.SimpleChannel; public class ModNetwork { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(YourMod.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); private static int packetId = 0; public static void register() { // Register packets here // CHANNEL.registerMessage(packetId++, ExamplePacket.class, ExamplePacket::encode, ExamplePacket::decode, ExamplePacket::handle); } public static <MSG> void sendToServer(MSG message) { CHANNEL.sendToServer(message); } public static <MSG> void sendToPlayer(MSG message, ServerPlayer player) { CHANNEL.send(PacketDistributor.PLAYER.with(() -> player), message); } public static <MSG> void sendToAllPlayers(MSG message) { CHANNEL.send(PacketDistributor.ALL.noArg(), message); } }

Data Generation

Recipe Provider

package com.yourname.yourmod.datagen; import com.yourname.yourmod.core.init.ModBlocks; import com.yourname.yourmod.core.init.ModItems; import net.minecraft.data.DataGenerator; import net.minecraft.data.recipes.FinishedRecipe; import net.minecraft.data.recipes.RecipeProvider; import net.minecraft.data.recipes.ShapedRecipeBuilder; import net.minecraft.data.recipes.ShapelessRecipeBuilder; import net.minecraft.world.item.Items; import net.minecraftforge.common.crafting.conditions.IConditionBuilder; import java.util.function.Consumer; public class ModRecipeProvider extends RecipeProvider implements IConditionBuilder { public ModRecipeProvider(DataGenerator generator) { super(generator); } @Override protected void buildCraftingRecipes(Consumer<FinishedRecipe> consumer) { // Shaped Recipes ShapedRecipeBuilder.shaped(ModItems.EXAMPLE_ITEM.get()) .pattern("###") .pattern("#X#") .pattern("###") .define('#', Items.STONE) .define('X', Items.DIAMOND) .unlockedBy("has_diamond", has(Items.DIAMOND)) .save(consumer); ShapedRecipeBuilder.shaped(ModBlocks.EXAMPLE_BLOCK.get()) .pattern("##") .pattern("##") .define('#', ModItems.EXAMPLE_ITEM.get()) .unlockedBy("has_example_item", has(ModItems.EXAMPLE_ITEM.get())) .save(consumer); // Shapeless Recipes ShapelessRecipeBuilder.shapeless(ModItems.MAGIC_CRYSTAL.get()) .requires(Items.DIAMOND) .requires(Items.ENDER_PEARL) .requires(Items.GLOWSTONE_DUST) .unlockedBy("has_diamond", has(Items.DIAMOND)) .save(consumer); // Tool Recipes ShapedRecipeBuilder.shaped(ModItems.EXAMPLE_SWORD.get()) .pattern("X") .pattern("X") .pattern("#") .define('X', ModItems.MAGIC_CRYSTAL.get()) .define('#', Items.STICK) .unlockedBy("has_magic_crystal", has(ModItems.MAGIC_CRYSTAL.get())) .save(consumer); } }

Language Provider

package com.yourname.yourmod.datagen; import com.yourname.yourmod.core.init.ModBlocks; import com.yourname.yourmod.core.init.ModItems; import net.minecraft.data.DataGenerator; import net.minecraftforge.common.data.LanguageProvider; public class ModLanguageProvider extends LanguageProvider { public ModLanguageProvider(DataGenerator gen, String locale) { super(gen, YourMod.MODID, locale); } @Override protected void addTranslations() { // Items add(ModItems.EXAMPLE_ITEM.get(), "Example Item"); add(ModItems.MAGIC_CRYSTAL.get(), "Magic Crystal"); add(ModItems.EXAMPLE_SWORD.get(), "Example Sword"); add(ModItems.TELEPORT_STAFF.get(), "Teleport Staff"); // Blocks add(ModBlocks.EXAMPLE_BLOCK.get(), "Example Block"); add(ModBlocks.MAGIC_ORE.get(), "Magic Ore"); add(ModBlocks.TELEPORTER_BLOCK.get(), "Teleporter Block"); // Creative Tab add("itemGroup.yourmod", "Your Mod"); // Tooltips add("item.yourmod.teleport_staff.tooltip", "Right-click to teleport forward"); add("item.yourmod.magic_crystal.tooltip", "Provides damage reduction when in inventory"); // Messages add("message.yourmod.welcome", "Welcome to Your Mod!"); } }

Complete Mod Class Integration

Updated Main Mod Class

package com.yourname.yourmod; import com.yourname.yourmod.core.init.*; import com.yourname.yourmod.network.ModNetwork; import com.yourname.yourmod.world.ModWorldGeneration; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @Mod(YourMod.MODID) public class YourMod { public static final String MODID = "yourmod"; public static final String NAME = "Your Awesome Mod"; public static final String VERSION = "1.0.0"; public static final Logger LOGGER = LogManager.getLogger(); public YourMod() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); IEventBus forgeEventBus = MinecraftForge.EVENT_BUS; // Register registries ModItems.register(modEventBus); ModBlocks.register(modEventBus); ModEntities.register(modEventBus); ModBlockItems.registerBlockItems(); // Register world generation ModWorldGeneration.register(modEventBus); // Register configuration ModConfig.register(); // Register event listeners modEventBus.addListener(this::commonSetup); forgeEventBus.register(this); LOGGER.info("{} v{} initialized!", NAME, VERSION); } private void commonSetup(final FMLCommonSetupEvent event) { event.enqueueWork(() -> { // Post-registration setup ModNetwork.register(); // Register entity attributes ModEntities.registerAttributes(); }); LOGGER.info("Common setup completed for {}", NAME); } // Creative tab remains the same... }

Deployment

mods.toml Configuration

modLoader="javafml" loaderVersion="[43,)" license="MIT" [[mods]] modId="yourmod" version="1.0.0" displayName="Your Awesome Mod" description=''' A fantastic mod that adds awesome features to Minecraft! ''' authors="YourName" credits="Thanks to the Forge team" [[dependencies.yourmod]] modId="forge" mandatory=true versionRange="[43.2.0,)" ordering="NONE" side="BOTH" [[dependencies.yourmod]] modId="minecraft" mandatory=true versionRange="[1.19.2,1.20)" ordering="NONE" side="BOTH"

Summary

This comprehensive Minecraft Forge modding guide covers:

  1. Project Setup: Gradle configuration and environment setup
  2. Core Structure: Main mod class and configuration system
  3. Custom Items: Basic items, tools, food, and special items with custom behavior
  4. Custom Blocks: Basic blocks, functional blocks, and block entities
  5. World Generation: Ore generation and biome modifiers
  6. Event Handling: Player interactions, block breaking, and entity events
  7. Custom Entities: Monster entities with custom AI and attributes
  8. Networking: Packet system for client-server communication
  9. Data Generation: Recipes, language files, and other data
  10. Deployment: Final configuration and packaging

The mod is production-ready and demonstrates best practices for Minecraft Forge mod development, including proper registration, configuration management, and event handling.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper