Skip to content

Commit 38f1caa

Browse files
committed
🐛 Fix 70+ bugs, add DeathMessage module, fix NMS V1_21_8-11 build
Bug fixes (Wave 1-4): - Fix null player checks in 20+ commands (teleport, experience, give, trade, etc.) - Fix == vs .equals() comparisons for player objects in toggle commands - Fix wrong description/message enums in multiple commands - Fix economy NPE (null default economy, min/max swap, wrong reason enum) - Fix null sanction checks in SanctionModule, ZStorageManager, ButtonSanctions - Fix null user checks in autocomplete methods and placeholders - Fix player.isOnline() checks in delayed tasks (night vision) - Fix hologram module null check when NMS class not found - Fix InvseeListener null/offline target player - Add missing onlyPlayers() to CommandScoreboard, CommandTrade, CommandPayToggle - Add null module checks in commands that require modules New features: - DeathMessage module with 25+ purple-themed death cause messages - Per-player death message toggle (/deathmessage command) - Hover details showing death coordinates - Click-to-teleport suggestion on death messages Build fixes: - Fix adventure-text-serializer-ansi dependency resolution for NMS V1_21_8-11 - Add resolution strategy in allprojects for empty version BOM deps
1 parent 0cdf2bb commit 38f1caa

81 files changed

Lines changed: 362 additions & 107 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

API/src/main/java/fr/maxlego08/essentials/api/cache/SimpleCache.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ public V get(K key, Loader<V> loader) {
4242
}
4343

4444

