# Minecraft Java Edition module.
#
# Uses the itzg/minecraft-server community image — widely deployed, actively
# maintained, designed for panel/automation use. All configuration is driven
# by env vars (unlike 7DTD, which fights us). Boots in ~60-90s on first run
# (downloads the server jar) and ~10-15s on subsequent runs.
#
# RCON uses Source RCON (binary protocol), which our agent doesn't yet have
# an adapter for — so this module declares the RCON port/password for future
# use but leaves the `rcon:` section out for now. Adding a source_rcon adapter
# is ~200 lines in agent/internal/rcon/ when we get to it.
id: minecraft-java
name: "Minecraft Java Edition"
version: 0.1.0
authors:
  - panel contributors
supported_modes:
  - docker
runtime:
  docker:
    image: itzg/minecraft-server:latest
    # Host networking -- container shares the host net namespace, so
    # any port the game/mod binds is directly on the LAN. AMP-like
    # model. Multi-instance safety comes from env-driven per-instance
    # ports (panel allocator + env: mapping on each ports entry).
    network_mode: host
    env:
      EULA: "TRUE"
      TYPE: "VANILLA"
      VERSION: "LATEST"
      MEMORY: "2G"
      ENABLE_RCON: "true"
      RCON_PASSWORD: "panel_rcon"   # default only — a generated per-instance secret overrides this at create
      MOTD: "Running on panel"
      ONLINE_MODE: "TRUE"
      DIFFICULTY: "normal"
      VIEW_DISTANCE: "10"
      # Pre-declared so the agent's resolve.go filter lets allocator-derived
      # ports flow through to the container env. itzg honors both SERVER_PORT
      # and RCON_PORT — defaults match the manifest port defaults below.
      SERVER_PORT: "25565"
      RCON_PORT: "25575"
    volumes:
      # /data holds the whole server including worlds, mods, configs.
      # Named volume for speed; survives instance recreation unless operator
      # explicitly removes it.
      - { type: volume, name: "panel-$INSTANCE_ID-mc", container: "/data" }
ports:
  - { name: game, proto: tcp, default: 25565, required: true,  env: SERVER_PORT }
  - { name: rcon, proto: tcp, default: 25575, internal: true, env: RCON_PORT }
# Per-instance generated RCON secret — overrides the env default below
# at create so every instance gets a unique password.
secrets:
  - name: RCON_PASSWORD
    description: "Minecraft RCON password — generated per instance"
    generated: true
rcon:
  adapter: source_rcon
  host_port: rcon
  auth: source_rcon_login
  password_secret: RCON_PASSWORD
  # Legacy fallback only (pre-generated-secret instances). New instances
  # always get the generated RCON_PASSWORD secret above.
  password_literal: "panel_rcon"
  commands:
    list: "list"
    say:  "say {msg}"
    kick: "kick {player} {reason}"
    stop: "stop"
    save: "save-all"
state_sources:
  - type: rcon
    command: "list"
    every: 60s
    parse:
      kind: regex
      pattern: 'There are (?P<players>\d+) of a max of (?P<max>\d+) players online'
      fields:
        players_online: players
        players_max: max
resources:
  min_ram_mb: 2048
  recommended_ram_mb: 4096

# /data has world saves mixed with downloadable libraries/, mods/ cache,
# and the server jar. Back up the player-state stuff; libraries +
# server jar regenerate from itzg's image on next start.
backup:
  include:
    - "world"               # default world dir (overworld)
    - "world_nether"        # nether
    - "world_the_end"       # end
    - "*.properties"        # server.properties + others
    - "*.json"              # whitelist, ops, banned-players, banned-ips, usercache
    - "plugins"             # bukkit/spigot plugins (config + state inside each)
    - "mods"                # Forge/Fabric mod jars (mod configs in plugins/)
    - "config"              # mod config files
  exclude:
    - "logs"                # rotates infinitely
    - "crash-reports"       # never useful in restore
    - "libraries"           # auto-downloaded by itzg
    - "cache"               # JVM/itzg fluff
    - "tmp"
  notes: "World data + plugins + mods + configs (~50-500 MB typical). Server jar + libraries fetched fresh by itzg on next start."
# itzg/minecraft-server handles install + version pinning via the VERSION env
# var on first container start — there's no SteamCMD / GitHub / direct flow
# the panel needs to drive.
#
# But: the manifest validator REQUIRES at least one update_provider. So we
# keep a placeholder. Without `auto_update_on_create: false` the agent kicks
# off this provider on first boot and direct.go errors out on the missing
# target_path — observed 2026-04-29. The combination here (placeholder +
# auto-update opt-out) is the right shape for any image-managed module.
auto_update_on_create: false
update_providers:
  - id: image-managed
    kind: direct
    url: "https://hub.docker.com/r/itzg/minecraft-server"
    target_path: ".panel-image-managed-marker"  # never written; auto-update is suppressed above
events:
  join:
    pattern: "(?P<name>[A-Za-z0-9_]+) joined the game"
    kind: join
  leave:
    pattern: "(?P<name>[A-Za-z0-9_]+) left the game"
    kind: leave
  chat:
    pattern: "<(?P<name>[A-Za-z0-9_]+)> (?P<msg>.*)"
    kind: chat

# --- Manifest-driven UI metadata (WI-07) --------------------------
# Consumed by the CONTROLLER/dashboard only (the controller loads its
# own ./modules copy at startup); the agent ignores these at runtime.
# ready_pattern is a JavaScript regex (slash-delimited when it needs
# flags) moved verbatim from the dashboard's READY_PATTERNS map.
ready_pattern: 'Done \([\d.]+s\)! For help'
appearance:
  emoji: "🧱"
  grad: "linear-gradient(135deg,#4c8b32,#84ce5c)"
  art: "/game-art/minecraft-java.png"
