Add config.yml handling
Wire up first-run defaults, typed reads, and a reload path, matching the project's stack and
conventions. Follow the collaborative rule: propose the design, show the code, then write after
the user approves.
Phase 1: Load context
- Read
.mcplugin/config.yml (the project descriptor) for platform, mc_version,
package, main_class, plugin_name. If it's missing, tell the user to run
/setup-platform (and /scaffold) first. Note: this is different from the plugin's own
runtime config.yml you're about to create under src/main/resources.
- Read the reference and pitfalls (relative to this skill;
Glob as fallback):
../../references/api/persistence-config.md — getConfig(), defaults, save/reload
../../references/pitfalls.md — the "Config" section
- Look at existing source to match style:
Glob src/main/java/**/*.java, read the main class
and check whether a src/main/resources/config.yml already exists (extend it, don't clobber).
Phase 2: Clarify the settings
Ask (AskUserQuestion or plain text) only what you can't infer:
- Which settings are needed, their types (int, double, boolean, String, list, section),
and a sensible default for each.
- Grouping — flat keys vs. nested sections (e.g.
messages.no-permission).
- Messages — if any user-facing text is configurable, note it (on Paper these can be
deserialized to Adventure
Component via MiniMessage; on Spigot they stay String).
- Reload — how should an admin reload without restarting? A
/<plugin> reload subcommand,
a dedicated admin command, or none. Offer to wire it.
Phase 3: Choose the accessor shape
Decide from the stack and explain the pick briefly:
- Direct
getConfig().getX(...) calls — fine for one or two values; simplest.
- A typed settings holder (recommended for several values) — a small class that reads all
keys once into typed fields on load/reload, so the rest of the code reads plain fields instead
of stringly-typed config paths. Fewer typos, one place for defaults, cheap reads in hot paths.
- Nested sections — for grouped keys use
getConfig().getConfigurationSection("messages")
and read within it; iterate getKeys(false) for map-like config (e.g. a set of named warps).
- Lists —
getStringList(path) / getIntegerList(path) return an empty list (not null)
when the key is absent, so they're safe to iterate directly.
Phase 4: Implement
Generate, in the project's package and resources:
src/main/resources/config.yml — every setting with its default value and a short
comment. This bundled file is what ships inside the jar.
- In the main class
onEnable, call saveDefaultConfig() so the file is written to the
data folder on first run (getConfig() reads the on-disk copy).
- A typed accessor / settings holder that reads each key with a default and is null-safe —
getConfig().getInt(path, default) style, never assuming a key is present. Validate ranges
where it matters (e.g. clamp a negative radius) and log a warning on bad values.
- A reload path if requested: a subcommand/admin command that calls
reloadConfig() then
re-reads into the settings holder, with a permission check and a confirmation message. (Use
saveConfig() only when the plugin itself writes values back — don't call it on pure reads,
as it can strip comments.)
Note that saveDefaultConfig() will not overwrite an existing on-disk config.yml, so new
keys you add in a later version won't appear for existing servers — read them with defaults (so
they still work), and if the shape changes materially, add a config-version key and migrate.
Show the new/edited files (config.yml, the settings class, the onEnable diff, any reload
command wiring) and get approval before writing.
Phase 5: Verify + hand off
- Re-check the pitfalls: bundled
config.yml present in resources, saveDefaultConfig() called
in onEnable, every read has a default and is null-safe, reload path calls
reloadConfig() before re-reading, and in-memory settings are refreshed after reload.
- Suggest next steps: "
/build to compile, then /run-server; edit config.yml and reload to
confirm values take effect."
Do not fabricate APIs for a Minecraft version newer than ../../references/api/VERSION.md
documents — if unsure a method exists in the target version, say so and verify.
1---2name: add-config3description: Add config.yml handling to a Minecraft plugin — a bundled default config, saveDefaultConfig() in onEnable, a typed settings accessor, and a reload path. Use this whenever the user wants configurable settings, options, a config file, tunable values, messages the admin can edit, a /reload command, or 'read this from config instead of hardcoding it' in their Bukkit/Paper plugin. Reads the target stack from .mcplugin/config.yml.4---56# Add config.yml handling78Wire up first-run defaults, typed reads, and a reload path, matching the project's stack and9conventions. Follow the collaborative rule: propose the design, show the code, then write after10the user approves.1112## Phase 1: Load context1314- Read `.mcplugin/config.yml` (the **project** descriptor) for `platform`, `mc_version`,15 `package`, `main_class`, `plugin_name`. If it's missing, tell the user to run16 `/setup-platform` (and `/scaffold`) first. Note: this is different from the plugin's own17 runtime `config.yml` you're about to create under `src/main/resources`.18- Read the reference and pitfalls (relative to this skill; `Glob` as fallback):19 - `../../references/api/persistence-config.md` — `getConfig()`, defaults, save/reload20 - `../../references/pitfalls.md` — the "Config" section21- Look at existing source to match style: `Glob` `src/main/java/**/*.java`, read the main class22 and check whether a `src/main/resources/config.yml` already exists (extend it, don't clobber).2324## Phase 2: Clarify the settings2526Ask (AskUserQuestion or plain text) only what you can't infer:27- **Which settings** are needed, their **types** (int, double, boolean, String, list, section),28 and a sensible **default** for each.29- **Grouping** — flat keys vs. nested sections (e.g. `messages.no-permission`).30- **Messages** — if any user-facing text is configurable, note it (on Paper these can be31 deserialized to Adventure `Component` via MiniMessage; on Spigot they stay `String`).32- **Reload** — how should an admin reload without restarting? A `/<plugin> reload` subcommand,33 a dedicated admin command, or none. Offer to wire it.3435## Phase 3: Choose the accessor shape3637Decide from the stack and explain the pick briefly:38- **Direct `getConfig().getX(...)` calls** — fine for one or two values; simplest.39- **A typed settings holder** (recommended for several values) — a small class that reads all40 keys once into typed fields on load/reload, so the rest of the code reads plain fields instead41 of stringly-typed config paths. Fewer typos, one place for defaults, cheap reads in hot paths.42- **Nested sections** — for grouped keys use `getConfig().getConfigurationSection("messages")`43 and read within it; iterate `getKeys(false)` for map-like config (e.g. a set of named warps).44- **Lists** — `getStringList(path)` / `getIntegerList(path)` return an empty list (not null)45 when the key is absent, so they're safe to iterate directly.4647## Phase 4: Implement4849Generate, in the project's package and resources:501. **`src/main/resources/config.yml`** — every setting with its default value and a short51 comment. This bundled file is what ships inside the jar.522. In the main class `onEnable`, call **`saveDefaultConfig()`** so the file is written to the53 data folder on first run (`getConfig()` reads the on-disk copy).543. **A typed accessor / settings holder** that reads each key with a default and is null-safe —55 `getConfig().getInt(path, default)` style, never assuming a key is present. Validate ranges56 where it matters (e.g. clamp a negative radius) and log a warning on bad values.574. **A reload path** if requested: a subcommand/admin command that calls `reloadConfig()` then58 re-reads into the settings holder, with a permission check and a confirmation message. (Use59 `saveConfig()` only when the plugin itself writes values back — don't call it on pure reads,60 as it can strip comments.)6162Note that `saveDefaultConfig()` will **not** overwrite an existing on-disk `config.yml`, so new63keys you add in a later version won't appear for existing servers — read them with defaults (so64they still work), and if the shape changes materially, add a `config-version` key and migrate.6566Show the new/edited files (`config.yml`, the settings class, the `onEnable` diff, any reload67command wiring) and get approval before writing.6869## Phase 5: Verify + hand off7071- Re-check the pitfalls: bundled `config.yml` present in resources, `saveDefaultConfig()` called72 in `onEnable`, every read has a **default** and is null-safe, reload path calls73 `reloadConfig()` **before** re-reading, and in-memory settings are refreshed after reload.74- Suggest next steps: "`/build` to compile, then `/run-server`; edit `config.yml` and reload to75 confirm values take effect."7677Do not fabricate APIs for a Minecraft version newer than `../../references/api/VERSION.md`78documents — if unsure a method exists in the target version, say so and verify.