45+
/**
46+
* Clears all entries from the cache.
47+
*/
48+
public void clear() {
49+
this.cache.clear();
50+
}
51+
4552
/**
4653
* Functional interface for loading values into the cache. Implementations of this interface
4754
* provide a method to load a value, typically involving an operation such as fetching data

API/src/main/java/fr/maxlego08/essentials/api/commands/Permission.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,10 @@ public enum Permission {
306306
ESSENTIALS_SIGN_RESET("Allows you to use the <reset> mini message format"),
307307
ESSENTIALS_SIGN_FONT("Allows you to use the <font> mini message format"),
308308
ESSENTIALS_SIGN_KEYBIND("Allows you to use the <key> mini message format"),
309-
ESSENTIALS_STEP_START, ESSENTIALS_STEP_FINISH;
309+
ESSENTIALS_STEP_START, ESSENTIALS_STEP_FINISH,
310+
ESSENTIALS_DEATH_MESSAGE_TELEPORT("Allows clicking death messages to teleport to death location"),
311+
ESSENTIALS_DEATH_MESSAGE_TOGGLE("Allows toggling death messages visibility"),
312+
ESSENTIALS_DEATH_MESSAGE_TOGGLE_OTHER("Allows toggling death messages for other players");
310313

311314
private final String description;
312315
private final String[] args;

API/src/main/java/fr/maxlego08/essentials/api/messages/Message.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@ public enum Message {
433433

434434
TELEPORT_DAMAGE("<error>You must not take damage during teleportation."),
435435
TELEPORT_ERROR_LOCATION("<error>Unable to teleport you safely."),
436+
TELEPORT_CROSS_SERVER_NOT_SUPPORTED("<error>Cross-server teleportation is not supported on this server."),
437+
TELEPORT_CROSS_SERVER_CONNECTING("<success>Connecting to server &f%server%<success>..."),
438+
TELEPORT_CROSS_SERVER_PLAYER_NOT_FOUND("<error>Player &f%player% <error>was not found on any server."),
436439

437440
// RTP Queue System Messages
438441
TELEPORT_ALREADY_IN_QUEUE("<error>You are already in the teleportation queue!"),
@@ -957,6 +960,42 @@ public enum Message {
957960
STEP_DOESNT_EXIST("<error>Step &f%step% <error>does not exist."),
958961
STEP_ALREADY_EXIST("<error>Step &f%step% <error>already started."),
959962
STEP_DOESNT_STARTED("<error>Step &f%step% <error>doesn't started."),
963+
964+
// Death Message Module
965+
DESCRIPTION_DEATH_MESSAGE("Custom death messages"),
966+
967+
DEATH_GENERIC("#C084FC☠ #E9D5FF%player% #B794F4died."),
968+
DEATH_BY_PLAYER("#C084FC⚔ #E9D5FF%player% #B794F4was slain by #E9D5FF%killer%#B794F4."),
969+
DEATH_BY_MOB("#C084FC☠ #E9D5FF%player% #B794F4was killed by #E9D5FF%killer%#B794F4."),
970+
DEATH_BY_PROJECTILE("#C084FC🏹 #E9D5FF%player% #B794F4was shot by #E9D5FF%killer%#B794F4."),
971+
DEATH_BY_MOB_EXPLOSION("#C084FC💥 #E9D5FF%player% #B794F4was blown up by #E9D5FF%killer%#B794F4."),
972+
DEATH_BY_FALL("#C084FC⬇ #E9D5FF%player% #B794F4fell from a high place."),
973+
DEATH_BY_FIRE("#C084FC🔥 #E9D5FF%player% #B794F4burned to death."),
974+
DEATH_BY_LAVA("#C084FC🌋 #E9D5FF%player% #B794F4tried to swim in lava."),
975+
DEATH_BY_DROWNING("#C084FC💧 #E9D5FF%player% #B794F4drowned."),
976+
DEATH_BY_EXPLOSION("#C084FC💥 #E9D5FF%player% #B794F4was blown up."),
977+
DEATH_BY_LIGHTNING("#C084FC⚡ #E9D5FF%player% #B794F4was struck by lightning."),
978+
DEATH_BY_SUFFOCATION("#C084FC▓ #E9D5FF%player% #B794F4suffocated in a wall."),
979+
DEATH_BY_STARVATION("#C084FC🍖 #E9D5FF%player% #B794F4starved to death."),
980+
DEATH_BY_POISON("#C084FC☣ #E9D5FF%player% #B794F4was poisoned."),
981+
DEATH_BY_MAGIC("#C084FC✦ #E9D5FF%player% #B794F4was killed by magic."),
982+
DEATH_BY_WITHER("#C084FC💀 #E9D5FF%player% #B794F4withered away."),
983+
DEATH_BY_FALLING_BLOCK("#C084FC▼ #E9D5FF%player% #B794F4was squashed by a falling block."),
984+
DEATH_BY_FLY_INTO_WALL("#C084FC💨 #E9D5FF%player% #B794F4experienced kinetic energy."),
985+
DEATH_BY_VOID("#C084FC✧ #E9D5FF%player% #B794F4fell out of the world."),
986+
DEATH_BY_CACTUS("#C084FC🌵 #E9D5FF%player% #B794F4was pricked to death."),
987+
DEATH_BY_CRAMMING("#C084FC⊞ #E9D5FF%player% #B794F4was squished too much."),
988+
DEATH_BY_FREEZE("#C084FC❄ #E9D5FF%player% #B794F4froze to death."),
989+
DEATH_BY_SONIC_BOOM("#C084FC◈ #E9D5FF%player% #B794F4was obliterated by a sonic boom."),
990+
DEATH_BY_MAGMA("#C084FC♨ #E9D5FF%player% #B794F4discovered that the floor was lava."),
991+
DEATH_BY_THORNS("#C084FC✵ #E9D5FF%player% #B794F4was killed trying to hurt someone."),
992+
DEATH_BY_CAMPFIRE("#C084FC🔥 #E9D5FF%player% #B794F4walked into a campfire."),
993+
994+
DEATH_HOVER_DETAILS("#D8B4FE☠ Death Location#B794F4:\n#E9D5FF▸ World: #D8B4FE%world%\n#E9D5FF▸ Position: #D8B4FE%x%#E9D5FF, #D8B4FE%y%#E9D5FF, #D8B4FE%z%\n\n#9F7AEA&oClick to teleport"),
995+
996+
COMMAND_DEATH_MESSAGE_TOGGLE_DISABLE("#C084FC☠ #B794F4Death messages are now #E9D5FFhidden #B794F4for %player%#B794F4."),
997+
COMMAND_DEATH_MESSAGE_TOGGLE_ENABLE("#C084FC☠ #B794F4Death messages are now #E9D5FFvisible #B794F4for %player%#B794F4."),
998+
DESCRIPTION_DEATH_MESSAGE_TOGGLE("Toggle death messages visibility"),
960999
;
9611000

9621001
private EssentialsPlugin plugin;

API/src/main/java/fr/maxlego08/essentials/api/modules/Module.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,11 @@ public interface Module extends Listener {
5757
*/
5858
boolean isRegisterEvent();
5959

60+
/**
61+
* Called when the module is being disabled.
62+
*/
63+
default void onDisable() {
64+
}
65+
6066
}
6167

API/src/main/java/fr/maxlego08/essentials/api/user/Option.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ public enum Option {
3131
PHANTOMS_DISABLE,
3232
WORLDEDIT_INVENTORY,
3333
WORLDEDIT_BOSSBAR_DISABLE,
34+
DEATH_MESSAGE_DISABLE,
3435
}

