Getting started
Drop the jar in and start the server
There is no second plugin to install, because the framework is inside the jar. On first run Bestiary writes an example mob, skill and drop table, and never overwrites a file once it exists.
Check what it thinks it is running on
/bestiary platformPrints the detected server, the scheduler in use, which AI tier was selected and how much content loaded. Worth reading once now so it is familiar when you need it in a bug report.
The AI line is the one to note:
Paper Goal API + NMS,Paper Goal API, ornone (Spigot).Spawn the example
mobs/bestiary/example.ymlis a complete boss with no Java behind it: attributes, AI goals, phases, a bossbar, timed skills and a drop table./bestiary spawn bestiary:example_bossThen browse everything that loaded:
/bestiary menuWrite a skill
Create
plugins/Bestiary/skills/my_skills.yml:frost_nova: cooldown: 6s skills: - sound{s=entity.player.hurt_freeze} @self - particle{p=snowflake;shape={type=ring;radius=5;points=40}} @selfLocation - damage{amount=6} @playersInRadius{r=5} - potion{type=slowness;duration=4s;level=1} @playersInRadius{r=5}Files under
skills/nest as deeply as you like and merge into one namespace, so the id is justfrost_nova.Write a mob that uses it
Create
plugins/Bestiary/mobs/aether/frostling.yml:frostling: type: stray display: "<aqua>Frostling" health: 60 damage: 5 skills: - skill{s=frost_nova} ~onTimer:120 - skill{s=frost_nova} ~onDamagedByPlayerUnder
mobs/, the first directory is the namespace, so this isaether:frostlingrather thanfrostling.Apply it
/bestiary reload /bestiary spawn aether:frostlingIf a skill does not do what you expected, run it from yourself with a live trace of every targeter and condition:
/bestiary cast frost_nova
What ends up on disk
plugins/Bestiary/
- config.ymlguards, storage, anchors, hooks
- messages.yml
- skills/nested freely, one flat namespace
- example.yml
- my_skills.yml
- mobs/first directory is the namespace
- bestiary/
- example.yml
- aether/yours
- frostling.yml
- bestiary/
- droptables/
- example.yml
- spawners/spawners, spawn regions and random spawn rules
skills/, droptables/ and spawners/ all merge into one namespace each, however deeply you nest the files. mobs/ is the exception, and deliberately so: mobs/aether/valkyrie_champion.yml defines aether:valkyrie_champion, which is what keeps two content packs from colliding.
Verify the baseline
Bestiary requires Java 17 or newer and Minecraft 1.19.4-26.x. It supports Spigot, Paper, Paper
forks and Folia; all plugins listed as soft dependencies are optional. Before adding content,
inspect the example with /bestiary info bestiary:example_boss and trace one of its skills with
/bestiary cast <skill>. These commands inspect compiled runtime state rather than only the YAML.
Commands you will use
/bestiary menu browse every mob and skill
/bestiary spawn <mob> [level] [x y z] [world]
/bestiary list [mobs|skills|droptables|anchors|spawners]
/bestiary info <mob|skill> attributes, phases, triggers, the whole tree
/bestiary cast <skill> [target] run a skill from yourself, with a trace
/bestiary debug <mob|off> attach that trace to a running mob
/bestiary reload re-read config and content
/bestiary platform what Bestiary thinks it is running on
When a file is wrong
Parse failures are per definition rather than per file, so one broken skill does not take out the other forty beside it. Each failure names the file, the YAML path, the offending value and what was expected:
[error] skills/my_skills.yml -> frost_nova -> skills[2]
unknown mechanic 'damgae'
A misspelled parameter behaves differently from a misspelled mechanic. Because every mechanic declares its parameters before the parser builds anything, an unknown key is a load-time warning that names the parameters which do exist, rather than a silent default that leaves you wondering why ignore_armour did nothing.