added
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.bitnix</groupId>
|
||||||
|
<artifactId>DirtHead</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>DirtHead</name>
|
||||||
|
<description>Drops glowing player heads on PvP death with configurable particles.</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.release>21</maven.compiler.release>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>papermc-repo</id>
|
||||||
|
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.papermc.paper</groupId>
|
||||||
|
<artifactId>paper-api</artifactId>
|
||||||
|
<version>1.21.1-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<configuration>
|
||||||
|
<release>21</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
package com.bitnix.dirthead;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Item;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class DirtHeadPlugin extends JavaPlugin implements Listener {
|
||||||
|
|
||||||
|
private final Map<UUID, BukkitTask> particleTasks = new HashMap<>();
|
||||||
|
private final LegacyComponentSerializer legacy = LegacyComponentSerializer.legacyAmpersand();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
saveDefaultConfig();
|
||||||
|
getServer().getPluginManager().registerEvents(this, this);
|
||||||
|
Objects.requireNonNull(getCommand("dirthead")).setExecutor((sender, command, label, args) -> {
|
||||||
|
if (!sender.hasPermission("dirthead.admin")) {
|
||||||
|
sender.sendMessage(color(getConfig().getString("messages.prefix", "&8[&6DirtHead&8] ")
|
||||||
|
+ getConfig().getString("messages.no-permission", "&cYou do not have permission.")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 1 && args[0].equalsIgnoreCase("reload")) {
|
||||||
|
reloadConfig();
|
||||||
|
sender.sendMessage(color(getConfig().getString("messages.prefix", "&8[&6DirtHead&8] ")
|
||||||
|
+ getConfig().getString("messages.reload", "&aConfig reloaded.")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(color(getConfig().getString("messages.prefix", "&8[&6DirtHead&8] ")
|
||||||
|
+ getConfig().getString("messages.usage", "&eUse: /dirthead reload")));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
for (BukkitTask task : particleTasks.values()) {
|
||||||
|
if (task != null) {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
particleTasks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
|
FileConfiguration config = getConfig();
|
||||||
|
|
||||||
|
if (!config.getBoolean("enabled", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config.getBoolean("head.drop-on-pvp-death", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player victim = event.getPlayer();
|
||||||
|
Player killer = victim.getKiller();
|
||||||
|
|
||||||
|
if (killer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (victim.hasPermission("dirthead.bypass")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.getBoolean("head.op-bypass", false) && victim.isOp()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack head = createPlayerHead(victim, killer);
|
||||||
|
if (head == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location dropLocation = victim.getLocation().clone();
|
||||||
|
Item dropped = victim.getWorld().dropItemNaturally(dropLocation, head);
|
||||||
|
|
||||||
|
if (config.getBoolean("head.glowing.enabled", true)) {
|
||||||
|
dropped.setGlowing(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
dropped.setInvulnerable(config.getBoolean("head.invulnerable", true));
|
||||||
|
dropped.setGravity(config.getBoolean("head.gravity", false));
|
||||||
|
dropped.setPickupDelay(Math.max(0, config.getInt("head.pickup-delay-ticks", 40)));
|
||||||
|
|
||||||
|
int despawnSeconds = Math.max(1, config.getInt("head.despawn-after-seconds", 120));
|
||||||
|
getServer().getScheduler().runTaskLater(this, () -> {
|
||||||
|
if (dropped.isValid() && !dropped.isDead()) {
|
||||||
|
cancelParticleTask(dropped.getUniqueId());
|
||||||
|
dropped.remove();
|
||||||
|
}
|
||||||
|
}, despawnSeconds * 20L);
|
||||||
|
|
||||||
|
startParticleTask(dropped);
|
||||||
|
|
||||||
|
if (!config.getBoolean("head.keep-vanilla-drops", true)) {
|
||||||
|
event.getDrops().removeIf(item -> item.getType() == Material.PLAYER_HEAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemStack createPlayerHead(Player victim, Player killer) {
|
||||||
|
ItemStack item = new ItemStack(Material.PLAYER_HEAD);
|
||||||
|
ItemMeta rawMeta = item.getItemMeta();
|
||||||
|
if (!(rawMeta instanceof SkullMeta meta)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta.setOwningPlayer(victim);
|
||||||
|
|
||||||
|
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
String displayName = getConfig().getString("head.name", "&6&l%player%'s Head")
|
||||||
|
.replace("%player%", victim.getName())
|
||||||
|
.replace("%killer%", killer.getName())
|
||||||
|
.replace("%time%", time);
|
||||||
|
|
||||||
|
meta.displayName(color(displayName));
|
||||||
|
|
||||||
|
List<String> loreLines = getConfig().getStringList("head.lore");
|
||||||
|
if (!loreLines.isEmpty()) {
|
||||||
|
List<Component> lore = new ArrayList<>();
|
||||||
|
for (String line : loreLines) {
|
||||||
|
lore.add(color(line
|
||||||
|
.replace("%player%", victim.getName())
|
||||||
|
.replace("%killer%", killer.getName())
|
||||||
|
.replace("%time%", time)));
|
||||||
|
}
|
||||||
|
meta.lore(lore);
|
||||||
|
}
|
||||||
|
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startParticleTask(Item dropped) {
|
||||||
|
FileConfiguration config = getConfig();
|
||||||
|
|
||||||
|
if (!config.getBoolean("particles.enabled", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Particle particle;
|
||||||
|
try {
|
||||||
|
particle = Particle.valueOf(config.getString("particles.particle", "DUST").toUpperCase(Locale.ROOT));
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
getLogger().warning("Invalid particle in config. Falling back to DUST.");
|
||||||
|
particle = Particle.DUST;
|
||||||
|
}
|
||||||
|
|
||||||
|
int interval = Math.max(1, config.getInt("particles.interval-ticks", 10));
|
||||||
|
int count = Math.max(1, config.getInt("particles.count", 8));
|
||||||
|
double offsetX = config.getDouble("particles.offset-x", 0.18);
|
||||||
|
double offsetY = config.getDouble("particles.offset-y", 0.25);
|
||||||
|
double offsetZ = config.getDouble("particles.offset-z", 0.18);
|
||||||
|
double extra = config.getDouble("particles.extra", 0.0);
|
||||||
|
|
||||||
|
Particle finalParticle = particle;
|
||||||
|
|
||||||
|
BukkitTask task = getServer().getScheduler().runTaskTimer(this, () -> {
|
||||||
|
if (!dropped.isValid() || dropped.isDead()) {
|
||||||
|
cancelParticleTask(dropped.getUniqueId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location loc = dropped.getLocation().clone().add(0.0, 0.2, 0.0);
|
||||||
|
|
||||||
|
if (finalParticle == Particle.DUST) {
|
||||||
|
int red = clampColor(getConfig().getInt("particles.color.red", 255));
|
||||||
|
int green = clampColor(getConfig().getInt("particles.color.green", 215));
|
||||||
|
int blue = clampColor(getConfig().getInt("particles.color.blue", 0));
|
||||||
|
float size = (float) getConfig().getDouble("particles.color.size", 1.2);
|
||||||
|
|
||||||
|
Particle.DustOptions dustOptions = new Particle.DustOptions(
|
||||||
|
Color.fromRGB(red, green, blue),
|
||||||
|
Math.max(0.1f, size)
|
||||||
|
);
|
||||||
|
|
||||||
|
dropped.getWorld().spawnParticle(finalParticle, loc, count, offsetX, offsetY, offsetZ, extra, dustOptions);
|
||||||
|
} else {
|
||||||
|
dropped.getWorld().spawnParticle(finalParticle, loc, count, offsetX, offsetY, offsetZ, extra);
|
||||||
|
}
|
||||||
|
}, 0L, interval);
|
||||||
|
|
||||||
|
particleTasks.put(dropped.getUniqueId(), task);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelParticleTask(UUID uuid) {
|
||||||
|
BukkitTask task = particleTasks.remove(uuid);
|
||||||
|
if (task != null) {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int clampColor(int value) {
|
||||||
|
return Math.max(0, Math.min(255, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component color(String text) {
|
||||||
|
return legacy.deserialize(text == null ? "" : text);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
enabled: true
|
||||||
|
|
||||||
|
head:
|
||||||
|
drop-on-pvp-death: true
|
||||||
|
keep-vanilla-drops: true
|
||||||
|
op-bypass: false
|
||||||
|
name: "&6&l%player%'s Head"
|
||||||
|
lore:
|
||||||
|
- "&7Killed by: &c%killer%"
|
||||||
|
- "&7Time: &e%time%"
|
||||||
|
glowing:
|
||||||
|
enabled: true
|
||||||
|
invulnerable: true
|
||||||
|
gravity: false
|
||||||
|
pickup-delay-ticks: 40
|
||||||
|
despawn-after-seconds: 120
|
||||||
|
|
||||||
|
particles:
|
||||||
|
enabled: true
|
||||||
|
particle: "DUST"
|
||||||
|
count: 8
|
||||||
|
offset-x: 0.18
|
||||||
|
offset-y: 0.25
|
||||||
|
offset-z: 0.18
|
||||||
|
extra: 0.0
|
||||||
|
interval-ticks: 10
|
||||||
|
color:
|
||||||
|
red: 255
|
||||||
|
green: 215
|
||||||
|
blue: 0
|
||||||
|
size: 1.2
|
||||||
|
|
||||||
|
messages:
|
||||||
|
prefix: "&8[&6DirtHead&8] "
|
||||||
|
reload: "&aConfig reloaded."
|
||||||
|
no-permission: "&cYou do not have permission."
|
||||||
|
usage: "&eUse: /dirthead reload"
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
name: DirtHead
|
||||||
|
version: 1.0-SNAPSHOT
|
||||||
|
main: com.bitnix.dirthead.DirtHeadPlugin
|
||||||
|
api-version: '1.21'
|
||||||
|
author: bitnix
|
||||||
|
description: Drops glowing player heads on PvP death with configurable particles.
|
||||||
|
commands:
|
||||||
|
dirthead:
|
||||||
|
description: Reload DirtHead config
|
||||||
|
usage: /dirthead reload
|
||||||
|
permission: dirthead.admin
|
||||||
|
permissions:
|
||||||
|
dirthead.admin:
|
||||||
|
description: Allows reloading the DirtHead config
|
||||||
|
default: op
|
||||||
|
dirthead.bypass:
|
||||||
|
description: Prevents your head from dropping on PvP death
|
||||||
|
default: false
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,37 @@
|
|||||||
|
enabled: true
|
||||||
|
|
||||||
|
head:
|
||||||
|
drop-on-pvp-death: true
|
||||||
|
keep-vanilla-drops: true
|
||||||
|
op-bypass: false
|
||||||
|
name: "&6&l%player%'s Head"
|
||||||
|
lore:
|
||||||
|
- "&7Killed by: &c%killer%"
|
||||||
|
- "&7Time: &e%time%"
|
||||||
|
glowing:
|
||||||
|
enabled: true
|
||||||
|
invulnerable: true
|
||||||
|
gravity: false
|
||||||
|
pickup-delay-ticks: 40
|
||||||
|
despawn-after-seconds: 120
|
||||||
|
|
||||||
|
particles:
|
||||||
|
enabled: true
|
||||||
|
particle: "DUST"
|
||||||
|
count: 8
|
||||||
|
offset-x: 0.18
|
||||||
|
offset-y: 0.25
|
||||||
|
offset-z: 0.18
|
||||||
|
extra: 0.0
|
||||||
|
interval-ticks: 10
|
||||||
|
color:
|
||||||
|
red: 255
|
||||||
|
green: 215
|
||||||
|
blue: 0
|
||||||
|
size: 1.2
|
||||||
|
|
||||||
|
messages:
|
||||||
|
prefix: "&8[&6DirtHead&8] "
|
||||||
|
reload: "&aConfig reloaded."
|
||||||
|
no-permission: "&cYou do not have permission."
|
||||||
|
usage: "&eUse: /dirthead reload"
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
name: DirtHead
|
||||||
|
version: 1.0-SNAPSHOT
|
||||||
|
main: com.bitnix.dirthead.DirtHeadPlugin
|
||||||
|
api-version: '1.21'
|
||||||
|
author: bitnix
|
||||||
|
description: Drops glowing player heads on PvP death with configurable particles.
|
||||||
|
commands:
|
||||||
|
dirthead:
|
||||||
|
description: Reload DirtHead config
|
||||||
|
usage: /dirthead reload
|
||||||
|
permission: dirthead.admin
|
||||||
|
permissions:
|
||||||
|
dirthead.admin:
|
||||||
|
description: Allows reloading the DirtHead config
|
||||||
|
default: op
|
||||||
|
dirthead.bypass:
|
||||||
|
description: Prevents your head from dropping on PvP death
|
||||||
|
default: false
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#Generated by Maven
|
||||||
|
#Thu Jun 11 20:29:18 EDT 2026
|
||||||
|
artifactId=DirtHead
|
||||||
|
groupId=com.bitnix
|
||||||
|
version=1.0-SNAPSHOT
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
com/bitnix/dirthead/DirtHeadPlugin.class
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/home/bitnix/Desktop/DirtHead/src/main/java/com/bitnix/dirthead/DirtHeadPlugin.java
|
||||||
Reference in New Issue
Block a user