# Configuration

# Configuration

**Version:** 1.12.1

All files live in the plugin's data folder `mods/kyuubisoft_pets/`. They are created with their defaults on the first start.

## Files

```
mods/
  kyuubisoft_pets/
    config.json                 main settings (this page)
    stat-pool.json              stat table and rarity rules (this page)
    loot_luck_blacklist.json    items Loot Luck never doubles (this page)
    pet-types/
      collector/*.json          collector pets
      combat/*.json             combat pets
      mount/*.json              mounts
    localization/<lang>.json    texts in 9 languages
    pets.db                     SQLite pet database
    data/players/<uuid>.json    per-player data
    pet_state.json              spawned pet NPCs, for the cleanup after a restart
    npc-roles/                  NPC role files, written on every start
  kslang/                       language choices shared by all KyuubiSoft mods
  KyuubiSoftPets_CustomItems/   generated summon items of custom pet types
```

| File / folder | Content |
|---------------|---------|
| `pet-types/` | One JSON file per pet type; the subfolder sets the module. Files whose name starts with `_` (the shipped `_template.json`) are skipped. Missing shipped files are written again on every start and reload, so deleting a shipped pet's file does not remove that pet. The fields are explained on [Custom Pets](./custom-pets). |
| `localization/` | One file per language, version 18. Older files are backed up as `<lang>.json.backup-v<old>` and replaced on start. See [Localization](./localization). |
| `pets.db` | The pet records: level, XP, stats, nickname, pickup filter, combat pet health and recovery, item generations. A `pets.db-wal` file next to it is normal while the server runs (`/kspetadmin dbflush` merges it). |
| `data/players/<uuid>.json` | Per player: which pets they own, the summoned pets, bestiary, HUD position and layout (once the player picked one), and pet items held back during a death (see [FAQ](./faq)). |
| `npc-roles/` | Rewritten on every start. Do not edit. |
| `mods/KyuubiSoftPets_CustomItems/` | When a custom pet type's summon item does not exist, the plugin generates it here; it is available after one more restart. See [Custom Pets](./custom-pets). |

## Loading and Reloading

- **With KyuubiSoft Core installed**, `config.json` is merged with the defaults on start: new keys of a plugin update are added to your file.
- **Without Core**, the file is read as it is. Only the newer blocks `combatBalance` (1.8.0) and `ui` (1.9.0) and the 1.11.1 keys `maxPetsEverywhere` and `combatBalance.levelUpCombatStatsOnly` are added once if they are missing; values already in the file are kept. Keys you leave out use their default.
- **`/kspetadmin reload`** (or **Reload** in the [admin window](./admin-panel)) re-reads `config.json`, `loot_luck_blacklist.json`, `stat-pool.json`, every pet type file and the language files.

Some settings are only read at server start or when a player joins:

| Setting | Takes effect |
|---------|--------------|
| `modules.*` | after a restart (the module's commands and game systems are registered at start) |
| `pickupTickIntervalMs`, `followTickIntervalMs`, `autoSaveIntervalSeconds`, `petDbFlushIntervalSeconds` | after a restart |
| `maxPetsPerPlayer` | for each player at their next join (or after `/kspetadmin dbreload <player>`) |
| `combatBalance.mortality.enabled` | switching it on with a reload applies to combat pets summoned afterwards; switching it off protects summoned pets at once |
| everything else | at the next reload |

---

## config.json

The shipped file (without its `_comment` lines):

```json
{
  "enabled": true,
  "modules": {
    "collector": true,
    "combat": true,
    "mount": true
  },
  "maxPetsPerPlayer": 5,
  "maxPetsEverywhere": false,
  "pickupTickIntervalMs": 1000,
  "followTickIntervalMs": 2000,
  "autoSaveIntervalSeconds": 300,
  "petDespawnOnDisconnect": true,
  "petTeleportDistance": 30,
  "hudPosition": "top-left",
  "hudLayout": "vertical",
  "xpSources": {
    "mobKill": 25,
    "blockBreak": 2,
    "crafting": 10,
    "itemPickup": 2,
    "passivePerMinute": 1
  },
  "combatBalance": {
    "damageThroughPipeline": false,
    "requireOwnerActivity": false,
    "ownerInactivitySeconds": 120,
    "levelUpCombatStatsOnly": false,
    "mortality": {
      "enabled": false,
      "baseHealth": 100.0,
      "healthPerLevel": 5.0,
      "tauntChance": 0.25,
      "deathCooldownMinutes": 15,
      "regenPerSecond": 2.0,
      "regenDelaySeconds": 10,
      "xpLossPercent": 0.0,
      "playerDamage": false
    }
  },
  "ui": {
    "compendium": true,
    "lockedPets": "visible",
    "previewTilt": 12,
    "previewSpinSpeed": 18
  },
  "defaultFilterMode": "blacklist",
  "defaultBlacklist": ["Dirt", "Sand", "Gravel", "Cobblestone"],
  "statCaps": {
    "armorBonus": 0.80,
    "damageBonus": 2.00,
    "critChance": 0.75,
    "lifeSteal": 0.50,
    "xpBonus": 3.00,
    "lootLuck": 2.00,
    "thorns": 50.0,
    "maxHealth": 500.0,
    "staminaRegen": 10.0,
    "manaRegen": 10.0,
    "pickupRadius": 15.0
  }
}
```

### General

| Key | Default | Effect |
|-----|---------|--------|
| `enabled` | `true` | Master switch. With `false`, eggs, battle runes, mount horns and scrolls do nothing, pets earn no XP and collect nothing, combat pets do not fight and pet damage bonuses stop. The commands stay registered. |
| `modules.collector` | `true` | Collector pets. Off: the item pickup system is not started, collector summons from the compendium are refused and the compendium hides the collector tab. |
| `modules.combat` | `true` | Combat pets. Off: `/kscombatpet` is not registered, battle runes and combat summons are refused, the compendium hides the combat tab. |
| `modules.mount` | `true` | Mounts. Off: `/ksmount` is not registered, mount horns and mount summons are refused, the compendium hides the mount tab. |
| `maxPetsPerPlayer` | `5` | Pet slots per player: the number of pets on the player's pet list (every kind together). `/kspetadmin give` always refuses when the player already owns this many; where else it applies is set by `maxPetsEverywhere`. Shown as "N / M slots" in the admin window. |
| `maxPetsEverywhere` | `false` | `false`: `maxPetsPerPlayer` only stops `/kspetadmin give`. `true`: it also stops hatching a blank egg, Battle Rune or Mount Horn into a new pet ("You already have 5/5 pets. No new pet can hatch.", before the active pet is sent home) and "Create pet" in the admin window. Items of pets the player already owns keep working. |
| `petTeleportDistance` | `30` | Blocks. A collector or combat pet farther away from its owner is teleported back next to them. |
| `petDbFlushIntervalSeconds` | `30` | Not in the shipped file; add it to change the default (with KyuubiSoft Core installed, the config merge adds it). Seconds between writes of every online player's summoned pets to `pets.db`; bounds the XP lost in a crash. Minimum 5. |
| `autoSaveIntervalSeconds` | `300` | Seconds between saves of all player files. |
| `followTickIntervalMs` | `2000` | Milliseconds between runs of the backup follow check. Pets are normally followed every tick by the regular system; this check only catches collector pets that system does not track (teleport when too far, respawn when lost). |
| `pickupTickIntervalMs` | `1000` | Milliseconds between runs of a small pickup housekeeping task. Fetching items runs on its own fixed cycle (four times per second) and does not depend on this value. |

### XP Sources

| Key | Default | Effect |
|-----|---------|--------|
| `xpSources.mobKill` | `25` | XP for the summoned collector pet when its owner kills a mob. A combat pet that makes a kill gets `mobKill × victim's max health / 100`. |
| `xpSources.blockBreak` | `2` | XP per broken block (none for chests, crates and other container blocks). |
| `xpSources.crafting` | `10` | XP per crafted item. |
| `xpSources.itemPickup` | `2` | XP per item the pet picks up (none for items a player dropped). |

How pets level is described on [Collector Pets](./collector-pets) and [Combat Pets](./combat-pets).

### Pickup Filter Defaults

| Key | Default | Effect |
|-----|---------|--------|
| `defaultFilterMode` | `"blacklist"` | Filter mode of every new pet (`"blacklist"` or `"whitelist"`). |
| `defaultBlacklist` | `["Dirt", "Sand", "Gravel", "Cobblestone"]` | Added as `name` rules (part of the item ID, case-insensitive) to the pickup filter of every new pet: hatched from an item, given with `/kspetadmin give` or created in the admin window. With `defaultFilterMode` `"whitelist"` these entries become the only items the pet collects. |

Existing pets keep their own filter. Players change it with `/kspet filter` (see [Commands](./commands)).

### Stat Caps

`statCaps` limits the total of a stat after the stats of the summoned collector pet and the summoned combat pet are added up. Fractions: `1.0` = +100 %. A cap of `0` means no cap.

| Key | Default | Limits |
|-----|---------|--------|
| `armorBonus` | `0.80` | damage reduction from Armor (80 %) |
| `damageBonus` | `2.00` | bonus damage from Damage (+200 %) |
| `critChance` | `0.75` | Crit Chance (75 %) |
| `lifeSteal` | `0.50` | share of dealt damage healed by Life Steal (50 %) |
| `xpBonus` | `3.00` | Pet XP bonus (+300 %) |
| `lootLuck` | `2.00` | Loot Luck |
| `thorns` | `50.0` | Thorns (flat) |
| `maxHealth` | `500.0` | extra max health (points) |
| `staminaRegen` | `10.0` | extra stamina regeneration (flat) |
| `manaRegen` | `10.0` | extra mana regeneration (flat) |
| `pickupRadius` | `15.0` | extra pickup range (blocks) |

### Combat Balance

Added in 1.8.0. **Every switch is off by default**: an untouched config keeps immortal combat pets that subtract HP directly and fight while the owner is away. Details on [Combat Pets](./combat-pets).

| Key | Default | Effect |
|-----|---------|--------|
| `combatBalance.damageThroughPipeline` | `false` | `true`: pet hits are normal Hytale damage with the pet as attacker, so armor, resistances and boss invulnerability phases apply. `false`: direct HP subtraction that ignores them. |
| `combatBalance.requireOwnerActivity` | `false` | `true`: combat pets stop fighting when their owner has neither turned the camera nor attacked for `ownerInactivitySeconds`. Being pushed around does not count as activity. The owner gets one chat notice. |
| `combatBalance.ownerInactivitySeconds` | `120` | Seconds without activity before the pet stops fighting. |
| `combatBalance.levelUpCombatStatsOnly` | `false` | `true`: a stat a combat pet unlocks through a natural level-up comes from the combat stats only (`combatStatTypes` in `stat-pool.json`), like its first stats, rerolls and admin rolls. `false`: from the full stat pool. Stats a pet already has are not changed. |
| `combatBalance.mortality.enabled` | `false` | `true`: combat pets have HP, can be defeated and need time to recover. |
| `combatBalance.mortality.baseHealth` | `100.0` | Pet HP at level 1. A pet type can override it with `combatStats.baseHealth` (0 = use this value). |
| `combatBalance.mortality.healthPerLevel` | `5.0` | HP per level above 1. A pet type can override it with `combatStats.healthPerLevel` (-1 = use this value). The pet's Max Health stat is added on top. |
| `combatBalance.mortality.tauntChance` | `0.25` | Chance (0 to 1) per pet hit that the target turns to the pet. |
| `combatBalance.mortality.deathCooldownMinutes` | `15` | Minutes a defeated pet needs before it can be summoned again. Survives relogs and restarts. A Battle Pet Revival Scroll or `/kspetadmin revive` ends it early. |
| `combatBalance.mortality.regenPerSecond` | `2.0` | HP regenerated per second out of combat. |
| `combatBalance.mortality.regenDelaySeconds` | `10` | Seconds without damage before regeneration starts. |
| `combatBalance.mortality.xpLossPercent` | `0.0` | Percent (0 to 100) of the current level's XP requirement lost on defeat. Never drops a level. |
| `combatBalance.mortality.playerDamage` | `false` | `true`: other players can hurt combat pets. The owner never can. |

Only hostile NPCs (and other players with `playerDamage`) can hurt a combat pet; fall damage, drowning, suffocation, the owner and other pets cannot.

Recommended against AFK boss farming (from the 1.8.0 release notes):

```json
"combatBalance": {
  "damageThroughPipeline": true,
  "requireOwnerActivity": true,
  "ownerInactivitySeconds": 120,
  "mortality": {
    "enabled": true,
    "baseHealth": 100.0,
    "healthPerLevel": 5.0,
    "tauntChance": 0.25,
    "deathCooldownMinutes": 15,
    "regenPerSecond": 2.0,
    "regenDelaySeconds": 10,
    "xpLossPercent": 0.0,
    "playerDamage": false
  }
}
```

### Compendium (`ui`)

Added in 1.9.0. The windows themselves are shown on [UI Pages](./ui-pages).

| Key | Default | Effect |
|-----|---------|--------|
| `ui.compendium` | `true` | `true`: `/kspet` opens the Pet Compendium with the live 3D preview. `false`: the classic pet menu. |
| `ui.lockedPets` | `"visible"` | Pets a player does not own. `"visible"`: dimmed, with name, base stats and a "How to get it" text. `"hidden"`: shown as `???` until owned, without name, model or values. |
| `ui.previewTilt` | `12` | Camera tilt of the 3D preview in degrees. |
| `ui.previewSpinSpeed` | `18` | Auto-rotation of the 3D preview in degrees per second; `0` = only rotate by dragging. |

![Pet Compendium with lockedPets set to hidden](../../../../assets/pets/pets-compendium-hidden.png)

*`ui.lockedPets: "hidden"`: pets you do not own yet are listed as "???", without name, 3D model or values; only their rarity and the "How to get it" text are shown.*

### HUD Position

| Key | Default | Effect |
|-----|---------|--------|
| `hudPosition` | `"top-left"` | HUD position for players who never picked their own: `top-left`, `top-right`, `middle-left`, `middle-right`, `bottom-left`, `bottom-right` |
| `hudLayout` | `"vertical"` | HUD layout for players who never picked their own: `vertical` or `horizontal` |

Every player can set the position and layout of their pet HUD in the compendium header; that choice is stored per player and wins over the config. Players whose pet file was written by an older version already have the old default (top-left / vertical) saved in it, so a changed server default only reaches new players and players without a pet file.

### Keys Without Effect

These keys are in the shipped file but have no effect (the file's `_comment` says so):

| Key | Note |
|-----|------|
| `petDespawnOnDisconnect` | Pets are always sent home when their owner logs out: a pet left behind would be saved with its chunk and come back as a frozen model. |
| `xpSources.passivePerMinute` | Pets earn no XP over time. |

---

## Loot Luck Blacklist

`mods/kyuubisoft_pets/loot_luck_blacklist.json` holds item ID patterns that the Loot Luck stat never doubles, for every player. The pet still collects the item and the player still gets it once. The shipped file is empty:

```json
{
  "patterns": []
}
```

Example with patterns:

```json
{
  "patterns": [
    "Weapon_*",
    "Armor_*",
    "Ore_*",
    "Ruby"
  ]
}
```

**Pattern rules:**

| Pattern | Matches | Example |
|---------|---------|---------|
| with `*` | `*` stands for any characters; the whole item ID must match | `Ore_*` hits every ID starting with `Ore_`; `*_Spear` every ID ending in `_Spear` |
| without `*` | the item ID contains the text | `Ruby` hits every ID containing `Ruby` |

Matching ignores upper and lower case; all other characters are taken literally. Duplicates are ignored.

**Editing:** the easiest way is the Blacklist section of the [admin window](./admin-panel) (`/kspetadmin lootluck`): it shows how many items each pattern hits, saves at once and applies to the next pickup. If you edit the file by hand, run `/kspetadmin reload` afterwards. The blacklist has its own file so that the window's saving never overwrites your manual edits in `config.json`.

:::note
The quick toggles of the old window (before 1.11.0) wrote `*_Weapon_*`, `*_Armor_*`, `*_Tool_*`, `*_Consumable_*` and `Resource_*`, which hit almost no item. The admin window offers an **Update** button that replaces them with `Weapon_*`, `Armor_*`, `Tool_*`, `Food_*` + `Potion_*` and `Ingredient_*`.
:::

To make a pet ignore items completely, use the player's own pickup filter (see [Collector Pets](./collector-pets)).

---

## stat-pool.json

The stat table every pet rolls from, and the rules per rarity. The shipped file:

```json
{
  "maxSameType": 3,
  "combatStatTypes": ["damage_bonus", "crit_chance", "max_health", "life_steal", "armor_bonus"],
  "combatDefaults": {
    "baseDamage": 8.0,
    "damagePerLevel": 0.5,
    "attackSpeed": 1.5,
    "attackRange": 3.0,
    "aggroRange": 15.0,
    "leashDistance": 20.0
  },
  "statPool": [
    { "type": "damage_bonus",  "displayName": "Damage",        "minBase": 0.01, "maxBase": 0.08,  "minPerLevel": 0.002, "maxPerLevel": 0.015 },
    { "type": "max_health",    "displayName": "Max Health",    "minBase": 2,    "maxBase": 20,    "minPerLevel": 1,     "maxPerLevel": 5 },
    { "type": "pickup_radius", "displayName": "Pickup Range",  "minBase": 0.3,  "maxBase": 3.0,   "minPerLevel": 0.05,  "maxPerLevel": 0.5 },
    { "type": "xp_bonus",      "displayName": "Pet XP",        "minBase": 0.01, "maxBase": 0.15,  "minPerLevel": 0.002, "maxPerLevel": 0.02 },
    { "type": "stamina_regen", "displayName": "Stamina Regen", "minBase": 0.3,  "maxBase": 3.0,   "minPerLevel": 0.1,   "maxPerLevel": 0.6 },
    { "type": "mana_regen",    "displayName": "Mana Regen",    "minBase": 0.3,  "maxBase": 3.0,   "minPerLevel": 0.1,   "maxPerLevel": 0.6 },
    { "type": "crit_chance",   "displayName": "Crit Chance",   "minBase": 0.01, "maxBase": 0.1,   "minPerLevel": 0.002, "maxPerLevel": 0.015 },
    { "type": "armor_bonus",   "displayName": "Armor",         "minBase": 0.01, "maxBase": 0.1,   "minPerLevel": 0.002, "maxPerLevel": 0.012 },
    { "type": "loot_luck",     "displayName": "Loot Luck",     "minBase": 0.02, "maxBase": 0.15,  "minPerLevel": 0.003, "maxPerLevel": 0.02 },
    { "type": "thorns",        "displayName": "Thorns",        "minBase": 0.3,  "maxBase": 3.0,   "minPerLevel": 0.1,   "maxPerLevel": 0.8 },
    { "type": "life_steal",    "displayName": "Life Steal",    "minBase": 0.005,"maxBase": 0.06,  "minPerLevel": 0.001, "maxPerLevel": 0.01 }
  ],
  "rarityRules": {
    "uncommon":  { "maxStats": 2, "unlockLevels": [1, 10],            "qualityMin": 0.0, "qualityMax": 0.7 },
    "rare":      { "maxStats": 3, "unlockLevels": [1, 8, 16],         "qualityMin": 0.0, "qualityMax": 0.85 },
    "epic":      { "maxStats": 4, "unlockLevels": [1, 6, 12, 20],     "qualityMin": 0.0, "qualityMax": 1.0 },
    "legendary": { "maxStats": 5, "unlockLevels": [1, 5, 10, 15, 25], "qualityMin": 0.0, "qualityMax": 1.2 }
  }
}
```

### Keys

| Key | Default | Effect |
|-----|---------|--------|
| `maxSameType` | `3` | How often the same stat may appear on one pet. `1` forbids duplicates; values below 1 count as 1. |
| `combatStatTypes` | 5 stats | The stats combat pets may roll: their first stats, rerolls and every admin roll. |
| `combatDefaults` | see above | Combat values for every combat pet type that does not set its own value in `combatStats`. |
| `statPool` | 11 stats | The stat table. `type` is the stat ID, `displayName` the fallback name when a language has no translation, `minBase`/`maxBase` the range of the value at level 1, `minPerLevel`/`maxPerLevel` the range of the growth per level. |
| `rarityRules` | 4 rarities | Per rarity: `maxStats` (number of stats), `unlockLevels` (one stat slot per entry, rolled when the pet reaches that level), `qualityMin`/`qualityMax` (where in the range a roll lands). |

If the file cannot be read or has no stats, the plugin logs a warning and uses built-in defaults with the same values.

### Stat units

Percent stats are stored as fractions: `0.08` = 8 %.

| Stat ID | Name | Unit |
|---------|------|------|
| `damage_bonus` | Damage | fraction (percent) |
| `xp_bonus` | Pet XP | fraction (percent) |
| `crit_chance` | Crit Chance | fraction (percent) |
| `armor_bonus` | Armor | fraction (percent) |
| `loot_luck` | Loot Luck | fraction (percent) |
| `life_steal` | Life Steal | fraction (percent) |
| `max_health` | Max Health | health points |
| `pickup_radius` | Pickup Range | blocks |
| `stamina_regen` | Stamina Regen | per second |
| `mana_regen` | Mana Regen | per second |
| `thorns` | Thorns | flat |

What each stat does in game is explained on [Collector Pets](./collector-pets) and [Combat Pets](./combat-pets).

### How a stat is rolled

1. A stat type is picked at random from the table (combat pets: only `combatStatTypes`), skipping types the pet already has `maxSameType` times.
2. A quality `q` is rolled between `qualityMin` and `qualityMax` of the pet's rarity.
3. Base = `minBase + (maxBase - minBase) × q`, per level = `minPerLevel + (maxPerLevel - minPerLevel) × q` (same `q`).
4. Both values are clamped to the table range and rounded to 3 decimals.

The value at level L is `base + perLevel × (L - 1)`, and 0 while L is below the stat's unlock level.

Because of step 4, a `qualityMax` above 1.0 does not create values above the table. It makes rolls at the maximum more frequent: with legendary's 1.2, about one roll in six lands exactly at the maximum.

A new pet rolls only the stats that unlock at level 1; the others are rolled when it reaches their unlock level. A pet type with a rarity that is not in `rarityRules` gets one stat at level 1.

:::caution
When a player joins, every stat of their pets is clamped into the current table range. Lowering a `maxBase` or `maxPerLevel` therefore also lowers existing pets, and values outside the range (for example typed into the admin window) are cut back at the owner's next login.
:::

:::note
By default, stats that a combat pet unlocks through normal level-ups are rolled from the full stat table, while its first stats, rerolls and admin rolls use `combatStatTypes` only. Set `combatBalance.levelUpCombatStatsOnly` to `true` in `config.json` to use `combatStatTypes` for those level-ups too.
:::