Getting Started with Fabric
Why Choose Fabric?
Fabric offers several advantages for Minecraft modding:
- Lightweight - Fabric has a minimal core that loads quickly and efficiently
- Modular - The API is split into modules that can be used independently
- Fast updates - Fabric typically updates to new Minecraft versions very quickly
- Modern codebase - Built with modern Java features and practices
- Growing ecosystem - A vibrant community creating libraries and mods
Setting Up Your Development Environment
Setting up for Fabric development is straightforward:
- Install Java Development Kit (JDK) 17 or higher
Fabric requires JDK 17 or higher for the latest versions. Download it from Adoptium or Oracle.
- Choose an IDE
We recommend IntelliJ IDEA or Eclipse for Java development.
- Use the Fabric Template Mod
The easiest way to get started is to use the Fabric Example Mod as a template.
- Set up Gradle
Fabric uses Gradle for building mods. The template mod already includes the necessary Gradle configuration.
build.gradle (Fabric Mod)1234567891011121314151617181920// build.gradle plugins { id 'fabric-loom' version '1.3-SNAPSHOT' id 'maven-publish' } version = project.mod_version group = project.maven_group repositories { // Add repositories for dependencies here } dependencies { // Minecraft and Fabric API minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" }
Fabric Mod Basics
Mod Structure
A basic Fabric mod consists of the following components:
- fabric.mod.json - The mod metadata file
- Main mod class - The entry point for your mod
- Mixin classes - For modifying Minecraft's code
- Resources - Textures, models, and other assets
Here's an example of a fabric.mod.json file:
{
"schemaVersion": 1,
"id": "example-mod",
"version": "${version}",
"name": "Example Mod",
"description": "This is an example mod for Fabric!",
"authors": [
"Your Name"
],
"contact": {
"homepage": "https://example.com/",
"sources": "https://github.com/yourusername/example-mod"
},
"license": "MIT",
"icon": "assets/example-mod/icon.png",
"environment": "*",
"entrypoints": {
"main": [
"com.example.examplemod.ExampleMod"
],
"client": [
"com.example.examplemod.ExampleModClient"
]
},
"mixins": [
"example-mod.mixins.json"
],
"depends": {
"fabricloader": ">=0.14.21",
"minecraft": "~1.20.1",
"java": ">=17",
"fabric-api": "*"
}
}
Main Mod Class
The main class is the entry point for your mod. Here's a simple example:
package com.example.examplemod;
import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExampleMod implements ModInitializer {
// Create a logger
public static final Logger LOGGER = LoggerFactory.getLogger("example-mod");
@Override
public void onInitialize() {
// This code runs when your mod is initialized
LOGGER.info("Example mod initialized!");
// Register items, blocks, etc. here
}
}
Registering Items and Blocks
Here's how to register a custom item in Fabric:
package com.example.examplemod;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExampleMod implements ModInitializer {
public static final Logger LOGGER = LoggerFactory.getLogger("example-mod");
// Define your custom item
public static final Item CUSTOM_ITEM = new Item(new FabricItemSettings());
@Override
public void onInitialize() {
LOGGER.info("Example mod initialized!");
// Register the custom item
Registry.register(
Registries.ITEM,
new Identifier("example-mod", "custom_item"),
CUSTOM_ITEM
);
}
}
Advanced Fabric Concepts
Using Mixins
Mixins are a powerful way to modify Minecraft's code without directly editing it. Here's a simple example:
package com.example.examplemod.mixin;
import net.minecraft.client.gui.screen.TitleScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class)
public class TitleScreenMixin {
@Inject(at = @At("HEAD"), method = "init()V")
private void init(CallbackInfo info) {
System.out.println("This line is printed by an example mod mixin!");
}
}
You also need to configure your mixins in a JSON file:
{
"required": true,
"minVersion": "0.8",
"package": "com.example.examplemod.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"client": [
"TitleScreenMixin"
],
"injectors": {
"defaultRequire": 1
}
}
Networking in Fabric
Fabric provides a simple API for networking between client and server:
// Server-side registration
public static final Identifier EXAMPLE_PACKET_ID = new Identifier("example-mod", "example_packet");
// Register the packet in your mod initializer
ServerPlayNetworking.registerGlobalReceiver(EXAMPLE_PACKET_ID, (server, player, handler, buf, responseSender) -> {
// Read data from the packet
String message = buf.readString(32767);
// Execute on the server thread
server.execute(() -> {
System.out.println("Received message from client: " + message);
});
});
// Client-side sending
public void sendExamplePacket() {
PacketByteBuf buf = PacketByteBufs.create();
buf.writeString("Hello from the client!");
ClientPlayNetworking.send(EXAMPLE_PACKET_ID, buf);
}
Config Files
Fabric doesn't have a built-in config system, but you can use libraries like Cloth Config or create your own:
// Using Cloth Config with TOML
public class ModConfig {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final File CONFIG_FILE = new File("config/example-mod.json");
public static ModConfigData CONFIG = new ModConfigData();
public static class ModConfigData {
public boolean enableFeature = true;
public int cooldownTicks = 20;
public String welcomeMessage = "Hello, world!";
}
public static void load() {
try {
if (CONFIG_FILE.exists()) {
BufferedReader reader = new BufferedReader(new FileReader(CONFIG_FILE));
CONFIG = GSON.fromJson(reader, ModConfigData.class);
} else {
save(); // Create default config
}
} catch (Exception e) {
System.err.println("Error loading config: " + e.getMessage());
}
}
public static void save() {
try {
if (!CONFIG_FILE.getParentFile().exists()) {
CONFIG_FILE.getParentFile().mkdirs();
}
FileWriter writer = new FileWriter(CONFIG_FILE);
GSON.toJson(CONFIG, writer);
writer.close();
} catch (Exception e) {
System.err.println("Error saving config: " + e.getMessage());
}
}
}