COWMODSКаталог модов

SoulKeeper

Keep your items after death inside a soul

Автор: makeevrserg2,3 тыс.7обновлён 18 окт. 2026 г.

Описание

👻 SoulKeeper

Your items survive death. So does your progress.

SoulKeeper captures your full inventory and experience into a glowing soul the instant you die — persisting through lava, fire, and even the void — and waits quietly at the death spot until you return to claim it.

souls.png


✨ Inspiration

SoulKeeper is the spiritual successor of DeadSoulsKT — rebuilt from scratch with a clean multiplatform architecture, async-first design, and a strong focus on reliability. Where DeadSoulsKT laid the foundation, SoulKeeper brings production-grade persistence, rich visual feedback, and cross-platform support to the same beloved mechanic.


💀 How Souls Work

Creating a soul

The moment you die, SoulKeeper silently intercepts the death event before anything hits the ground. Your entire inventory and a configurable portion of your dropped XP are captured and stored in the database as a soul — nothing is scattered across the floor.

A burst of red particles and a resonant bell signal that your soul has been born. The soul appears as a shimmering particle cloud with a floating nameplate — "Soul of <Your Name>" — right where you fell.

Souls spawned in The End are clamped to a minimum Y so they can never sink into the void.

Picking up a soul

Just walk close — no right-click, no shift, no interaction. As soon as you enter the soul's range, it detects you and begins transferring:

SignalMeaning
🔵 Cyan dust particlesSoul holds XP
⚪ White dust particlesSoul holds items
🔔 Beacon ambient soundSoul is nearby — follow the sound
🟣 Purple smoke + anvil soundInventory full — items still remain
✨ Bright flash + extinguish soundSoul fully collected and gone

Items flow back inventory-slot by inventory-slot. If your inventory is full, partial pickup works: XP is absorbed, whatever fits goes in, and the soul persists with only what remains — no items are ever dropped or lost because of a full bag.

Soul lifecycle

Death → [PRIVATE] ──── soul_free_after ────▶ [PUBLIC] ──── soul_fade_after ────▶ [DELETED]
           │                                      │
      Only owner                           Any player
      can collect                          can collect
StateWho can collectDefault timing
🔒 PrivateOwner onlyImmediately after death
🔓 PublicAny playerAfter soul_free_after (default: 2 days)
💨 Gone—After soul_fade_after (default: 14 days)

Background workers (FreeSoulWorker, DeleteSoulWorker) run on a configurable tick cadence and advance souls through this lifecycle automatically — no cron jobs, no restarts, no admin action needed.


🗃️ Krates — Backup Storage

Every death also writes a Krate: a standalone YAML snapshot of the soul, saved to disk independently of the database.

plugins/SoulKeeper/
  deaths/
    <player-uuid>/
      <epoch-second>_0.yml   ← first krate
      <epoch-second>_1.yml   ← second krate (if retry occurred)
      ...

Krates are a last-resort safety net. Even if the SQLite database is lost, corrupted, or rolled back, an admin can restore any dead player's exact inventory from the krate file — zero database interaction required.

/soulkrate <uuid> <epoch-second> <index>

This reads the matching <epoch>_<index>.yml krate file and deposits its items directly into the requesting player's inventory. Use it when:

  • A database failure occurred during a busy session
  • A player was rolled back by an external tool
  • Items need to be restored from a specific past death

🚀 Features

🔄 Fully non-blocking

Every heavy operation — soul creation, pickup detection, database reads/writes, background worker loops — runs on Kotlin coroutines dispatched to background threads via KotlinDispatchers. The main game thread is never touched for I/O.

🛡️ Safe, explicit failure paths

Database operations return kotlin.Result<T>. Failures are logged at the call site and skipped gracefully — they never crash the server, silently eat items, or leave souls in a broken state. Concurrent DB writes in SoulsDaoImpl, the pickup loop in PickUpWorker, and death event handling in ForgeSoulEvents/BukkitSoulEvents are each guarded by their own Mutex.

📦 Krate safety net

A file-based snapshot is written on every death independently of the database. Items cannot be lost in a catastrophic DB failure.

🎨 Fully customizable effects

