Skip to content

Commit b9bccfa

Browse files
committed
[FIX] Fix README.md
1 parent 56b83d0 commit b9bccfa

1 file changed

Lines changed: 231 additions & 49 deletions

File tree

README.md

Lines changed: 231 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,260 @@
1-
![kotlin_version](https://img.shields.io/badge/kotlin-2.0.0-blueviolet?style=flat-square)
2-
![kotlin_version](https://img.shields.io/badge/java-21-blueviolet?style=flat-square)
3-
![minecraft_version](https://img.shields.io/badge/minecraft-1.20.1-green?style=flat-square)
4-
![platforms](https://img.shields.io/badge/platform-spigot-blue?style=flat-square)
1+
<div align="center">
52

6-
Originally [DeadSouls](https://github.com/Astra-Interactive/DeadSoulsKT)
3+
# 👻 SoulKeeper
74

8-
> [!CAUTION]
9-
> Java 21 and Paper 1.21.1 only supported! Use other versions on your own risk!
5+
### Your items survive death. So does your progress.
106

11-
# SoulKeeper
7+
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.
128

13-
Plugin to prevent XP and/or Items loss on your death. The items will not despawn no matter what - lava, fire, void!
9+
![souls.png](media%2Fsouls.png)
1410

15-
All your inventory will be safely stored inside a soul until someone will take it(in case of soul is freed).
11+
</div>
1612

17-
## Screenshot
13+
---
1814

19-
![souls.png](media%2Fsouls.png)
15+
## ✨ Inspiration
16+
17+
SoulKeeper is the spiritual successor of [DeadSoulsKT](https://github.com/Astra-Interactive/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.
18+
19+
---
20+
21+
## 💀 How Souls Work
22+
23+
### Creating a soul
24+
25+
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.
26+
27+
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.
28+
29+
> Souls spawned in The End are clamped to a minimum Y so they can never sink into the void.
30+
31+
### Picking up a soul
32+
33+
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:
34+
35+
| Signal | Meaning |
36+
|-----------------------------------|-------------------------------------|
37+
| 🔵 Cyan dust particles | Soul holds XP |
38+
| ⚪ White dust particles | Soul holds items |
39+
| 🔔 Beacon ambient sound | Soul is nearby — follow the sound |
40+
| 🟣 Purple smoke + anvil sound | Inventory full — items still remain |
41+
| ✨ Bright flash + extinguish sound | Soul fully collected and gone |
42+
43+
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.
44+
45+
### Soul lifecycle
46+
47+
```
48+
Death → [PRIVATE] ──── soul_free_after ────▶ [PUBLIC] ──── soul_fade_after ────▶ [DELETED]
49+
│ │
50+
Only owner Any player
51+
can collect can collect
52+
```
53+
54+
| State | Who can collect | Default timing |
55+
|----------------|-----------------|--------------------------------------------|
56+
| 🔒 **Private** | Owner only | Immediately after death |
57+
| 🔓 **Public** | Any player | After `soul_free_after` (default: 2 days) |
58+
| 💨 **Gone** || After `soul_fade_after` (default: 14 days) |
59+
60+
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.
61+
62+
---
63+
64+
## 🗃️ Krates — Backup Storage
65+
66+
Every death also writes a **Krate**: a standalone YAML snapshot of the soul, saved to disk **independently of the database**.
67+
68+
```
69+
plugins/SoulKeeper/
70+
deaths/
71+
<player-uuid>/
72+
<epoch-second>_0.yml ← first krate
73+
<epoch-second>_1.yml ← second krate (if retry occurred)
74+
...
75+
```
76+
77+
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**.
78+
79+
```
80+
/soulkrate <uuid> <epoch-second> <index>
81+
```
82+
83+
This reads the matching `<epoch>_<index>.yml` krate file and deposits its items directly into the requesting player's inventory. Use it when:
84+
85+
- A database failure occurred during a busy session
86+
- A player was rolled back by an external tool
87+
- Items need to be restored from a specific past death
88+
89+
---
90+
91+
## 🚀 Features
92+
93+
### 🔄 Fully non-blocking
94+
95+
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.
96+
97+
### 🛡️ Safe, explicit failure paths
98+
99+
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`.
100+
101+
### 📦 Krate safety net
102+
103+
A file-based snapshot is written on every death independently of the database. Items cannot be lost in a catastrophic DB failure.
104+
105+
### 🎨 Fully customizable effects
106+
107+
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.
108+
109+
### ⏳ Configurable soul lifecycle
20110

21-
## How to create a soul
111+
`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.
22112

23-
- **Die** (in minecraft)
24-
- Find the place of death. Or use `/souls` command. There will be a soul with your items and XP. Stand near soul a few
25-
sec. Whoosh! Your items now collected
26-
- If you don't have enough space, the soul will make a sound and purple smoke will appear indicating lack of space.
27-
- The soul will become public after a configured time.
113+
### 📈 Partial pickup
28114

29-
Features:
115+
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.
30116

31-
- [x] Fully async
32-
- [x] Highly customizable particle effects
33-
- [x] Highly customizable sound effects
34-
- [x] Runtime reloadable database
35-
- [x] Control retained XP amount
117+
### 🏷️ Virtual floating name tags
36118

37-
| Command | Description | Permission |
38-
|:-----------------|:-----------------------------|:--------------------|
39-
|`/skreload` | Reload plugin | soulkeeper.reload |
40-
|`/souls <page>` | List souls | `-` |
41-
|`-` | View all souls in `/souls` | soulkeeper.all |
42-
|`-` | Free any soul in `/souls` | soulkeeper.free.all |
43-
|`-` | Teleport to soul in `/souls` | soulkeeper.teleport |
119+
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.
44120

45-
## Support
121+
### 🔔 Proximity soul calling
46122

47-
If anything go wrong, please:
123+
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.
48124

49-
1. Define a clear steps to reproduce
50-
2. Try to reproduce again in clear environment
51-
3. Obtain latest console logs
52-
4. [Join Discord](https://discord.com/invite/8fEzV2TDS2) and create a ticket in `support`
125+
### 🌍 End dimension safety
53126

54-
## Feature request
127+
Souls spawned in The End are clamped to `endLocationLimitY` so they never fall below the island floor and become unreachable.
55128

56-
Almost the same as support.
129+
### 📑 Paginated soul browser
57130

58-
- Join discord
59-
- Create a ticket in `suggestions`
60-
- We will have a little talk and after that I will create issue on github
131+
`/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.
61132

62-
## Incompatible plugin
133+
### 🗄️ Versioned database migrations
63134

64-
- Any plugin which is editing `PlayerDeathEvent`
135+
`DatabaseMigrator` carries all schema migration steps. Upgrading the plugin never requires manual SQL — migrations run automatically on startup.
65136

66-
# Preview
137+
---
67138

68-
## Killing
139+
## ⚙️ Configuration
140+
141+
All settings live in `config.yml` inside the plugin data folder and are hot-reloadable via `/skreload`.
142+
143+
```yaml
144+
# Database file path (SQLite)
145+
database: ...
146+
147+
# Soul becomes publicly collectible after this duration
148+
soul_free_after: 2d
149+
150+
# Soul disappears permanently after this duration
151+
soul_fade_after: 14d
152+
153+
# Radius (blocks) within which a soul emits sounds/particles to guide its owner
154+
soul_call_radius: 100
155+
156+
# Fraction of dropped XP stored in the soul (0.0 – 1.0)
157+
retained_xp: 1.0
158+
159+
# Minimum Y for souls in The End (prevents void loss)
160+
end_location_limit_y: 0.0
161+
162+
# Show floating "Soul of <player>" name tags above souls
163+
display_soul_titles: true
164+
165+
# How PvP deaths are handled
166+
# NONE – PvP deaths create no soul
167+
# EXP_ONLY – soul holds XP only
168+
# ITEMS_ONLY – soul holds items only
169+
# EXP_AND_ITEMS – soul holds everything (same as normal death)
170+
pvp_behaviour: NONE
171+
```
172+
173+
### 🎵 Sounds
174+
175+
Every audio cue is independently configurable with `id`, `volume`, and `pitch`:
176+
177+
| Key | Default sound | Trigger |
178+
|---------------------|----------------------------------|------------------------------|
179+
| `collect_xp` | `entity.experience_orb.pickup` | XP absorbed from soul |
180+
| `collect_item` | `item.trident.return` | Items absorbed from soul |
181+
| `soul_disappear` | `entity.generic.extinguish_fire` | Soul fully collected |
182+
| `soul_dropped` | `block.bell.resonate` | Soul created on death |
183+
| `soul_calling` | `block.beacon.ambient` | Soul pulsing near owner |
184+
| `soul_content_left` | `block.anvil.place` | Inventory full, items remain |
185+
186+
### 🌟 Particles
187+
188+
Every particle effect is independently configurable with `key`, `count`, and optional `dust_options` (RGBA color + size):
189+
190+
| Key | Default color | Trigger |
191+
|---------------------|------------------|----------------------------------|
192+
| `soul_items` | White `#FFFFFF` | Soul contains items (continuous) |
193+
| `soul_xp` | Cyan `#00FFFF` | Soul contains XP (continuous) |
194+
| `soul_created` | Red `#eb3437` | Burst on soul creation |
195+
| `soul_gone` | Yellow `#FFFF00` | Burst on full collection |
196+
| `soul_content_left` | Purple `#a103fc` | Inventory full warning |
197+
198+
---
199+
200+
## 🛠️ Commands
201+
202+
| Command | Description | Permission |
203+
|-------------------------------------|------------------------------------|-----------------------|
204+
| `/skreload` | Hot-reload config and translations | `soulkeeper.reload` |
205+
| `/souls [page]` | List your souls (5 per page) | *(none)* |
206+
| `/souls [page]` | List **all** server souls | `soulkeeper.all` |
207+
| `/souls` → **\[FREE\]** | Force-free any soul immediately | `soulkeeper.free.all` |
208+
| `/souls` → **\[TP\]** | Teleport to a soul's location | `soulkeeper.teleport` |
209+
| `/soulkrate <uuid> <epoch> <index>` | Restore items from a krate file | `soulkeeper.load` |
210+
211+
---
212+
213+
## 🌐 Multiplatform
214+
215+
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.
216+
217+
| Platform | Jar | Minimum version |
218+
|--------------------|---------------------------|-----------------|
219+
| **Paper / Spigot** | `soulkeeper-bukkit.jar` | Paper 1.21.1 |
220+
| **Forge** | `soulkeeper-forge.jar` | Forge 1.21.1 |
221+
| **NeoForge** | `soulkeeper-neoforge.jar` | NeoForge 1.21.1 |
222+
223+
Pick the jar for your platform and drop it in — the same soul data, the same commands, the same behaviour everywhere.
224+
225+
---
226+
227+
## 🎬 Preview
228+
229+
### On death — soul created
69230

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

72-
## Collecting
233+
### Returning — soul collected
73234

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

76-
More plugins from AstraInteractive [AstraInteractive](https://github.com/Astra-Interactive)
237+
---
238+
239+
## ⚠️ Known Incompatibilities
240+
241+
- 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.
242+
243+
---
244+
245+
## 🐛 Support
246+
247+
1. Reproduce the issue in a clean environment (no unrelated plugins/mods).
248+
2. Collect the full server log from startup through the issue.
249+
3. [Join our Discord](https://discord.com/invite/8fEzV2TDS2) and open a ticket in `#support`.
250+
251+
## 💡 Feature Requests
252+
253+
Open a ticket in `#suggestions` on our [Discord](https://discord.com/invite/8fEzV2TDS2) and we'll discuss it before creating a GitHub issue.
254+
255+
---
256+
257+
<div align="center">
77258

78-
<img src="https://bstats.org/signatures/bukkit/SoulKeeper.svg"/>
259+
More plugins from [AstraInteractive](https://github.com/Astra-Interactive)
260+
</div>

0 commit comments

Comments
 (0)