Skip to content

Development

Pavel Erokhin edited this page Nov 9, 2026 · 3 revisions

Stack

  • Kotlin and the Gradle Kotlin DSL, on Java 25
  • Paper API 26.3 and Adventure MiniMessage
  • kotlinx-serialization with kaml for the config
  • MaxMind DB reader for the country database
  • Optional, compile-only: PlaceholderAPI, MiniPlaceholders, Plan, TAB’s API, and WorldAPI’s expansion API 2

How the code fits together

Everything sits in src/main/kotlin/ru/mairwunnx/moafks/.

File What it does
MoAfksPlugin.kt Startup, shutdown, and reload()
Settings.kt config.yml. Every field has a default, and migrate() turns a 1.x config into switches
Rules.kt The decisions, apart from Bukkit: what counts as activity, which damage is cancelled, when AFK is refused, which warning is due
Afk.kt Who is AFK, entering and leaving, the idle timer, the limit, and putting back what AFK changed
ProtectionListener.kt Every event that could hurt, move, or reward an AFK player
ActivityListener.kt What the player does with their own hands
SessionListener.kt The country lookup at login, quiet exits on quit, death, and world change
AfkEffects.kt, SafeSpot.kt Sounds, particles, and the name mark, plus the safe spot on return
Languages.kt, GeoIp.kt, Messenger.kt Message keys, picking a language, the country database, rendering per reader
AfkCommand.kt, MoAfksCommand.kt The commands
Placeholders.kt, AdventurePlaceholders.kt, Collision.kt, Plan.kt PlaceholderAPI, MiniPlaceholders, TAB, and Plan. Each loads only when its plugin is there
Vanish.kt Who is vanished
WorldApi.kt The moafks namespace in WorldAPI: an Expansion object whose fields declare its parameters and resources, with a record for each answer. It loads only when WorldAPI 4.5.0 or newer is there

The repository’s CLAUDE.md holds the rules that keep it working and a table of every Paper event the plugin handles, with its switch.

Rules for a change

  • A new message gets a Message entry and a line in every file in src/main/resources/lang/.
  • A new config key gets a default in Settings and the same default in src/main/resources/config.yml.
  • A 1.x config must still load (src/test/resources/config-1.x.yml).
  • AFK never changes anything the game saves.

ResourcesTest fails when a language file misses a key or a default doesn’t match.

Tests

  1. ./gradlew build runs the unit tests: Rules, Settings, LocaleResolver, and the bundled files. There is no MockBukkit for Paper 26.3, so the rest runs on a real server.

  2. .claude/scripts/paper_smoke.py starts a real Paper with the jar and the optional plugins, and fails on any error about Mo’Afks:

    python3 -I .claude/scripts/paper_smoke.py --game 26.3 --plugin build/libs/moafks-dev.jar --modrinth placeholderapi --modrinth plan --jar https://cdn.modrinth.com/data/HQyibRsN/versions/N2WfJ0ll/MiniPlaceholders-Paper-3.2.0.jar --jar https://github.com/MairwunNx/minecraft-worldapi/releases/latest/download/worldapi-paper.jar --command "papi list" --command "miniplaceholders expansions" --expect "registered internal expansion: moafks" --expect "Registered extension: Mo’Afks" --expect "^moafks$" --expect "WorldAPI found" --expect "MoAfks shares moafks: 4 resources, 0 topics" --ignore "Plan\] Failed to enable geolocation"
  3. The console can’t go AFK, so anything about a player needs a game client: /afk, idling, and a night with someone AFK.

AI involvement

AI wrote parts of the documentation and some of the code: the serializers and the safe-spot search at first, then the 2.0 rewrite with languages by IP and the review of every Paper event. AI also writes the commit messages from the changes.

Every Monday the autopilot workflow runs Claude to update the dependencies and the game version, fix what breaks, and release when what the plugin ships changed.

Next: Releasing

Clone this wiki locally