Every particle (type, color, size, count) and every sound (ID, volume, pitch) is independently configurable per event type. Six sound cues, five particle effects — all tweakable without touching code.

⏳ Configurable soul lifecycle

soul_free_after and soul_fade_after are plain duration values. Set them to seconds, minutes, hours, or days. Background services poll reactively from a config Flow — changes reload live without a restart.

📈 Partial pickup

If your inventory is full when you reach a soul, XP is collected first, then as many items as fit go in. The soul survives with the remainder. Walk back once you have space — nothing is ever force-dropped.

🏷️ Virtual floating name tags

Floating armor-stand nameplates ("Soul of <Player>") are sent as virtual entities via PacketEvents on Bukkit — no real entities are spawned into the world, so performance is unaffected regardless of soul count.

🔔 Proximity soul calling

A SoulCallWorker tracks every online player's position. When a player enters soul_call_radius blocks of a soul they can collect, ambient sounds and particles begin pulsing — guiding them back even in complete darkness or deep underground.

🌍 End dimension safety

Souls spawned in The End are clamped to endLocationLimitY so they never fall below the island floor and become unreachable.

📑 Paginated soul browser

/souls lists all visible souls with owner name, coordinates, age (formatted as "X days ago"), and item/XP indicators. Admins see clickable [FREE] and [TP] buttons inline. 5 souls per page; prev/next navigation included.

🗄️ Versioned database migrations

DatabaseMigrator carries all schema migration steps. Upgrading the plugin never requires manual SQL — migrations run automatically on startup.


⚙️ Configuration

All settings live in config.yml inside the plugin data folder and are hot-reloadable via /skreload.

# Database file path (SQLite)
database: ...

# Soul becomes publicly collectible after this duration
soul_free_after: 2d

# Soul disappears permanently after this duration
soul_fade_after: 14d

# Radius (blocks) within which a soul emits sounds/particles to guide its owner
soul_call_radius: 100

# Fraction of dropped XP stored in the soul (0.0 – 1.0)
retained_xp: 1.0

# Minimum Y for souls in The End (prevents void loss)
end_location_limit_y: 0.0

# Show floating "Soul of <player>" name tags above souls
display_soul_titles: true

# How PvP deaths are handled
# NONE        – PvP deaths create no soul
# EXP_ONLY    – soul holds XP only
# ITEMS_ONLY  – soul holds items only
# EXP_AND_ITEMS – soul holds everything (same as normal death)
pvp_behaviour: NONE

🎵 Sounds

Every audio cue is independently configurable with id, volume, and pitch:

KeyDefault soundTrigger
collect_xpentity.experience_orb.pickupXP absorbed from soul
collect_itemitem.trident.returnItems absorbed from soul
soul_disappearentity.generic.extinguish_fireSoul fully collected
soul_droppedblock.bell.resonateSoul created on death
soul_callingblock.beacon.ambientSoul pulsing near owner
soul_content_leftblock.anvil.placeInventory full, items remain

🌟 Particles

Every particle effect is independently configurable with key, count, and optional dust_options (RGBA color + size):

KeyDefault colorTrigger
soul_itemsWhite #FFFFFFSoul contains items (continuous)
soul_xpCyan #00FFFFSoul contains XP (continuous)
soul_createdRed #eb3437Burst on soul creation
soul_goneYellow #FFFF00Burst on full collection
soul_content_leftPurple #a103fcInventory full warning

🛠️ Commands

CommandDescriptionPermission
/skreloadHot-reload config and translationssoulkeeper.reload
/souls [page]List your souls (5 per page)(none)
/souls [page]List all server soulssoulkeeper.all
/souls → [FREE]Force-free any soul immediatelysoulkeeper.free.all
/souls → [TP]Teleport to a soul's locationsoulkeeper.teleport
/soulkrate <uuid> <epoch> <index>Restore items from a krate filesoulkeeper.load

🌐 Multiplatform

SoulKeeper ships a separate fat-jar for each supported platform. All core logic — soul lifecycle, pickup detection, database, background workers, commands — lives in shared platform-agnostic modules. Only event wiring and item serialization are platform-specific.

PlatformJarMinimum version
Paper / Spigotsoulkeeper-bukkit.jarPaper 1.21.1
Forgesoulkeeper-forge.jarForge 1.21.1
NeoForgesoulkeeper-neoforge.jarNeoForge 1.21.1

