Fabric mc modding
Skill PSB1234/Fabric-Minecraft-Skill-1.20.1/fabric-mc-modding
Expert guidance for creating and modifying Minecraft mods using the Fabric toolchain targeting Minecraft 1.20.1. Use this skill whenever the user asks about Fabric modding, writing mod code, setting up a Fabric project, registering blocks or items, using Mixins, handling events, creating custom entities, data generation, or any Minecraft 1.20.1 mod development task. Trigger even for partial phrases like "fabric mod", "minecraft mod", "mixin", "fabric API", "mod initializer", or when the user shares Java code that references Minecraft or Fabric classes.From its SKILL.md
npx -y skills add PSB1234/Fabric-Minecraft-Skill-1.20.1 --skill fabric-mc-moddingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
12.8 KB, ~3.2k tokens by cl100k_base, as published. Nobody here has run it
Fabric Minecraft 1.20.1 Modding Skill
Environment & Version Pins
| Component | Version for 1.20.1 |
|---|---|
| Java | 17 |
| Gradle | 8.x (via wrapper) |
| Fabric Loom | 1.3.x |
| Fabric Loader | 0.14.x / 0.15.x |
| Fabric API | 0.83.x+1.20.1 |
| Yarn Mappings | 1.20.1+build.10 (or latest) |
| Mixin compat | JAVA_17 |
Always check https://fabricmc.net/develop/ for the latest compatible versions.
Project Structure
my-mod/
├── build.gradle
├── gradle.properties
├── settings.gradle
├── src/main/
│ ├── java/com/example/mymod/
│ │ ├── MyMod.java ← ModInitializer (server+client)
│ │ ├── MyModClient.java ← ClientModInitializer
│ │ ├── block/ ← Custom block classes
│ │ ├── item/ ← Custom item classes
│ │ ├── entity/ ← Custom entity classes
│ │ └── mixin/ ← ALL mixin classes here (nothing else)
│ └── resources/
│ ├── fabric.mod.json
│ ├── mymod.mixins.json
│ └── assets/mymod/ ← Textures, models, lang files
│ ├── lang/en_us.json
│ ├── models/item/
│ ├── models/block/
│ └── textures/
gradle.properties (1.20.1 example)
minecraft_version=1.20.1
yarn_mappings=1.20.1+build.10
loader_version=0.15.11
fabric_version=0.92.2+1.20.1
mod_version=1.0.0
maven_group=com.example
archives_base_name=mymod
build.gradle (key parts)
plugins {
id 'fabric-loom' version '1.3-SNAPSHOT'
id 'maven-publish'
}
java.sourceCompatibility = JavaVersion.VERSION_17
dependencies {
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}"
}
tasks.withType(JavaCompile).configureEach {
it.options.release = 17
}
fabric.mod.json
{
"schemaVersion": 1,
"id": "mymod",
"version": "${version}",
"name": "My Mod",
"description": "Does cool things.",
"authors": ["YourName"],
"license": "MIT",
"environment": "*",
"entrypoints": {
"main": ["com.example.mymod.MyMod"],
"client": ["com.example.mymod.MyModClient"]
},
"mixins": ["mymod.mixins.json"],
"depends": {
"fabricloader": ">=0.14.0",
"fabric-api": "*",
"minecraft": "~1.20.1",
"java": ">=17"
}
}
Mod Initializer
public class MyMod implements ModInitializer {
public static final String MOD_ID = "mymod";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@Override
public void onInitialize() {
ModItems.register();
ModBlocks.register();
LOGGER.info("MyMod loaded!");
}
}
Client-side initializer (rendering, key bindings, etc.):
public class MyModClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
// Register client-only things here
}
}
Registering Items
public class ModItems {
public static final Item MY_ITEM = new Item(new FabricItemSettings());
public static void register() {
Registry.register(Registries.ITEM, new Identifier("mymod", "my_item"), MY_ITEM);
}
}
1.20.1 note: Use
FabricItemSettings(not the vanillaItem.Settings) for extra Fabric hooks likeequippable,customDamage, etc. VanillaItem.Settingsalso works for basic items.
Registering Blocks
public class ModBlocks {
public static final Block MY_BLOCK = new Block(
FabricBlockSettings.create()
.hardness(2.0f)
.resistance(3.0f)
.requiresTool()
);
public static void register() {
Registry.register(Registries.BLOCK, new Identifier("mymod", "my_block"), MY_BLOCK);
// Also register the block item:
Registry.register(Registries.ITEM,
new Identifier("mymod", "my_block"),
new BlockItem(MY_BLOCK, new FabricItemSettings())
);
}
}
Mixins
mymod.mixins.json
{
"required": true,
"minVersion": "0.8",
"package": "com.example.mymod.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [],
"client": ["TitleScreenMixin"],
"server": [],
"injectors": { "defaultRequire": 1 }
}
Example @Inject
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin {
@Inject(at = @At("HEAD"), method = "onDeath")
private void onDeath(DamageSource source, CallbackInfo ci) {
// runs at the start of LivingEntity#onDeath
}
}
Common injection points
@At value | When it fires |
|---|---|
"HEAD" | Top of method |
"RETURN" | Before each return |
"TAIL" | Before the final return |
"INVOKE" | Before a specific method call (needs target =) |
Cancelling execution
// Change CallbackInfo to CallbackInfoReturnable<T> for methods with return values
@Inject(at = @At("HEAD"), method = "method", cancellable = true)
private void myHook(CallbackInfo ci) {
ci.cancel(); // prevents rest of method from running
}
@Redirect — replace a method call
@Redirect(at = @At(value = "INVOKE",
target = "Lnet/minecraft/entity/LivingEntity;heal(F)V"),
method = "someMethod")
private void redirectHeal(LivingEntity entity, float amount) {
entity.heal(amount * 2); // double all healing
}
Accessor / Invoker — access private fields or methods
@Mixin(PlayerEntity.class)
public interface PlayerEntityAccessor {
@Accessor("hungerManager")
HungerManager getHungerManager();
}
Fabric Events (prefer over mixins where possible)
📖 See the
fabric-eventsskill for the full event reference — all event classes, signatures, ActionResult values, custom event creation, and a quick-picker table. Load it whenever the user asks about listening to game events, callbacks, or hooking into game logic without a Mixin.
Quick examples to get started:
// Server tick
ServerTickEvents.END_SERVER_TICK.register(server -> { /* runs every tick */ });
// Player join / leave
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { });
// Cancel a block break (return false to cancel)
PlayerBlockBreakEvents.BEFORE.register((world, player, pos, state, entity) -> true);
// Item right-click
UseItemCallback.EVENT.register((player, world, hand) ->
TypedActionResult.pass(player.getStackInHand(hand)));
For the complete list — tick, lifecycle, entity, loot, screen, command, HUD, and custom
events — load the fabric-events skill.
Access Wideners
When you need to access a private or final class/field/method without a mixin:
- Create
src/main/resources/mymod.accesswidener:
accessWidener v2 named
accessible field net/minecraft/entity/LivingEntity bodyYaw F
mutable field net/minecraft/entity/LivingEntity bodyYaw F
accessible method net/minecraft/server/network/ServerPlayerEntity getServer ()Lnet/minecraft/server/MinecraftServer;
- Add to
build.gradle:
loom {
accessWidenerPath = file("src/main/resources/mymod.accesswidener")
}
- Reference it in
fabric.mod.json:
"accessWidener": "mymod.accesswidener"
Networking (1.20.1 — old packet API)
Note: 1.20.1 uses the pre-1.20.5 networking API. The new API arrived in 1.20.5.
// Define packet ID
public static final Identifier MY_PACKET = new Identifier("mymod", "my_packet");
// Server → Client send
PacketByteBuf buf = PacketByteBufs.create();
buf.writeInt(42);
ServerPlayNetworking.send(serverPlayer, MY_PACKET, buf);
// Client-side receive
ClientPlayNetworking.registerGlobalReceiver(MY_PACKET, (client, handler, buf, responseSender) -> {
int value = buf.readInt();
client.execute(() -> { /* update client state */ });
});
Data Generation
public class MyDataGenerator implements DataGeneratorEntrypoint {
@Override
public void onInitializeDataGenerator(FabricDataGenerator generator) {
FabricDataGenerator.Pack pack = generator.createPack();
pack.addProvider(MyBlockTagProvider::new);
pack.addProvider(MyLootTableProvider::new);
pack.addProvider(MyRecipeProvider::new);
pack.addProvider(MyModelProvider::new);
}
}
Add entrypoint to fabric.mod.json:
"fabric-datagen": ["com.example.mymod.datagen.MyDataGenerator"]
Run with: ./gradlew runDatagen
Common 1.20.1 API Changes (vs older versions)
Entity#world→ private. Useentity.getWorld()orentity.getServerWorld().Materialclass removed. UseAbstractBlock.Settings.create().mapColor(...).pistonBehavior(...).DrawHelper→ replaced byDrawContextpassed into render methods.BlockStatesolid check now automatic — only override with.solid()/.notSolid()in settings when needed.- Registry sync bug fix: clients must have the same content mods as the server.
Required Resources for a Block
assets/mymod/
blockstates/my_block.json ← maps BlockState variants → models
models/block/my_block.json ← model definition
models/item/my_block.json ← item model (usually parents block model)
textures/block/my_block.png ← 16×16 PNG texture
lang/en_us.json ← "block.mymod.my_block": "My Block"
Gradle Tasks Reference
| Task | Purpose |
|---|---|
./gradlew build | Compile & package the mod jar |
./gradlew runClient | Launch Minecraft client in dev |
./gradlew runServer | Launch dedicated server in dev |
./gradlew genSources | Generate decompiled Minecraft source for reference |
./gradlew runDatagen | Run data generators |
./gradlew cleanloom | Clear Loom cache (fixes many weird build errors) |
./gradlew --stop | Kill Gradle daemon (fixes some daemon issues) |
Debugging Tips
- Crash on startup: Check
fabric.mod.jsonentrypoint class names match exactly. - Mixin not applying: Verify the class is listed in
mymod.mixins.jsonin the correct array (mixins,client, orserver).@At("INVOKE")target descriptors must use/not.in class names. - Missing textures: File paths are case-sensitive on Linux. Check
blockstates/json references model paths correctly. - Registry errors: All
Registry.register()calls must happen duringonInitialize, not lazily. - IntelliJ run configs missing: Run
./gradlew ideaSyncTask, or set "Build and run using" → Gradle in IntelliJ Gradle settings.
Scripts
This skill ships executable scripts. Run them with python <script>:
| Script | What it does |
|---|---|
scripts/scaffold_mod.py | Generate a complete new mod project (all boilerplate files) |
scripts/add_block.py | Add a new block (Java class + all JSON assets + tag file) |
scripts/add_item.py | Add a new item (Java class or snippet + model JSON) |
# Create a brand-new mod project
python scripts/scaffold_mod.py --mod-id mymod --name "My Mod" --group com.example --output ./mymod
# Add a block to an existing project
python scripts/add_block.py --mod-id mymod --group com.example --block-id ruby_block --hardness 3.0 --tool pickaxe
# Add a custom item
python scripts/add_item.py --mod-id mymod --group com.example --item-id ruby --type basic
Assets (Templates)
Copy-paste ready template files in assets/:
| File | Use for |
|---|---|
assets/fabric.mod.json | Starting point for fabric.mod.json |
assets/gradle.properties | Version-pinned gradle.properties for 1.20.1 |
assets/MODID.mixins.json | Mixin config skeleton |
Further References
- Fabric Docs: https://docs.fabricmc.net/develop/
- Fabric Wiki: https://wiki.fabricmc.net/
- Version picker: https://fabricmc.net/develop/
- Fabric API source: https://github.com/FabricMC/fabric
- Example mod (1.20 branch): https://github.com/FabricMC/fabric-example-mod/tree/1.20
What ships with it: 6 files
20.2 KB alongside SKILL.md, 3 of them executable
assets/
- fabric.mod.json518 B
- gradle.properties381 B
- MODID.mixins.json206 B
scripts/
- add_block.pyruns5.8 KB
- add_item.pyruns5.4 KB
- scaffold_mod.pyruns7.9 KB