agentsclimarketplace

Fabric config

Skill PSB1234/Fabric-Minecraft-Skill-1.20.1/fabric-config

Reference for mod configuration in Fabric Minecraft 1.20.1 — using Cloth Config API for GUI-based config screens, and plain TOML/JSON files with a custom serializer. Use this skill whenever the user asks about mod config, settings file, config screen, Cloth Config, ClothConfigScreen, AutoConfig, TOML config, JSON config, persistent mod settings, or config GUI. Triggers on: "mod config", "config file", "config screen", "Cloth Config", "ClothConfigScreen", "AutoConfig", "TOML", "settings screen", "config serializer", "persistent settings", or "mod options". Part of the fabric-mc-modding skill family.From its SKILL.md

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

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

7.6 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

Fabric Config — 1.20.1 Reference

Two common approaches are covered here:

  1. Cloth Config + AutoConfig — GUI config screen with minimal boilerplate (recommended)
  2. Manual JSON/TOML — plain file-based config without a GUI dependency

Option A: Cloth Config + AutoConfig (Recommended)

1. Add dependency

build.gradle:

repositories {
    maven { url "https://maven.shedaniel.me/" }
    maven { url "https://maven.terraformersmc.com/releases/" }
}

dependencies {
    // Cloth Config
    modApi("me.shedaniel.cloth:cloth-config-fabric:11.1.136") {
        exclude(group: "net.fabricmc.fabric-api")
    }
    // Optional: ModMenu integration (shows config button in mod list)
    modImplementation "com.terraformersmc:modmenu:7.2.2"
}

gradle.properties — increment if you need newer versions:

cloth_config_version=11.1.136
modmenu_version=7.2.2

Include as JiJ (jar-in-jar) if you want to bundle it:

include("me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}")

2. Config class

@Config(name = "mymod")  // generates mymod.json in .minecraft/config/
public class MyConfig implements ConfigData {

    // These are the actual config values with defaults
    public boolean enableFeature = true;
    public int    maxItems       = 64;
    public float  damageMultiplier = 1.5f;
    public String serverUrl     = "example.com";
    public List<String> allowedPlayers = new ArrayList<>();

    // Bounds validation (Cloth Config respects these for sliders/fields)
    @ConfigEntry.BoundedDiscrete(min = 1, max = 256)
    public int tickRate = 20;

    @ConfigEntry.ColorPicker
    public int highlightColor = 0xFF00FF;

    // Nested category
    @ConfigEntry.Category("advanced")
    public boolean debugMode = false;
}

3. Register and load

// In onInitialize() — do this before anything reads config values
public class MyMod implements ModInitializer {

    public static MyConfig CONFIG;

    @Override
    public void onInitialize() {
        AutoConfig.register(MyConfig.class, GsonConfigSerializer::new);
        CONFIG = AutoConfig.getConfigHolder(MyConfig.class).getConfig();
        // Now access config via MyMod.CONFIG.enableFeature etc.
    }
}

4. ModMenu integration (optional, shows "Config" button)

Create src/main/java/com/example/mymod/ModMenuIntegration.java:

public class ModMenuIntegration implements ModMenuApi {
    @Override
    public ConfigScreenFactory<?> getModConfigScreenFactory() {
        return parent -> AutoConfig.getConfigScreen(MyConfig.class, parent).get();
    }
}

Register the entrypoint in fabric.mod.json:

{
  "entrypoints": {
    "modmenu": ["com.example.mymod.ModMenuIntegration"]
  }
}

5. Saving config programmatically

// After modifying config values at runtime:
AutoConfig.getConfigHolder(MyConfig.class).save();

Option B: Manual JSON Config (No GUI)

Simple, zero-dependency approach using Gson:

Config class

public class ModConfig {
    public boolean enableFeature = true;
    public int maxItems = 64;
    public float damageMultiplier = 1.5f;
    public String serverUrl = "example.com";
}

Config manager

public class ConfigManager {

    private static final Path CONFIG_PATH =
        FabricLoader.getInstance().getConfigDir().resolve("mymod.json");
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();

    public static ModConfig config = new ModConfig(); // holds defaults

    public static void load() {
        if (Files.exists(CONFIG_PATH)) {
            try (Reader reader = Files.newBufferedReader(CONFIG_PATH)) {
                config = GSON.fromJson(reader, ModConfig.class);
                if (config == null) config = new ModConfig();
            } catch (IOException e) {
                MyMod.LOGGER.error("Failed to load config", e);
                config = new ModConfig();
            }
        } else {
            save(); // write defaults on first run
        }
    }

    public static void save() {
        try {
            Files.createDirectories(CONFIG_PATH.getParent());
            try (Writer writer = Files.newBufferedWriter(CONFIG_PATH)) {
                GSON.toJson(config, writer);
            }
        } catch (IOException e) {
            MyMod.LOGGER.error("Failed to save config", e);
        }
    }
}

Call in onInitialize():

ConfigManager.load();
// Access: ConfigManager.config.enableFeature

Option C: Night Config (TOML files)

For TOML format with comments:

// build.gradle
dependencies {
    implementation("com.electronwill.night-config:toml:3.6.7")
    include("com.electronwill.night-config:toml:3.6.7")
    include("com.electronwill.night-config:core:3.6.7")
}
public class TomlConfig {

    private static final Path CONFIG_FILE =
        FabricLoader.getInstance().getConfigDir().resolve("mymod.toml");

    public static boolean enableFeature = true;
    public static int     maxItems      = 64;

    public static void load() {
        CommentedFileConfig config = CommentedFileConfig.builder(CONFIG_FILE.toFile())
            .sync()
            .autosave()
            .preserveInsertionOrder()
            .build();
        config.load();

        // Read with defaults
        enableFeature = config.getOrElse("general.enable_feature", true);
        maxItems      = config.getOrElse("general.max_items", 64);

        // Write back (creates file with values on first run)
        config.setComment("general.enable_feature", "Whether the feature is enabled");
        config.set("general.enable_feature", enableFeature);
        config.set("general.max_items", maxItems);
        config.save();
    }
}

Accessing Config Dir

Path configDir = FabricLoader.getInstance().getConfigDir();
// On client: .minecraft/config/
// On server: server-root/config/

Common Patterns

Read-only config (load once, never save at runtime)

  • Load in onInitialize(), use throughout.

Reloadable config (support /reload)

  • Listen to ServerLifecycleEvents.END_DATA_PACK_RELOAD and call load() again.

Per-player config

  • Store in NBT on the player entity or in a separate file per UUID.

Common Mistakes

  • Cloth Config version mismatch — check https://modrinth.com/mod/cloth-config for the latest 1.20.1-compatible version.
  • CONFIG is null at startupAutoConfig.register() must run before getConfig().
  • GSON deserializes null — always null-check or assign a new default instance if fromJson returns null.
  • Config not persisting across runs — ensure save() is called after any runtime changes.

Further Reading

Related Skills

  • fabric-mc-modding — project setup
  • fabric-commands — exposing config values via commands

What ships with it

Read from the repository

Just SKILL.md. No reference files, no 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.