Pick the jar for your platform and drop it in — the same soul data, the same commands, the same behaviour everywhere.


🎬 Preview

On death — soul created

https://github.com/user-attachments/assets/ec5f1437-0dab-404f-a4a8-725ee1cd9129

Returning — soul collected

https://github.com/user-attachments/assets/75f58f92-7d13-4c23-a7fb-b2d89476748b


⚠️ Known Incompatibilities

  • Plugins that cancel or heavily modify PlayerDeathEvent (Bukkit) or the equivalent drop events (Forge/NeoForge) may prevent soul creation. Items may not be captured correctly when those plugins are present.

🐛 Support

  1. Reproduce the issue in a clean environment (no unrelated plugins/mods).
  2. Collect the full server log from startup through the issue.
  3. Join our Discord and open a ticket in #support.

💡 Feature Requests

Open a ticket in #suggestions on our Discord and we'll discuss it before creating a GitHub issue.


More plugins from AstraInteractive

Галерея

Последние версии

Все версии →
beta

SoulKeeper-bukkit

1.17.2
18 окт. 2026 г.26Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21bukkit
Скачать
Что нового
[TEST] Drop the VariableNaming suppression detekt does not need\n[REFACTOR] Let the stub armor stand display show nothing on its own\n[REFACTOR] Keep the soul renderers beside the soul call worker
beta

SoulKeeper-neoforge

1.17.2
18 окт. 2026 г.7Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21neoforge
Скачать
Что нового
[TEST] Drop the VariableNaming suppression detekt does not need\n[REFACTOR] Let the stub armor stand display show nothing on its own\n[REFACTOR] Keep the soul renderers beside the soul call worker
beta

SoulKeeper-forge

1.17.2
18 окт. 2026 г.13Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21forge
Скачать
Что нового
[TEST] Drop the VariableNaming suppression detekt does not need\n[REFACTOR] Let the stub armor stand display show nothing on its own\n[REFACTOR] Keep the soul renderers beside the soul call worker
beta

SoulKeeper-forge

1.17.2
17 окт. 2026 г.31Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21forge
Скачать
Что нового
[BUILD] Lint every module with the gradle-plugin linter\n[BUILD] Run the architecture checks on pull requests\n[FIX] Play the item pick-up sound only when an item was added\n[BUILD] Drop project dependencies nothing imports\n[REFACTOR] Split soul storage into data/dao contracts and data/exposed\n[REFACTOR] Pick up a soul in one use case with its rules on the model\n[REFACTOR] Show armor stands through a display contract chosen in DI\n[REFACTOR] Move command, core, platform and renderer files into kind packages\n[REFACTOR] Move the command failure handler and time-ago text into the command unit\n[REFACTOR] Keep the throttle and flow helpers beside the soul call worker\n[REFACTOR] Name the soul DI modules without Service\n[DOCS] Describe every unit in a one-sentence README\n[REFACTOR] Name lambda parameters and order declarations as detekt checks\n[BUILD] Accept the renderer variant packages until the checker knows them\n[CHORE] Bump version to 1.17.2
beta

SoulKeeper-neoforge

1.17.2
17 окт. 2026 г.5Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21neoforge
Скачать
Что нового
[BUILD] Lint every module with the gradle-plugin linter\n[BUILD] Run the architecture checks on pull requests\n[FIX] Play the item pick-up sound only when an item was added\n[BUILD] Drop project dependencies nothing imports\n[REFACTOR] Split soul storage into data/dao contracts and data/exposed\n[REFACTOR] Pick up a soul in one use case with its rules on the model\n[REFACTOR] Show armor stands through a display contract chosen in DI\n[REFACTOR] Move command, core, platform and renderer files into kind packages\n[REFACTOR] Move the command failure handler and time-ago text into the command unit\n[REFACTOR] Keep the throttle and flow helpers beside the soul call worker\n[REFACTOR] Name the soul DI modules without Service\n[DOCS] Describe every unit in a one-sentence README\n[REFACTOR] Name lambda parameters and order declarations as detekt checks\n[BUILD] Accept the renderer variant packages until the checker knows them\n[CHORE] Bump version to 1.17.2
beta

