Corpse
Overview
When a player dies, Corpse takes over their drops: the whole inventory (hotbar, armor, off-hand) and the experience are moved into a corpse standing where they fell. The vanilla drops are cleared. The corpse stays until someone loots it or it expires, and it survives a restart.
The corpse is a packet entity, rendered separately for every player nearby. It can be a plain player model in the dying pose wearing the victim's skin and armor, or any model from a supported backend. Two manifest entries drive everything: Corpse Global Settings for server-wide rules and Corpse Model Definition for the look of the corpse.
Features
- Full loot capture — inventory, armor, off-hand and experience go into the corpse; vanilla drops and experience are cleared.
- Three loot modes — a paged loot menu, direct transfer into the looter's inventory, or dropping everything on the ground.
- Loot protection — owner-only looting, or a protection window after which anyone can loot.
- Expiry — corpses disappear after a configurable time, or never.
- Persistence — corpses survive restarts, in MySQL when available, otherwise in a local file.
- Several looks — definitions are chosen by world and priority; models from EntityExtension, ModelEngine, BetterModel, BTC Mob NPC or MythicMobs NPC.
- Plain player fallback — skin, armor, glow and a pose (lying, fallen, dying or standing) when no model is set.
- Quest hooks — events on spawn, loot and expiry, facts, a recovery objective and a waypoint showing the way back.
- World filter — leave corpses only in some worlds (for example the dungeons) with
allowedWorldsandexcludedWorlds. - Every text is yours — messages, menu labels and materials, the waypoint format and its arrows, and the command replies are all fields.
- Staff command — list and clear the corpses of the whole server.
- Folia ready — world changes run on the region that owns the corpse.
Installation
- Install the TypeWriter extensions Basic, Quest and Entity from the Extensions tab of the web panel (see the TypeWriter documentation).
- Install the GUI extension: the loot menu is built on it.
- Optional: install the model backend you want for the look of the corpse (ModelEngine, BetterModel, MythicMobs NPC or BTC Mob NPC).
- Optional: install the MySQL extension to store corpses in a database. Without it, corpses are saved in
plugins/Typewriter/corpse/corpses.json. - Put the Corpse JAR in
plugins/Typewriter/extensions/and restart the server.
At startup the console logs which model backends were found. If none is found, corpses still hold loot and render as a plain player.
Getting started
Set up corpses that last five minutes, are protected for the owner for one minute, and show a way back:
- In the TypeWriter web panel, open a manifest page and add a Corpse Global Settings entry. Without it, built-in defaults apply (300 seconds, loot menu, anyone can loot).
- Set
durationto300,onlyOwnerCanLootto off andownerProtectionSecondsto60. - Choose
lootMode:GUIopens the loot menu on right-click,DIRECTmoves everything into the looter's inventory,DROPdrops it on the ground. Sneaking while clicking uses another mode (sneakSwapsLootMode). - Add a Corpse Model Definition. Leave
definitionRefempty for the plain player model, or pick an entity definition for a model. Setpose,rotationModeand theinteraction*hit box if needed. - Add a Corpse Waypoint audience entry to show the distance and an arrow to the corpse on the action bar. It disappears once the corpse is gone.
- To make recovery a quest step, add a Corpse Recovery Objective linked to a quest.
- Publish, die once in a test world, and right-click the corpse.
Corpse only takes what the death would have dropped. With the keepInventory game rule on, the player keeps their items and no corpse is made: the death is vanilla. Items that other plugins keep for the player (Curse of Vanishing, soulbound items) are not duplicated into the corpse.
Restrict to some worlds
By default every world leaves a corpse. Two lists in Corpse Global Settings choose where:
allowedWorlds: the worlds where a death leaves a corpse. Empty means every world.excludedWorlds: the worlds where a death never leaves a corpse. It always wins overallowedWorlds.
For corpses in the dungeons only, and nowhere else:
allowedWorlds:
- dungeon_*
Rules for both lists:
- One entry per world.
*matches any run of characters and?exactly one, sodungeon_*covers every world a dungeon generates for a run, whiledgbuildis one named world. - Each entry is compared, ignoring case, with the world name (its folder name) and with its dimension key, for example
minecraft:the_nether. - Outside the allowed worlds (or in an excluded one) the death is vanilla: normal drops and normal experience, no corpse.
- This only decides whether a corpse exists. The look of a corpse is still picked by the
worldslist of the Corpse Model Definition, which takes the same entries.
What the player sees in a refused world. filteredWorldDeath chooses it. It has no effect when both lists are empty.
VANILLA_DEATH_SCREEN(default): an ordinary Minecraft death. The body lying on the ground and the death screen are drawn by the Minecraft client, not by Corpse, and Corpse cannot remove them.INSTANT_RESPAWN: the player respawns on the next tick, without the death screen. Items and experience drop on the ground as in vanilla, in both cases.
For corpses in the dungeons only, and an instant respawn everywhere else:
allowedWorlds:
- dungeon_*
filteredWorldDeath: INSTANT_RESPAWN
A death leaves no corpse, and stays vanilla, when:
- the world is not allowed or is excluded;
keepInventoryis on;- another plugin cancelled the death (a totem or revive plugin): the player is not dead;
- there is nothing to take over: no item and no experience.
How it works
Which definition is used is decided at death: among the Corpse Model Definition entries whose worlds list contains the world of death (an empty list means every world), the one with the highest priority wins. Without any definition, a default one is used. Its lifetime comes from overrideDuration when above 0, otherwise from the global duration. The owner-protection rule is fixed when the corpse is created.
Only a right-click on the corpse loots it. Looting empties the corpse, and the corpse is removed. A corpse that nobody loots expires and its items are lost.
Menus
In GUI loot mode, right-clicking the corpse opens a 54-slot menu built with the GUI extension.
- The first five rows (45 slots) hold the corpse's items. Click an item to take it into your inventory (an item that does not fit is dropped at your feet); the corpse is saved after each item taken. Taking the last item empties the corpse, which gives the experience and fires
on_corpse_loot. - The bottom row holds the buttons: previous page (left), next page, a button that takes everything, and close (right). The paging buttons appear only when there are several pages.
- The take-everything chest lists the experience held by the corpse (and the current page) in its lore, and hands everything, experience included, to the looter.
- The title and every label can be changed in Corpse Global Settings (
guiTitle,guiLootAllLabel,guiCloseLabel,guiPreviousPageLabel,guiNextPageLabel,guiExperienceLabel,guiPageLabel).
If the looter's inventory is full in DIRECT mode, the overflow is dropped at the corpse and inventoryFullMessage is shown. Dropped items can be reserved for the looter (reserveDroppedItems, reserveDroppedItemsSeconds).
Configuration
Corpses are stored outside the web panel:
| Storage | When | Location |
|---|---|---|
| MySQL | the MySQL extension provides a data source | table corpse_corpses, created automatically |
| Local file | no data source, or MySQL failed to initialize | plugins/Typewriter/corpse/corpses.json |
Corpses whose expiry time passed while the server was off are deleted at startup, without firing on_corpse_expire. After a restart, a corpse is shown with the name and settings that are constant values: names and options driven by placeholders fall back to their defaults. A restored corpse keeps its pose, glow, name and animation, but not the owner's skin and armour: it shows the plain model's. An unreadable storage file is kept aside (.unreadable-<time>) instead of being overwritten.
Commands
The command is a Corpse Admin Command entry that you create in the web panel. Its name and permission are fields of the entry; the defaults are below.
| Command | Description |
|---|---|
/corpses list | List every corpse of the server, whatever its world, with its owner, position, world, item count and experience. |
/corpses clear | Remove every corpse of the server, not only those of your world. Does not fire on_corpse_expire. |
Both commands are global to the server, not per world. Their replies, and the header of the list, are editable fields of the entry.
Permissions
| Permission | Grants |
|---|---|
typewriter.corpse.admin | /corpses list and /corpses clear (default value of the entry's permission field). |
Entries
11 entries, generated from the extension source.
Events3
- On Corpse ExpireWhen a corpse expires unlooted
- On Corpse LootWhen a corpse is looted
- On Corpse SpawnWhen a corpse spawns
Objectives1
- Corpse Recovery ObjectiveRecover your corpse
Facts2
- Corpse CountHow many corpses the player has
- Has CorpseWhether the player has a corpse waiting
Audiences2
- Corpse Owner AudiencePlayers who have a corpse waiting
- Corpse WaypointPoints players back to their corpse
Commands1
- Corpse Admin CommandAdmin command for corpses
Manifests2
- Corpse DefinitionCorpse Model Definition
- Corpse SettingsCorpse Global Settings
Troubleshooting
Nothing happens when I right-click the corpse. Corpse is clickable through an invisible hit box, interactionWidth by interactionHeight blocks, which is 1.0 by default. Make it larger for a big model. Turn on debugInteractions in Corpse Global Settings to log every click in the console, then turn it off again. Also check onlyOwnerCanLoot and ownerProtectionSeconds: other players get the cannotLootMessage.
The corpse is a plain player, not my model. definitionRef is empty or could not be resolved (the console shows Failed to resolve entity definition). Make sure the backend extension is installed: the startup log lists the detected backends.
The loot menu does not open. The menu needs the GUI extension. Also check lootMode, and that you are not sneaking: with sneakSwapsLootMode on, sneaking uses the other mode.
There is no corpse after a death. Check, in this order: the world is allowed by allowedWorlds and not in excludedWorlds (compare with the world folder name and with the dimension key); the keepInventory game rule is off in that world; no other plugin cancelled the death; the player had at least one item or some experience.
Clicking from far away does nothing. A click only counts within interactionReach blocks of the corpse (6 by default, 0 = no limit). Repeated clicks within interactionCooldownMillis are ignored as one gesture.
The corpse is gone after a restart. Check the console for Restored n corpse(s) from storage. If the corpse expired while the server was off, it is deleted. When MySQL initialization fails, Corpse falls back to the local file with a warning in the log.
Placeholders in the name do not work. Use {player} for the owner's name in displayName. In respawnMessage, use <x>, <y>, <z> and <world>; in guiTitle, <player>. Placeholders in the other texts are filled before MiniMessage, and a player's name is escaped so it never becomes a clickable tag.
Related extensions
- GUI — provides the loot menu.
- BetterModel and MythicMobs NPC — model backends for the corpse.
- MySQL — database storage for corpses.