Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,27 @@ Dead bodies in minecraft for 1.8-1.21.11 servers.
- `render-armor` – Render armor/items on the corpse.
- `corpse-distance` – Max blocks at which corpses are visible.
- `lootable-corpses` – Right‑click to open inventory and loot.
- `entity-pose` – Pose used for the corpse entity (`SLEEPING` or `SWIMMING`).

## API

Add the dependency (e.g. JitPack) and use the **builder API** via `Corpse.fromPlayer()` or `Corpse.fromLocation()`:

```java
import com.github.unldenis.corpse.corpse.Corpse;
import com.github.unldenis.corpse.model.CorpseArmor;

// At player location, with their skin and armor
Corpse corpse = Corpse.fromPlayer(player).spawn();

// At a specific location
Corpse corpse = Corpse.fromPlayer(player).location(location).spawn();
Corpse corpse = Corpse.fromLocation(location).name(offlinePlayer.getName()).spawn();

// Custom armor (array order: boots, leggings, chestplate, helmet)
ItemStack[] armor = new ItemStack[]{boots, leggings, chestPlate, helmet};
Corpse corpse = Corpse.fromPlayer(player).location(location).armorContents(armor).spawn();
Corpse corpse = Corpse.fromLocation(location).name(name).armorContents(armor).spawn();
// Custom armor (use CorpseArmor)
CorpseArmor armor = new CorpseArmor().boots(boots).leggings(leggings).chestplate(chestplate).helmet(helmet);
Corpse corpse = Corpse.fromPlayer(player).location(location).armor(armor).spawn();
Corpse corpse = Corpse.fromLocation(location).name(name).armor(armor).spawn();

// Remove a corpse
corpse.destroy();
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/github/unldenis/corpse/CorpsePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
import com.github.retrooper.packetevents.settings.PacketEventsSettings;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.unldenis.corpse.command.*;
import com.github.unldenis.corpse.data.*;
import com.github.unldenis.corpse.config.*;
import com.github.unldenis.corpse.corpse.*;
import com.github.unldenis.corpse.event.AsyncCorpseInteractEvent;
import com.github.unldenis.corpse.manager.*;
import com.github.unldenis.corpse.pool.*;

import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
package com.github.unldenis.corpse.command;

import com.github.unldenis.corpse.corpse.Corpse;
import com.github.unldenis.corpse.manager.*;
import com.github.unldenis.corpse.pool.*;

import org.bukkit.*;
import org.bukkit.command.*;
import org.bukkit.entity.*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.github.unldenis.corpse.data;
package com.github.unldenis.corpse.config;

import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.file.FileConfiguration;
Expand Down
51 changes: 39 additions & 12 deletions src/main/java/com/github/unldenis/corpse/corpse/Corpse.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTeams;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUseBed;
import com.github.unldenis.corpse.CorpsePlugin;
import com.github.unldenis.corpse.manager.CorpsePool;
import com.github.unldenis.corpse.model.CorpseArmor;
import com.github.unldenis.corpse.pool.CorpsePool;
import com.github.unldenis.corpse.util.BedUtil;
import com.github.unldenis.corpse.util.ProfileUtils;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
Expand Down Expand Up @@ -83,7 +84,7 @@ public static CorpseBuilder fromLocation(@NotNull Location location) {
Corpse(
@NotNull Location location,
@NotNull List<TextureProperty> textures,
@Nullable ItemStack[] armorContents,
@Nullable CorpseArmor armor,
@Nullable String name
) {
pool = CorpsePool.getInstance();
Expand All @@ -92,20 +93,16 @@ public static CorpseBuilder fromLocation(@NotNull Location location) {
this.location = location;
this.profile = new UserProfile(UUID.randomUUID(), name != null ? name : ProfileUtils.randomName(), textures);

// create npc
internalNPC = new CorpseNPC(profile, id,
pool.isShowTags() ? null : WrapperPlayServerTeams.NameTagVisibility.NEVER);

// set npc location
internalNPC.setLocation(SpigotConversionUtil.fromBukkitLocation(location));
if (pool.isRenderArmor() && armorContents != null) {
if (armorContents[0] != null)
internalNPC.setBoots(SpigotConversionUtil.fromBukkitItemStack(armorContents[0]));
if (armorContents[1] != null)
internalNPC.setLeggings(SpigotConversionUtil.fromBukkitItemStack(armorContents[1]));
if (armorContents[2] != null)
internalNPC.setChestplate(SpigotConversionUtil.fromBukkitItemStack(armorContents[2]));
if (armorContents[3] != null)
internalNPC.setHelmet(SpigotConversionUtil.fromBukkitItemStack(armorContents[3]));

// set npc armor
if (pool.isRenderArmor() && armor != null) {
this.setArmor(armor);
hasArmor = true;
} else {
hasArmor = false;
Expand Down Expand Up @@ -148,7 +145,7 @@ public void show(@NotNull Player player) {

} else {
List<EntityData<?>> entityData = new ArrayList<>();
entityData.add(new EntityData<>(6, EntityDataTypes.ENTITY_POSE, EntityPose.SLEEPING));
entityData.add(new EntityData<>(6, EntityDataTypes.ENTITY_POSE, pool.getEntityPose()));
WrapperPlayServerEntityMetadata packet = new WrapperPlayServerEntityMetadata(id, entityData);
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, packet);
}
Expand Down Expand Up @@ -181,23 +178,53 @@ public void destroy() {
CorpsePool.getInstance().remove(this.id);
}

/**
* Gets the entity id of the corpse.
* @return The entity id of the corpse.
*/
public int getId() {
return id;
}

/**
* Gets the name of the corpse.
* @return The name of the corpse.
*/
@NotNull
public String getName() {
return profile.getName();
}

/**
* Gets the location of the corpse.
* @return The location of the corpse.
*/
@NotNull
public Location getLocation() {
return location;
}

/**
* Gets the players that are seeing the corpse.
* @return The players that are seeing the corpse.
*/
@NotNull
public Collection<Player> getSeeingPlayers() {
return Collections.unmodifiableCollection(this.seeingPlayers);
}

/**
* Sets the armor of the corpse.
* @param armor The armor to set.
*/
private void setArmor(@NotNull CorpseArmor armor) {
if (armor.getBoots() != null)
internalNPC.setBoots(SpigotConversionUtil.fromBukkitItemStack(armor.getBoots()));
if (armor.getLeggings() != null)
internalNPC.setLeggings(SpigotConversionUtil.fromBukkitItemStack(armor.getLeggings()));
if (armor.getChestplate() != null)
internalNPC.setChestplate(SpigotConversionUtil.fromBukkitItemStack(armor.getChestplate()));
if (armor.getHelmet() != null)
internalNPC.setHelmet(SpigotConversionUtil.fromBukkitItemStack(armor.getHelmet()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@
import java.util.ArrayList;
import java.util.List;

import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;

import com.github.unldenis.corpse.model.CorpseArmor;

/**
* Builder for creating a Corpse object.
*/
public class CorpseBuilder {

private Location location;
private List<TextureProperty> textures = new ArrayList<>();
private ItemStack[] armorContents = null;
private CorpseArmor armor = null;
private String name = null;

/**
Expand All @@ -30,7 +31,7 @@ public class CorpseBuilder {
CorpseBuilder(@NotNull Player player) {
this.location = player.getLocation();
this.textures = SpigotReflectionUtil.getUserProfile(player);
this.armorContents = player.getInventory().getArmorContents();
this.armor = new CorpseArmor(player);
this.name = player.getName();
}

Expand Down Expand Up @@ -63,12 +64,12 @@ public CorpseBuilder textures(@NotNull List<TextureProperty> textures) {
}

/**
* Set the armor of the corpse. Order: boots, leggings, chestplate, helmet.
* @param armorContents The armor contents to set.
* Set the armor of the corpse.
* @param armor The armor to set.
* @return This builder.
*/
public CorpseBuilder armorContents(@NotNull ItemStack[] armorContents) {
this.armorContents = armorContents;
public CorpseBuilder armor(@NotNull CorpseArmor armor) {
this.armor = armor;
return this;
}

Expand All @@ -87,6 +88,6 @@ public CorpseBuilder name(@NotNull String name) {
* @return The spawned Corpse instance.
*/
public Corpse spawn() {
return new Corpse(location, textures, armorContents, name);
return new Corpse(location, textures, armor, name);
}
}
111 changes: 111 additions & 0 deletions src/main/java/com/github/unldenis/corpse/model/CorpseArmor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.github.unldenis.corpse.model;

import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;

import org.bukkit.entity.Player;

/**
* Represents the armor of a corpse.
*/
public class CorpseArmor {

public static final CorpseArmor EMPTY = new CorpseArmor();


private ItemStack boots;
private ItemStack leggings;
private ItemStack chestplate;
private ItemStack helmet;

/**
* Creates a new CorpseArmor.
* @return A new CorpseArmor.
*/
public CorpseArmor() {}

/**
* Creates a new CorpseArmor from a player.
* @param player The player to create the CorpseArmor for.
* @return A new CorpseArmor.
*/
public CorpseArmor(@NotNull Player player) {
ItemStack[] armorContents = player.getInventory().getArmorContents();
this.boots = armorContents[0];
this.leggings = armorContents[1];
this.chestplate = armorContents[2];
this.helmet = armorContents[3];
}

/**
* Sets the boots of the armor.
* @param boots The boots item stack.
* @return This armor.
*/
public CorpseArmor boots(@NotNull ItemStack boots) {
this.boots = boots;
return this;
}

/**
* Sets the leggings of the armor.
* @param leggings The leggings item stack.
* @return This armor.
*/
public CorpseArmor leggings(@NotNull ItemStack leggings) {
this.leggings = leggings;
return this;
}

/**
* Sets the chestplate of the armor.
* @param chestplate The chestplate item stack.
* @return This armor.
*/
public CorpseArmor chestplate(@NotNull ItemStack chestplate) {
this.chestplate = chestplate;
return this;
}

/**
* Sets the helmet of the armor.
* @param helmet The helmet item stack.
* @return This armor.
*/
public CorpseArmor helmet(@NotNull ItemStack helmet) {
this.helmet = helmet;
return this;
}

/**
* Gets the boots of the armor.
* @return The boots item stack.
*/
public ItemStack getBoots() {
return boots;
}

/**
* Gets the leggings of the armor.
* @return The leggings item stack.
*/
public ItemStack getLeggings() {
return leggings;
}

/**
* Gets the chestplate of the armor.
* @return The chestplate item stack.
*/
public ItemStack getChestplate() {
return chestplate;
}

/**
* Gets the helmet of the armor.
* @return The helmet item stack.
*/
public ItemStack getHelmet() {
return helmet;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.github.unldenis.corpse.manager;
package com.github.unldenis.corpse.pool;

import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.unldenis.corpse.*;
import com.github.unldenis.corpse.corpse.*;
Expand Down Expand Up @@ -49,7 +50,8 @@ public class CorpsePool implements Listener {
private final boolean showTags;
private final boolean renderArmor;
private final boolean lootableCorpses;

private final EntityPose entityPose;

private final Map<Integer, Corpse> corpseMap = new ConcurrentHashMap<>();

private BukkitTask tickTask;
Expand All @@ -66,6 +68,14 @@ private CorpsePool() {
this.renderArmor = config.getBoolean("render-armor");
this.lootableCorpses = config.getBoolean("lootable-corpses");

// get entity pose
String entityPoseString = config.getString("entity-pose");
if (entityPoseString == null) {
this.entityPose = EntityPose.SLEEPING;
} else {
this.entityPose = EntityPose.valueOf(entityPoseString.toUpperCase());
}

Bukkit.getPluginManager().registerEvents(this, plugin);
this.corpseTick();
}
Expand Down Expand Up @@ -178,6 +188,10 @@ public boolean isShowTags() {
return showTags;
}

public EntityPose getEntityPose() {
return entityPose;
}

@Nullable
public BukkitTask getTickTask() {
return tickTask;
Expand Down
6 changes: 5 additions & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ render-armor: true
corpse-distance: 60

## Lootable corpses
lootable-corpses: true
lootable-corpses: true

## Entity Pose to use for the corpses.
## Possible values: SLEEPING, SWIMMING
entity-pose: "SLEEPING"