SoulKeeper-bukkit

1.17.2
17 окт. 2026 г.6Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21bukkit
Скачать
Что нового
[BUILD] Lint every module with the gradle-plugin linter\n[BUILD] Run the architecture checks on pull requests\n[FIX] Play the item pick-up sound only when an item was added\n[BUILD] Drop project dependencies nothing imports\n[REFACTOR] Split soul storage into data/dao contracts and data/exposed\n[REFACTOR] Pick up a soul in one use case with its rules on the model\n[REFACTOR] Show armor stands through a display contract chosen in DI\n[REFACTOR] Move command, core, platform and renderer files into kind packages\n[REFACTOR] Move the command failure handler and time-ago text into the command unit\n[REFACTOR] Keep the throttle and flow helpers beside the soul call worker\n[REFACTOR] Name the soul DI modules without Service\n[DOCS] Describe every unit in a one-sentence README\n[REFACTOR] Name lambda parameters and order declarations as detekt checks\n[BUILD] Accept the renderer variant packages until the checker knows them\n[CHORE] Bump version to 1.17.2
beta

SoulKeeper-bukkit

1.17.1
29 сент. 2026 г.17Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21bukkit
Скачать
Что нового
[FIX] Update AstraLibs to 3.50.1 to register commands on a running server\n[FIX] Build against Adventure 4.26.1 that Paper ships\n[BUILD] Keep Dependabot on Adventure 4.x\n[CHORE] Bump version to 1.17.1\nMerge pull request #106 from Astra-Interactive/fix/late-enabled-commands [FIX] Commands when loaded on a running server, texts on Paper
beta

SoulKeeper-forge

1.17.1
29 сент. 2026 г.12Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21forge
Скачать
Что нового
[FIX] Update AstraLibs to 3.50.1 to register commands on a running server\n[FIX] Build against Adventure 4.26.1 that Paper ships\n[BUILD] Keep Dependabot on Adventure 4.x\n[CHORE] Bump version to 1.17.1\nMerge pull request #106 from Astra-Interactive/fix/late-enabled-commands [FIX] Commands when loaded on a running server, texts on Paper
beta

SoulKeeper-neoforge

1.17.1
29 сент. 2026 г.13Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21neoforge
Скачать
Что нового
[FIX] Update AstraLibs to 3.50.1 to register commands on a running server\n[FIX] Build against Adventure 4.26.1 that Paper ships\n[BUILD] Keep Dependabot on Adventure 4.x\n[CHORE] Bump version to 1.17.1\nMerge pull request #106 from Astra-Interactive/fix/late-enabled-commands [FIX] Commands when loaded on a running server, texts on Paper
beta

SoulKeeper-bukkit

1.17.0
28 сент. 2026 г.14Minecraft: 1.16, 1.16.1, 1.16.2, 1.16.3, 1.16.4, 1.16.5, 1.17, 1.17.1, 1.18, 1.18.1, 1.18.2, 1.19, 1.19.1, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21bukkit
Скачать
Что нового
[REFACTOR] Create MultiplatformCommand in CoreModule The command error handler moves into CoreModule and needs it to find the sender, so the command module now takes it from there instead of receiving its own copy.\n[REFACTOR] Move CommandExceptionHandler into CoreModule\n[FEAT] Tell the sender why a command failed Any failure that was not a permission or player check used to read "wrong usage", even a crash. Texts carried by LocalizableComponentCommandException now reach the sender, and an unexpected exception is logged and reported as an unknown error.\n[FEAT] Give every AstraLibs command exception its own text An unknown player and an unparsable argument read "wrong usage", which does not tell the sender what to fix. A sender the platform cannot wrap, like a command block, made the handler throw; it is now only logged, with the command name but not its arguments.\n[FIX] Report a malformed /soulkrate argument as an invalid argument UUID.fromString and Instant.ofEpochSecond throw plain JDK exceptions, which the handler rightly treats as unexpected. The uuid now goes through an argument converter, and Brigadier rejects seconds outside the range of Instant.\n[CHORE] Bump version to 1.17.0\n[DOCS] Remove the KDoc this change added\nMerge pull request #105 from Astra-Interactive/feat/command-exception-handler [FEAT] Tell the sender why a command failed