agentsclimarketplace

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

Install
npx -y skills add PSB1234/Fabric-Minecraft-Skill-1.20.1 --skill fabric-mc-modding

Assembled 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

ComponentVersion for 1.20.1
Java17
Gradle8.x (via wrapper)
Fabric Loom1.3.x
Fabric Loader0.14.x / 0.15.x
Fabric API0.83.x+1.20.1
Yarn Mappings1.20.1+build.10 (or latest)
Mixin compatJAVA_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 vanilla Item.Settings) for extra Fabric hooks like equippable, customDamage, etc. Vanilla Item.Settings also 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 valueWhen 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-events skill 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:

  1. 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;
  1. Add to build.gradle:
loom {
    accessWidenerPath = file("src/main/resources/mymod.accesswidener")
}
  1. 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#worldprivate. Use entity.getWorld() or entity.getServerWorld().
  • Material class removed. Use AbstractBlock.Settings.create().mapColor(...).pistonBehavior(...).
  • DrawHelper → replaced by DrawContext passed into render methods.
  • BlockState solid 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

TaskPurpose
./gradlew buildCompile & package the mod jar
./gradlew runClientLaunch Minecraft client in dev
./gradlew runServerLaunch dedicated server in dev
./gradlew genSourcesGenerate decompiled Minecraft source for reference
./gradlew runDatagenRun data generators
./gradlew cleanloomClear Loom cache (fixes many weird build errors)
./gradlew --stopKill Gradle daemon (fixes some daemon issues)

Debugging Tips

  • Crash on startup: Check fabric.mod.json entrypoint class names match exactly.
  • Mixin not applying: Verify the class is listed in mymod.mixins.json in the correct array (mixins, client, or server). @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 during onInitialize, 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>:

ScriptWhat it does
scripts/scaffold_mod.pyGenerate a complete new mod project (all boilerplate files)
scripts/add_block.pyAdd a new block (Java class + all JSON assets + tag file)
scripts/add_item.pyAdd 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/:

FileUse for
assets/fabric.mod.jsonStarting point for fabric.mod.json
assets/gradle.propertiesVersion-pinned gradle.properties for 1.20.1
assets/MODID.mixins.jsonMixin config skeleton

Further References

What ships with it: 6 files

20.2 KB alongside SKILL.md, 3 of them executable

scripts/

Keep looking

Skills are one crate of 326,861. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.