Skip to main content

Corpse

Player corpses holding inventory and XP, with loot menu, protection, expiry and model backends.

Freev0.7Entities & models
RequiresTypeWriter0.9Basic extensionEntity extensionQuest extensionGUIMySQLoptionalModelEngineoptionalBetterModeloptionalMythicMobs NPCoptionalBTC Mob NPCoptional

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 allowedWorlds and excludedWorlds.
  • 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​

  1. Install the TypeWriter extensions Basic, Quest and Entity from the Extensions tab of the web panel (see the TypeWriter documentation).
  2. Install the GUI extension: the loot menu is built on it.
  3. Optional: install the model backend you want for the look of the corpse (ModelEngine, BetterModel, MythicMobs NPC or BTC Mob NPC).
  4. Optional: install the MySQL extension to store corpses in a database. Without it, corpses are saved in plugins/Typewriter/corpse/corpses.json.
  5. 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:

  1. 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).
  2. Set duration to 300, onlyOwnerCanLoot to off and ownerProtectionSeconds to 60.
  3. Choose lootMode: GUI opens the loot menu on right-click, DIRECT moves everything into the looter's inventory, DROP drops it on the ground. Sneaking while clicking uses another mode (sneakSwapsLootMode).
  4. Add a Corpse Model Definition. Leave definitionRef empty for the plain player model, or pick an entity definition for a model. Set pose, rotationMode and the interaction* hit box if needed.
  5. 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.
  6. To make recovery a quest step, add a Corpse Recovery Objective linked to a quest.
  7. Publish, die once in a test world, and right-click the corpse.
note

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 over allowedWorlds.

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, so dungeon_* covers every world a dungeon generates for a run, while dgbuild is 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 worlds list 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;
  • keepInventory is 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.

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:

StorageWhenLocation
MySQLthe MySQL extension provides a data sourcetable corpse_corpses, created automatically
Local fileno data source, or MySQL failed to initializeplugins/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.

CommandDescription
/corpses listList every corpse of the server, whatever its world, with its owner, position, world, item count and experience.
/corpses clearRemove 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​

PermissionGrants
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
Objectives1
Facts2
Audiences2
Commands1
Manifests2

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.