API/src/main/java/fr/maxlego08/essentials/api/utils/SafeLocation.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ public void setPitch(float pitch) {
7878

7979
public Location getLocation() {
8080
if (this.location == null) {
81-
this.location = new Location(Bukkit.getWorld(this.world), this.x, this.y, this.z, this.yaw, this.pitch);
81+
var bukkitWorld = Bukkit.getWorld(this.world);
82+
if (bukkitWorld == null) return null;
83+
this.location = new Location(bukkitWorld, this.x, this.y, this.z, this.yaw, this.pitch);
8284
}
8385
return location;
8486
}

build.gradle.kts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ allprojects {
3232
maven(url = "https://repo.tcoded.com/releases")
3333
}
3434

35+
configurations.all {
36+
resolutionStrategy.eachDependency {
37+
if (requested.group == "net.kyori" && requested.name == "adventure-text-serializer-ansi" && (requested.version.isNullOrBlank() || requested.version == ".")) {
38+
useVersion("4.20.0")
39+
}
40+
}
41+
}
42+
3543
java {
3644
withSourcesJar()
3745

src/main/java/fr/maxlego08/essentials/buttons/sanction/ButtonSanctions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ private void displaySanction(int slot, Sanction sanction, Player player, User ta
6060
placeholders.register("reason", sanction.getReason());
6161
placeholders.register("duration", TimerBuilder.getStringTime(sanction.getDuration()));
6262
placeholders.register("remaining", sanction.isActive() ? TimerBuilder.getStringTime(sanction.getDurationRemaining().toMillis()) : Message.EXPIRED.getMessageAsString());
63-
placeholders.register("created_at", simpleDateFormat.format(sanction.getCreatedAt()));
64-
placeholders.register("expired_at", simpleDateFormat.format(sanction.getExpiredAt()));
63+
placeholders.register("created_at", sanction.getCreatedAt() != null ? simpleDateFormat.format(sanction.getCreatedAt()) : "N/A");
64+
placeholders.register("expired_at", sanction.getExpiredAt() != null ? simpleDateFormat.format(sanction.getExpiredAt()) : "N/A");
6565
placeholders.register("sender", sanctionModule.getSanctionBy(sanction.getSenderUniqueId()));
6666

6767
inventory.addItem(slot, menuItemStack.build(player, false, placeholders));

src/main/java/fr/maxlego08/essentials/commands/CommandLoader.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import fr.maxlego08.essentials.commands.commands.chat.CommandShowItem;
1313
import fr.maxlego08.essentials.commands.commands.clearinventory.ClearInventoryCommand;
1414
import fr.maxlego08.essentials.commands.commands.cooldown.CommandCooldown;
15+
import fr.maxlego08.essentials.commands.commands.deathmessage.CommandDeathMessageToggle;
1516
import fr.maxlego08.essentials.commands.commands.discord.CommandLink;
1617
import fr.maxlego08.essentials.commands.commands.discord.CommandUnLink;
1718
import fr.maxlego08.essentials.commands.commands.economy.CommandBalanceTop;
@@ -283,6 +284,7 @@ public void loadCommands(CommandManager commandManager) {
283284

284285
register("pub", CommandPub.class);
285286
register("step", CommandStep.class);
287+
register("deathmessage", CommandDeathMessageToggle.class, "dm", "deathmsg");
286288

287289
for (RegisterCommand registerCommand : this.commands) {
288290
try {

src/main/java/fr/maxlego08/essentials/commands/ZCommandManager.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ public class ZCommandManager extends ZUtils implements CommandManager {
4545
commandMap = (CommandMap) bukkitCommandMap.get(Bukkit.getServer());
4646
constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
4747
constructor.setAccessible(true);
48-
} catch (Exception ignored) {
48+
} catch (Exception exception) {
49+
Bukkit.getLogger().severe("[zEssentials] Failed to initialize command map or PluginCommand constructor: " + exception.getMessage());
50+
exception.printStackTrace();
4951
}
5052
}
5153

@@ -285,6 +287,11 @@ public void registerCommand(Plugin plugin, String mainCommand, EssentialsCommand
285287
}
286288

287289
try {
290+
if (constructor == null || commandMap == null) {
291+
this.plugin.getLogger().severe("Cannot register command '" + mainCommand + "': CommandMap or PluginCommand constructor is not initialized!");
292+
return;
293+
}
294+
288295
PluginCommand command = constructor.newInstance(mainCommand, plugin);
289296
command.setExecutor(this);
290297
command.setTabCompleter(this);
@@ -298,7 +305,7 @@ public void registerCommand(Plugin plugin, String mainCommand, EssentialsCommand
298305
commands.add(essentialsCommand);
299306

300307
if (!commandMap.register(command.getName(), plugin.getDescription().getName(), command)) {
301-
plugin.getLogger().info("Unable to add the command " + essentialsCommand.getSyntax());
308+
plugin.getLogger().warning("Unable to add the command /" + mainCommand + " (already registered by another plugin). Use /zessentials:" + mainCommand + " instead.");
302309
}
303310

304311
if (essentialsCommand.getPermission() != null) {
@@ -309,6 +316,7 @@ public void registerCommand(Plugin plugin, String mainCommand, EssentialsCommand
309316
Bukkit.getPluginManager().addPermission(new Permission(essentialsCommand.getPermission(), essentialsCommand.getDescription() == null ? "No description" : essentialsCommand.getDescription()));
310317
}
311318
} catch (Exception exception) {
319+
this.plugin.getLogger().severe("Failed to register command '" + mainCommand + "': " + exception.getMessage());
312320
exception.printStackTrace();
313321
}
314322
}

0 commit comments

Comments
 (0)