From 6ad9407cb48021347676ba198256151ba4fe7654 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Thu, 13 Aug 2026 10:14:38 +0200 Subject: [PATCH 01/21] Creating a first test, to verify if my install worked properly --- .../gameplay/mobSilenceNametag/FirstTestClass.java | 12 ++++++++++++ .../mobSilenceNametag/FirstTestListener.java | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java new file mode 100644 index 0000000..c4f5055 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java @@ -0,0 +1,12 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.mobSilenceNametag; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import org.bukkit.entity.Player; + +public class FirstTestClass extends Appliance { + + public String greetPlayer(Player player) { + return "Hello, " + player.getName() + "! Test 1"; + } + +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java new file mode 100644 index 0000000..2ca719e --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java @@ -0,0 +1,12 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.mobSilenceNametag; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.event.EventHandler; + +public class FirstTestListener extends ApplianceListener { + @EventHandler + public void onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) { + String greeting = this.getAppliance().greetPlayer(event.getPlayer()); + event.getPlayer().sendMessage(greeting); + } +} From 673bae4d50189242b863cfaae6be2085cc8466ed Mon Sep 17 00:00:00 2001 From: David Rauh Date: Thu, 13 Aug 2026 10:33:38 +0200 Subject: [PATCH 02/21] Fixing my first test, to verify if my install worked properly --- .../gameplay/mobSilenceNametag/FirstTestClass.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java index c4f5055..9c7e8c2 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java @@ -2,6 +2,10 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.mobSilenceName import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +import java.util.List; public class FirstTestClass extends Appliance { @@ -9,4 +13,9 @@ public class FirstTestClass extends Appliance { return "Hello, " + player.getName() + "! Test 1"; } + protected @NotNull List listeners() { + return List.of(new FirstTestListener()); + } + + } From f615dc867aac714c7ed79c520281e6b9473a89a0 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Thu, 13 Aug 2026 13:09:14 +0200 Subject: [PATCH 03/21] Rerunning my first test, to verify if my install worked properly --- .../appliances/gameplay/mobSilenceNametag/FirstTestClass.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java index 9c7e8c2..fdb473f 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java @@ -10,7 +10,7 @@ import java.util.List; public class FirstTestClass extends Appliance { public String greetPlayer(Player player) { - return "Hello, " + player.getName() + "! Test 1"; + return "Hello, " + player.getName() + "! Test 2"; } protected @NotNull List listeners() { From 3221450cde1a6d879e66fc7eff7fa8f2208f43ef Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 14:53:13 +0200 Subject: [PATCH 04/21] Clean up test scripts and to prepare for development of the feature --- .../mobSilenceNametag/FirstTestClass.java | 21 ------------------- .../mobSilenceNametag/FirstTestListener.java | 12 ----------- 2 files changed, 33 deletions(-) delete mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java delete mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java deleted file mode 100644 index fdb473f..0000000 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestClass.java +++ /dev/null @@ -1,21 +0,0 @@ -package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.mobSilenceNametag; - -import eu.mhsl.craftattack.spawn.core.appliance.Appliance; -import org.bukkit.entity.Player; -import org.bukkit.event.Listener; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public class FirstTestClass extends Appliance { - - public String greetPlayer(Player player) { - return "Hello, " + player.getName() + "! Test 2"; - } - - protected @NotNull List listeners() { - return List.of(new FirstTestListener()); - } - - -} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java deleted file mode 100644 index 2ca719e..0000000 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/mobSilenceNametag/FirstTestListener.java +++ /dev/null @@ -1,12 +0,0 @@ -package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.mobSilenceNametag; - -import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; -import org.bukkit.event.EventHandler; - -public class FirstTestListener extends ApplianceListener { - @EventHandler - public void onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) { - String greeting = this.getAppliance().greetPlayer(event.getPlayer()); - event.getPlayer().sendMessage(greeting); - } -} From dd2d71d7544806b12b860b1394469298768e3d0f Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 15:28:11 +0200 Subject: [PATCH 05/21] Created necessary classes and implement console logs for PrepareAnvilEvent --- .../silenceNametag/NametagAnvilListener.java | 18 ++++++++++++++++++ .../silenceNametag/SilenceNametag.java | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java new file mode 100644 index 0000000..e07ea9d --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -0,0 +1,18 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.event.EventHandler; +import org.bukkit.event.inventory.PrepareAnvilEvent; +import org.bukkit.inventory.view.AnvilView; + +public class NametagAnvilListener extends ApplianceListener { + @EventHandler + public void onAnvilRename(PrepareAnvilEvent event){ + System.out.println("Anvil prepare event triggered"); + AnvilView anvilView = event.getView(); + System.out.println(anvilView.getItem(1)); + System.out.println(anvilView.getItem(2)); + System.out.println(anvilView.getItem(3)); + System.out.println(anvilView.getRenameText()); + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java new file mode 100644 index 0000000..24c52c6 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -0,0 +1,18 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import org.bukkit.NamespacedKey; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Objects; + +public class SilenceNametag extends Appliance { + public static final @NotNull NamespacedKey silenceNametag = Objects.requireNonNull(NamespacedKey.fromString("silence_nametag")); + + @Override + protected @NotNull List listeners() { + return List.of(new NametagAnvilListener()); + } +} From 15ee6ee79ebc82ba31ccf059941fd8204680816f Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 15:40:12 +0200 Subject: [PATCH 06/21] catch anvil event and return if not a nametag --- .../gameplay/silenceNametag/NametagAnvilListener.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index e07ea9d..2472b04 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -1,18 +1,20 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.inventory.PrepareAnvilEvent; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.view.AnvilView; public class NametagAnvilListener extends ApplianceListener { @EventHandler public void onAnvilRename(PrepareAnvilEvent event){ - System.out.println("Anvil prepare event triggered"); AnvilView anvilView = event.getView(); - System.out.println(anvilView.getItem(1)); - System.out.println(anvilView.getItem(2)); - System.out.println(anvilView.getItem(3)); + ItemStack input = anvilView.getItem(0); + if(input == null || input.getType() != Material.NAME_TAG) return; + + ItemStack result = anvilView.getItem(2); System.out.println(anvilView.getRenameText()); } } From b1c92310cb403b89ef2baac457bc1c71d4d43f34 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 16:25:18 +0200 Subject: [PATCH 07/21] setting the lore of the result item --- .../silenceNametag/NametagAnvilListener.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index 2472b04..b8b0bd5 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -1,20 +1,38 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.inventory.PrepareAnvilEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.view.AnvilView; +import java.util.ArrayList; +import java.util.List; + public class NametagAnvilListener extends ApplianceListener { @EventHandler public void onAnvilRename(PrepareAnvilEvent event){ - AnvilView anvilView = event.getView(); - ItemStack input = anvilView.getItem(0); - if(input == null || input.getType() != Material.NAME_TAG) return; + ItemStack resultItem = event.getResult(); + if(resultItem == null) return; - ItemStack result = anvilView.getItem(2); - System.out.println(anvilView.getRenameText()); + + AnvilView anvilView = event.getView(); + ItemStack inputItem = anvilView.getItem(0); + if(inputItem == null || inputItem.getType() != Material.NAME_TAG) return; + + + if(!"@verstummen".equals(anvilView.getRenameText()) + && !"@entstummen".equals(anvilView.getRenameText())) return; + + resultItem.editMeta(meta -> { + List lore = meta.hasLore() ? meta.lore() : new ArrayList<>(); + if("@verstummen".equals(anvilView.getRenameText())) { + lore.add(Component.text("Dieses Namensschild verstummt Mobs.")); + } else if("@entstummen".equals(anvilView.getRenameText())) { + lore.add(Component.text("Dieses Namensschild entstummt Mobs.")); + } + }); } } From 1dbc9b29a3679f9f88b24b0310d5e99d6227a398 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 16:32:39 +0200 Subject: [PATCH 08/21] adding logging to debug --- .../gameplay/silenceNametag/NametagAnvilListener.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index b8b0bd5..6ed1a65 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -27,12 +27,18 @@ public class NametagAnvilListener extends ApplianceListener { && !"@entstummen".equals(anvilView.getRenameText())) return; resultItem.editMeta(meta -> { + System.out.println("editing meta for " + anvilView.getRenameText()); List lore = meta.hasLore() ? meta.lore() : new ArrayList<>(); if("@verstummen".equals(anvilView.getRenameText())) { + System.out.println("Adding lore for @verstummen"); lore.add(Component.text("Dieses Namensschild verstummt Mobs.")); } else if("@entstummen".equals(anvilView.getRenameText())) { + System.out.println("Adding lore for @entstummen"); lore.add(Component.text("Dieses Namensschild entstummt Mobs.")); } + if(meta.hasItemName()){ + meta.customName(meta.itemName()); + } }); } } From 410658259dee4bd585116b452908d823ab14f55e Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 16:36:59 +0200 Subject: [PATCH 09/21] setting the result item in the anvil --- .../gameplay/silenceNametag/NametagAnvilListener.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index 6ed1a65..c9bdc9e 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -40,5 +40,7 @@ public class NametagAnvilListener extends ApplianceListener { meta.customName(meta.itemName()); } }); + + event.setResult(resultItem); } } From aebd7f7bc8af288f85be1ea8d1829b8dca80ab5f Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 16:45:14 +0200 Subject: [PATCH 10/21] fix: ensure lore is correctly initialized when editing item meta --- .../gameplay/silenceNametag/NametagAnvilListener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index c9bdc9e..43ce4c5 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -28,7 +28,7 @@ public class NametagAnvilListener extends ApplianceListener { resultItem.editMeta(meta -> { System.out.println("editing meta for " + anvilView.getRenameText()); - List lore = meta.hasLore() ? meta.lore() : new ArrayList<>(); + List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); if("@verstummen".equals(anvilView.getRenameText())) { System.out.println("Adding lore for @verstummen"); lore.add(Component.text("Dieses Namensschild verstummt Mobs.")); @@ -39,6 +39,7 @@ public class NametagAnvilListener extends ApplianceListener { if(meta.hasItemName()){ meta.customName(meta.itemName()); } + meta.lore(lore); }); event.setResult(resultItem); From 0f415b9aba16fafa1014eeed5cadf99f6ecb5664 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Tue, 18 Aug 2026 17:12:02 +0200 Subject: [PATCH 11/21] refactor: streamline nametag action handling and update lore management --- .../silenceNametag/NametagAnvilListener.java | 22 ++------ .../silenceNametag/SilenceNametag.java | 54 ++++++++++++++++++- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index 43ce4c5..01da3bb 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -23,25 +23,9 @@ public class NametagAnvilListener extends ApplianceListener { if(inputItem == null || inputItem.getType() != Material.NAME_TAG) return; - if(!"@verstummen".equals(anvilView.getRenameText()) - && !"@entstummen".equals(anvilView.getRenameText())) return; + if(!SilenceNametag.muteString.equals(anvilView.getRenameText()) + && !SilenceNametag.unmuteString.equals(anvilView.getRenameText())) return; - resultItem.editMeta(meta -> { - System.out.println("editing meta for " + anvilView.getRenameText()); - List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); - if("@verstummen".equals(anvilView.getRenameText())) { - System.out.println("Adding lore for @verstummen"); - lore.add(Component.text("Dieses Namensschild verstummt Mobs.")); - } else if("@entstummen".equals(anvilView.getRenameText())) { - System.out.println("Adding lore for @entstummen"); - lore.add(Component.text("Dieses Namensschild entstummt Mobs.")); - } - if(meta.hasItemName()){ - meta.customName(meta.itemName()); - } - meta.lore(lore); - }); - - event.setResult(resultItem); + event.setResult(this.getAppliance().createSilenceNametag(resultItem, anvilView.getRenameText())); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index 24c52c6..c1cc9e4 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -1,15 +1,67 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import net.kyori.adventure.text.Component; import org.bukkit.NamespacedKey; import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; import java.util.Objects; public class SilenceNametag extends Appliance { - public static final @NotNull NamespacedKey silenceNametag = Objects.requireNonNull(NamespacedKey.fromString("silence_nametag")); + public static final String pluginName = "silence-nametag"; + public static final String muteString = "@verstummen"; + public static final String unmuteString = "@entstummen"; + + public enum NametagActions { + SILENCE, + UNSILENCE + } + + NamespacedKey nametagActionKey = + new NamespacedKey(pluginName, "nametag-action"); + + ItemStack setNametagAction(ItemStack item, NametagActions action) { + Objects.requireNonNull(item, "item must not be null"); + item.editPersistentDataContainer(pdc -> { + pdc.set( + nametagActionKey, + PersistentDataType.INTEGER, + action.ordinal() + ); + }); + item.editMeta(meta -> { + List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); + if(action == NametagActions.SILENCE) { + lore.add(Component.text("Dieses Namensschild verstummt Mobs.")); + } else if (action == NametagActions.UNSILENCE){ + lore.add(Component.text("Dieses Namensschild entstummt Mobs.")); + } + meta.customName(null); + meta.lore(lore); + }); + return item; + } + + NametagActions getNametagAction(ItemStack item) { + Objects.requireNonNull(item, "item must not be null"); + return item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER) == null + ? null + : NametagActions.values()[item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER)]; + } + + public ItemStack createSilenceNametag(ItemStack oldResultItem, String renameText){ + if(renameText.equals(muteString)) { + return this.setNametagAction(oldResultItem, NametagActions.SILENCE); + } else if(renameText.equals(unmuteString)) { + return this.setNametagAction(oldResultItem, NametagActions.UNSILENCE); + } + return oldResultItem; + } @Override protected @NotNull List listeners() { From 167ed811b6d6ab1142f59fac88c08392de7fc167 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Sat, 19 Sep 2026 21:12:36 +0200 Subject: [PATCH 12/21] fix: update lore text for silence nametag and improve nullability handling --- .../gameplay/silenceNametag/NametagAnvilListener.java | 11 ++++------- .../gameplay/silenceNametag/SilenceNametag.java | 7 ++++--- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index 01da3bb..bd265b6 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -1,16 +1,12 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; -import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.inventory.PrepareAnvilEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.view.AnvilView; -import java.util.ArrayList; -import java.util.List; - public class NametagAnvilListener extends ApplianceListener { @EventHandler public void onAnvilRename(PrepareAnvilEvent event){ @@ -22,10 +18,11 @@ public class NametagAnvilListener extends ApplianceListener { ItemStack inputItem = anvilView.getItem(0); if(inputItem == null || inputItem.getType() != Material.NAME_TAG) return; + String renameText = anvilView.getRenameText(); - if(!SilenceNametag.muteString.equals(anvilView.getRenameText()) - && !SilenceNametag.unmuteString.equals(anvilView.getRenameText())) return; + if(!SilenceNametag.muteString.equals(renameText) + && !SilenceNametag.unmuteString.equals(renameText)) return; - event.setResult(this.getAppliance().createSilenceNametag(resultItem, anvilView.getRenameText())); + event.setResult(this.getAppliance().createSilenceNametag(resultItem, renameText)); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index c1cc9e4..99d4499 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -7,6 +7,7 @@ import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -37,9 +38,9 @@ public class SilenceNametag extends Appliance { item.editMeta(meta -> { List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); if(action == NametagActions.SILENCE) { - lore.add(Component.text("Dieses Namensschild verstummt Mobs.")); + lore.add(Component.text("Dieser Name Tag verstummt Mobs.")); } else if (action == NametagActions.UNSILENCE){ - lore.add(Component.text("Dieses Namensschild entstummt Mobs.")); + lore.add(Component.text("Dieser Name Tag entstummt Mobs.")); } meta.customName(null); meta.lore(lore); @@ -47,7 +48,7 @@ public class SilenceNametag extends Appliance { return item; } - NametagActions getNametagAction(ItemStack item) { + @Nullable NametagActions getNametagAction(ItemStack item) { Objects.requireNonNull(item, "item must not be null"); return item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER) == null ? null From 3513477265d64a5d465f3b357e73e3509a542f42 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Fri, 25 Sep 2026 16:22:32 +0200 Subject: [PATCH 13/21] refactor: enhance nametag action handling and improve lore management --- .../silenceNametag/NametagAnvilListener.java | 1 - .../silenceNametag/SilenceNametag.java | 41 +++++++++++++------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index bd265b6..de9b6f9 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -13,7 +13,6 @@ public class NametagAnvilListener extends ApplianceListener { ItemStack resultItem = event.getResult(); if(resultItem == null) return; - AnvilView anvilView = event.getView(); ItemStack inputItem = anvilView.getItem(0); if(inputItem == null || inputItem.getType() != Material.NAME_TAG) return; diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index 99d4499..fdeed7a 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -27,14 +27,30 @@ public class SilenceNametag extends Appliance { new NamespacedKey(pluginName, "nametag-action"); ItemStack setNametagAction(ItemStack item, NametagActions action) { - Objects.requireNonNull(item, "item must not be null"); - item.editPersistentDataContainer(pdc -> { - pdc.set( - nametagActionKey, - PersistentDataType.INTEGER, - action.ordinal() - ); + Objects.requireNonNull(item, "Item must not be null."); + setPersistentDataOfNametag(item, action); + removeLoreOfNametag(item); + setLoreOfNametag(item, action); + return item; + } + + void setPersistentDataOfNametag(ItemStack item, NametagActions action){ + item.editPersistentDataContainer(pdc -> pdc.set( + nametagActionKey, + PersistentDataType.INTEGER, + action.ordinal() + )); + } + + void removeLoreOfNametag(ItemStack item){ + item.editMeta(meta -> { + List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); + lore.removeIf(line -> line.toString().contains("Dieser Name Tag")); + meta.lore(lore); }); + } + + void setLoreOfNametag(ItemStack item, NametagActions action){ item.editMeta(meta -> { List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); if(action == NametagActions.SILENCE) { @@ -45,23 +61,22 @@ public class SilenceNametag extends Appliance { meta.customName(null); meta.lore(lore); }); - return item; } @Nullable NametagActions getNametagAction(ItemStack item) { - Objects.requireNonNull(item, "item must not be null"); + Objects.requireNonNull(item, "Item must not be null."); return item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER) == null ? null : NametagActions.values()[item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER)]; } - public ItemStack createSilenceNametag(ItemStack oldResultItem, String renameText){ + public ItemStack createSilenceNametag(ItemStack ResultItem, String renameText){ if(renameText.equals(muteString)) { - return this.setNametagAction(oldResultItem, NametagActions.SILENCE); + return this.setNametagAction(ResultItem, NametagActions.SILENCE); } else if(renameText.equals(unmuteString)) { - return this.setNametagAction(oldResultItem, NametagActions.UNSILENCE); + return this.setNametagAction(ResultItem, NametagActions.UNSILENCE); } - return oldResultItem; + return ResultItem; } @Override From 879dfb9bdd9c1d3a401a239c046f1403103aaafd Mon Sep 17 00:00:00 2001 From: David Rauh Date: Fri, 25 Sep 2026 16:47:48 +0200 Subject: [PATCH 14/21] feat: add NametagEntityListener to handle special nametag interactions --- .../silenceNametag/NametagEntityListener.java | 32 +++++++++++++++++++ .../silenceNametag/SilenceNametag.java | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java new file mode 100644 index 0000000..7922769 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -0,0 +1,32 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; + +public class NametagEntityListener extends ApplianceListener { + @EventHandler + public void onNametagUse(PlayerInteractEntityEvent event){ + ItemStack item; + + if (event.getHand() == EquipmentSlot.HAND) { + item = event.getPlayer().getInventory().getItemInMainHand(); + } else { + item = event.getPlayer().getInventory().getItemInOffHand(); + } + + if(item.getType() != Material.NAME_TAG) return; + + if(!item.getItemMeta().getPersistentDataContainer().has( + this.getAppliance().nametagActionKey, + PersistentDataType.INTEGER + )) return; + + System.out.println("NametagEntityListener: Player " + event.getPlayer().getName() + " used a special nametag on entity " + event.getRightClicked().getType()); + + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index fdeed7a..6751984 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -81,6 +81,6 @@ public class SilenceNametag extends Appliance { @Override protected @NotNull List listeners() { - return List.of(new NametagAnvilListener()); + return List.of(new NametagAnvilListener(), new NametagEntityListener()); } } From 091bc8f10c91d484e233e5cbe9aaf65acbc56a5e Mon Sep 17 00:00:00 2001 From: David Rauh Date: Fri, 25 Sep 2026 16:53:22 +0200 Subject: [PATCH 15/21] feat: implement silence and unsilence actions in NametagEntityListener --- .../silenceNametag/NametagEntityListener.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java index 7922769..7814d11 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -1,6 +1,8 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerInteractEntityEvent; @@ -26,7 +28,18 @@ public class NametagEntityListener extends ApplianceListener { PersistentDataType.INTEGER )) return; - System.out.println("NametagEntityListener: Player " + event.getPlayer().getName() + " used a special nametag on entity " + event.getRightClicked().getType()); - + if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.SILENCE) { + event.getRightClicked().setSilent(true); + event.getPlayer().sendMessage( + Component.text("Der Mob wurde verstummt.") + .color(NamedTextColor.GREEN) + ); + } else if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.UNSILENCE) { + event.getRightClicked().setSilent(false); + event.getPlayer().sendMessage( + Component.text("Der Mob wurde entstummt.") + .color(NamedTextColor.GREEN) + ); + } } } From 98dc59ca15b58ef5ede108da1d28d117c07d40ab Mon Sep 17 00:00:00 2001 From: David Rauh Date: Fri, 25 Sep 2026 17:19:54 +0200 Subject: [PATCH 16/21] feat: enhance silence and unsilence functionality and manage nametag item amount --- .../gameplay/silenceNametag/NametagEntityListener.java | 9 +++++++++ .../gameplay/silenceNametag/SilenceNametag.java | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java index 7814d11..e7be5b4 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -16,8 +16,10 @@ public class NametagEntityListener extends ApplianceListener { ItemStack item; if (event.getHand() == EquipmentSlot.HAND) { + System.out.println("Using main hand"); item = event.getPlayer().getInventory().getItemInMainHand(); } else { + System.out.println("Using off hand"); item = event.getPlayer().getInventory().getItemInOffHand(); } @@ -29,17 +31,24 @@ public class NametagEntityListener extends ApplianceListener { )) return; if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.SILENCE) { + System.out.println("Silencing mob"); event.getRightClicked().setSilent(true); event.getPlayer().sendMessage( Component.text("Der Mob wurde verstummt.") .color(NamedTextColor.GREEN) ); } else if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.UNSILENCE) { + System.out.println("Unsilencing mob"); event.getRightClicked().setSilent(false); event.getPlayer().sendMessage( Component.text("Der Mob wurde entstummt.") .color(NamedTextColor.GREEN) ); } + + if (item.getItemMeta().customName() == null){ + System.out.println("Nametag has no custom name, reducing amount"); + item.setAmount(item.getAmount() - 1); + } } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index 6751984..aa1d0d0 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -31,6 +31,7 @@ public class SilenceNametag extends Appliance { setPersistentDataOfNametag(item, action); removeLoreOfNametag(item); setLoreOfNametag(item, action); + restoreDefaultNameOfNametag(item); return item; } @@ -58,11 +59,16 @@ public class SilenceNametag extends Appliance { } else if (action == NametagActions.UNSILENCE){ lore.add(Component.text("Dieser Name Tag entstummt Mobs.")); } - meta.customName(null); meta.lore(lore); }); } + void restoreDefaultNameOfNametag(ItemStack item){ + item.editMeta(meta -> { + meta.customName(null); + }); + } + @Nullable NametagActions getNametagAction(ItemStack item) { Objects.requireNonNull(item, "Item must not be null."); return item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER) == null From 961a22beac694d1db9f0a5d161638bf0b1f9fe6f Mon Sep 17 00:00:00 2001 From: David Rauh Date: Fri, 25 Sep 2026 17:24:50 +0200 Subject: [PATCH 17/21] feat: improve silence and unsilence feedback for mobs in NametagEntityListener --- .../silenceNametag/NametagEntityListener.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java index e7be5b4..dfa5bf5 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -4,6 +4,7 @@ import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; +import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.inventory.EquipmentSlot; @@ -30,23 +31,39 @@ public class NametagEntityListener extends ApplianceListener { PersistentDataType.INTEGER )) return; + Entity mob = event.getRightClicked(); + if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.SILENCE) { + if(mob.isSilent()) { + event.getPlayer().sendMessage( + Component.text("Der Mob ist bereits verstummt.") + .color(NamedTextColor.RED) + ); + return; + } System.out.println("Silencing mob"); - event.getRightClicked().setSilent(true); + mob.setSilent(true); event.getPlayer().sendMessage( Component.text("Der Mob wurde verstummt.") .color(NamedTextColor.GREEN) ); } else if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.UNSILENCE) { + if (!mob.isSilent()) { + event.getPlayer().sendMessage( + Component.text("Der Mob ist bereits entstummt.") + .color(NamedTextColor.RED) + ); + return; + } System.out.println("Unsilencing mob"); - event.getRightClicked().setSilent(false); + mob.setSilent(false); event.getPlayer().sendMessage( Component.text("Der Mob wurde entstummt.") .color(NamedTextColor.GREEN) ); } - if (item.getItemMeta().customName() == null){ + if (item.getItemMeta().customName() == null && event.getPlayer().getGameMode() != org.bukkit.GameMode.CREATIVE) { System.out.println("Nametag has no custom name, reducing amount"); item.setAmount(item.getAmount() - 1); } From f1250f2879949557310d6fafe74fd804d958c5dc Mon Sep 17 00:00:00 2001 From: David Rauh Date: Fri, 25 Sep 2026 17:37:25 +0200 Subject: [PATCH 18/21] feat: streamline silence and unsilence logic in NametagEntityListener --- .../silenceNametag/NametagEntityListener.java | 33 ++----------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java index dfa5bf5..d7bf3d0 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -1,8 +1,6 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; @@ -17,10 +15,8 @@ public class NametagEntityListener extends ApplianceListener { ItemStack item; if (event.getHand() == EquipmentSlot.HAND) { - System.out.println("Using main hand"); item = event.getPlayer().getInventory().getItemInMainHand(); } else { - System.out.println("Using off hand"); item = event.getPlayer().getInventory().getItemInOffHand(); } @@ -34,37 +30,14 @@ public class NametagEntityListener extends ApplianceListener { Entity mob = event.getRightClicked(); if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.SILENCE) { - if(mob.isSilent()) { - event.getPlayer().sendMessage( - Component.text("Der Mob ist bereits verstummt.") - .color(NamedTextColor.RED) - ); - return; - } - System.out.println("Silencing mob"); + if(mob.isSilent()) return; mob.setSilent(true); - event.getPlayer().sendMessage( - Component.text("Der Mob wurde verstummt.") - .color(NamedTextColor.GREEN) - ); } else if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.UNSILENCE) { - if (!mob.isSilent()) { - event.getPlayer().sendMessage( - Component.text("Der Mob ist bereits entstummt.") - .color(NamedTextColor.RED) - ); - return; - } - System.out.println("Unsilencing mob"); + if (!mob.isSilent()) return; mob.setSilent(false); - event.getPlayer().sendMessage( - Component.text("Der Mob wurde entstummt.") - .color(NamedTextColor.GREEN) - ); } - if (item.getItemMeta().customName() == null && event.getPlayer().getGameMode() != org.bukkit.GameMode.CREATIVE) { - System.out.println("Nametag has no custom name, reducing amount"); + if (item.getItemMeta().customName() == null) { item.setAmount(item.getAmount() - 1); } } From 5ae2ac933aaa51580d9c2d91e7308cda5ba6ce12 Mon Sep 17 00:00:00 2001 From: David Rauh Date: Fri, 25 Sep 2026 17:56:08 +0200 Subject: [PATCH 19/21] feat: refactor silence and unsilence logic into applyNametagAction method in SilenceNametag --- .../silenceNametag/NametagEntityListener.java | 15 +-------- .../silenceNametag/SilenceNametag.java | 32 +++++++++++++++---- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java index d7bf3d0..e5624a7 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -2,7 +2,6 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; import org.bukkit.Material; -import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.inventory.EquipmentSlot; @@ -27,18 +26,6 @@ public class NametagEntityListener extends ApplianceListener { PersistentDataType.INTEGER )) return; - Entity mob = event.getRightClicked(); - - if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.SILENCE) { - if(mob.isSilent()) return; - mob.setSilent(true); - } else if (getAppliance().getNametagAction(item) == SilenceNametag.NametagActions.UNSILENCE) { - if (!mob.isSilent()) return; - mob.setSilent(false); - } - - if (item.getItemMeta().customName() == null) { - item.setAmount(item.getAmount() - 1); - } + getAppliance().applyNametagAction(item, event.getRightClicked()); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index aa1d0d0..e6f5b8f 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -3,6 +3,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import net.kyori.adventure.text.Component; import org.bukkit.NamespacedKey; +import org.bukkit.entity.Entity; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; @@ -26,6 +27,9 @@ public class SilenceNametag extends Appliance { NamespacedKey nametagActionKey = new NamespacedKey(pluginName, "nametag-action"); + private final Component silenceNametagLore = Component.text("Dieses Namensschild verstummt Mobs."); + private final Component unsilenceNametagLore = Component.text("Dieses Namensschild entstummt Mobs."); + ItemStack setNametagAction(ItemStack item, NametagActions action) { Objects.requireNonNull(item, "Item must not be null."); setPersistentDataOfNametag(item, action); @@ -46,7 +50,9 @@ public class SilenceNametag extends Appliance { void removeLoreOfNametag(ItemStack item){ item.editMeta(meta -> { List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); - lore.removeIf(line -> line.toString().contains("Dieser Name Tag")); + lore.removeIf(line -> + line.toString().contains(silenceNametagLore.toString()) + || line.toString().contains(unsilenceNametagLore.toString())); meta.lore(lore); }); } @@ -55,18 +61,16 @@ public class SilenceNametag extends Appliance { item.editMeta(meta -> { List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); if(action == NametagActions.SILENCE) { - lore.add(Component.text("Dieser Name Tag verstummt Mobs.")); + lore.add(silenceNametagLore); } else if (action == NametagActions.UNSILENCE){ - lore.add(Component.text("Dieser Name Tag entstummt Mobs.")); + lore.add(unsilenceNametagLore); } meta.lore(lore); }); } void restoreDefaultNameOfNametag(ItemStack item){ - item.editMeta(meta -> { - meta.customName(null); - }); + item.editMeta(meta -> meta.customName(null)); } @Nullable NametagActions getNametagAction(ItemStack item) { @@ -85,6 +89,22 @@ public class SilenceNametag extends Appliance { return ResultItem; } + public void applyNametagAction(ItemStack item, Entity mob) { + if (getNametagAction(item) == SilenceNametag.NametagActions.SILENCE) { + if(mob.isSilent()) return; + mob.setSilent(true); + } else if (getNametagAction(item) == SilenceNametag.NametagActions.UNSILENCE) { + if (!mob.isSilent()) return; + mob.setSilent(false); + } + + // Consume one unnamed nametag manually. + // Custom-named tags use vanilla nametag behavior, including item consumption. + if (item.getItemMeta().customName() == null) { + item.setAmount(item.getAmount() - 1); + } + } + @Override protected @NotNull List listeners() { return List.of(new NametagAnvilListener(), new NametagEntityListener()); From fb78a450b8c899ffa0142b2b8ad7d7d46b74c8fe Mon Sep 17 00:00:00 2001 From: besiece Date: Sun, 8 Nov 2026 12:38:27 +0100 Subject: [PATCH 20/21] refactor: separate nametag item handling from silence actions and add rename aliases --- .../silenceNametag/NametagAction.java | 52 +++++++++ .../silenceNametag/NametagAnvilListener.java | 12 +-- .../silenceNametag/NametagEntityListener.java | 28 +++-- .../silenceNametag/SilenceNametag.java | 102 ++---------------- .../silenceNametag/SilenceNametagItem.java | 50 +++++++++ 5 files changed, 136 insertions(+), 108 deletions(-) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAction.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametagItem.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAction.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAction.java new file mode 100644 index 0000000..1e317fd --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAction.java @@ -0,0 +1,52 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.Nullable; + +import java.util.Locale; +import java.util.Set; + +public enum NametagAction { + SILENCE(0, Set.of("@verstummen", "@stumm", "@mute"), "Dieses Namensschild muted Mobs.", true), + UNSILENCE(1, Set.of("@entstummen", "@laut", "@unmute"), "Dieses Namensschild unmuted Mobs.", false); + + private final int persistentId; + private final Set renameTexts; + private final Component lore; + private final boolean silent; + + NametagAction(int persistentId, Set renameTexts, String lore, boolean silent) { + this.persistentId = persistentId; + this.renameTexts = Set.copyOf(renameTexts); + this.lore = Component.text(lore); + this.silent = silent; + } + + public int persistentId() { + return this.persistentId; + } + + public Component lore() { + return this.lore; + } + + public boolean silent() { + return this.silent; + } + + public static @Nullable NametagAction fromPersistentId(int id) { + for(NametagAction action : values()) { + if(action.persistentId == id) return action; + } + return null; + } + + public static @Nullable NametagAction fromRenameText(@Nullable String text) { + if(text == null) return null; + String normalizedText = text.strip().toLowerCase(Locale.ROOT); + for(NametagAction action : values()) { + if(action.renameTexts.contains(normalizedText)) return action; + } + return null; + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java index de9b6f9..244d883 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagAnvilListener.java @@ -9,19 +9,17 @@ import org.bukkit.inventory.view.AnvilView; public class NametagAnvilListener extends ApplianceListener { @EventHandler - public void onAnvilRename(PrepareAnvilEvent event){ + public void onAnvilRename(PrepareAnvilEvent event) { ItemStack resultItem = event.getResult(); - if(resultItem == null) return; + if(resultItem == null || resultItem.getType() != Material.NAME_TAG) return; AnvilView anvilView = event.getView(); ItemStack inputItem = anvilView.getItem(0); if(inputItem == null || inputItem.getType() != Material.NAME_TAG) return; - String renameText = anvilView.getRenameText(); + NametagAction action = NametagAction.fromRenameText(anvilView.getRenameText()); + if(action == null) return; - if(!SilenceNametag.muteString.equals(renameText) - && !SilenceNametag.unmuteString.equals(renameText)) return; - - event.setResult(this.getAppliance().createSilenceNametag(resultItem, renameText)); + event.setResult(SilenceNametagItem.create(resultItem, action)); } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java index e5624a7..13f5923 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -1,19 +1,19 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataType; public class NametagEntityListener extends ApplianceListener { - @EventHandler - public void onNametagUse(PlayerInteractEntityEvent event){ + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onNametagUse(PlayerInteractEntityEvent event) { ItemStack item; - - if (event.getHand() == EquipmentSlot.HAND) { + if(event.getHand() == EquipmentSlot.HAND) { item = event.getPlayer().getInventory().getItemInMainHand(); } else { item = event.getPlayer().getInventory().getItemInOffHand(); @@ -21,11 +21,19 @@ public class NametagEntityListener extends ApplianceListener { if(item.getType() != Material.NAME_TAG) return; - if(!item.getItemMeta().getPersistentDataContainer().has( - this.getAppliance().nametagActionKey, - PersistentDataType.INTEGER - )) return; + NametagAction action = SilenceNametagItem.readAction(item); + if(action == null) return; - getAppliance().applyNametagAction(item, event.getRightClicked()); + SilenceNametag.ActionResult result = this.getAppliance().applyNametagAction(event.getRightClicked(), action); + if(result == SilenceNametag.ActionResult.UNSUPPORTED) return; + + // Named tags retain vanilla naming and consumption, even if the mob is already in the desired state. + if(item.getItemMeta().customName() != null) return; + + // Unnamed special tags are handled entirely here, including no-op interactions. + event.setCancelled(true); + if(result == SilenceNametag.ActionResult.CHANGED && event.getPlayer().getGameMode() != GameMode.CREATIVE) { + item.setAmount(item.getAmount() - 1); + } } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index e6f5b8f..4ad51d1 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -1,108 +1,28 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; -import net.kyori.adventure.text.Component; -import org.bukkit.NamespacedKey; import org.bukkit.entity.Entity; +import org.bukkit.entity.Mob; import org.bukkit.event.Listener; -import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; import java.util.Objects; public class SilenceNametag extends Appliance { - public static final String pluginName = "silence-nametag"; - public static final String muteString = "@verstummen"; - public static final String unmuteString = "@entstummen"; - - public enum NametagActions { - SILENCE, - UNSILENCE + public enum ActionResult { + CHANGED, + UNCHANGED, + UNSUPPORTED } - NamespacedKey nametagActionKey = - new NamespacedKey(pluginName, "nametag-action"); + public ActionResult applyNametagAction(Entity entity, NametagAction action) { + Objects.requireNonNull(action, "Action must not be null."); + if(!(entity instanceof Mob)) return ActionResult.UNSUPPORTED; + if(entity.isSilent() == action.silent()) return ActionResult.UNCHANGED; - private final Component silenceNametagLore = Component.text("Dieses Namensschild verstummt Mobs."); - private final Component unsilenceNametagLore = Component.text("Dieses Namensschild entstummt Mobs."); - - ItemStack setNametagAction(ItemStack item, NametagActions action) { - Objects.requireNonNull(item, "Item must not be null."); - setPersistentDataOfNametag(item, action); - removeLoreOfNametag(item); - setLoreOfNametag(item, action); - restoreDefaultNameOfNametag(item); - return item; - } - - void setPersistentDataOfNametag(ItemStack item, NametagActions action){ - item.editPersistentDataContainer(pdc -> pdc.set( - nametagActionKey, - PersistentDataType.INTEGER, - action.ordinal() - )); - } - - void removeLoreOfNametag(ItemStack item){ - item.editMeta(meta -> { - List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); - lore.removeIf(line -> - line.toString().contains(silenceNametagLore.toString()) - || line.toString().contains(unsilenceNametagLore.toString())); - meta.lore(lore); - }); - } - - void setLoreOfNametag(ItemStack item, NametagActions action){ - item.editMeta(meta -> { - List lore = meta.hasLore() ? new ArrayList<>(meta.lore()) : new ArrayList<>(); - if(action == NametagActions.SILENCE) { - lore.add(silenceNametagLore); - } else if (action == NametagActions.UNSILENCE){ - lore.add(unsilenceNametagLore); - } - meta.lore(lore); - }); - } - - void restoreDefaultNameOfNametag(ItemStack item){ - item.editMeta(meta -> meta.customName(null)); - } - - @Nullable NametagActions getNametagAction(ItemStack item) { - Objects.requireNonNull(item, "Item must not be null."); - return item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER) == null - ? null - : NametagActions.values()[item.getPersistentDataContainer().get(nametagActionKey, PersistentDataType.INTEGER)]; - } - - public ItemStack createSilenceNametag(ItemStack ResultItem, String renameText){ - if(renameText.equals(muteString)) { - return this.setNametagAction(ResultItem, NametagActions.SILENCE); - } else if(renameText.equals(unmuteString)) { - return this.setNametagAction(ResultItem, NametagActions.UNSILENCE); - } - return ResultItem; - } - - public void applyNametagAction(ItemStack item, Entity mob) { - if (getNametagAction(item) == SilenceNametag.NametagActions.SILENCE) { - if(mob.isSilent()) return; - mob.setSilent(true); - } else if (getNametagAction(item) == SilenceNametag.NametagActions.UNSILENCE) { - if (!mob.isSilent()) return; - mob.setSilent(false); - } - - // Consume one unnamed nametag manually. - // Custom-named tags use vanilla nametag behavior, including item consumption. - if (item.getItemMeta().customName() == null) { - item.setAmount(item.getAmount() - 1); - } + entity.setSilent(action.silent()); + return ActionResult.CHANGED; } @Override diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametagItem.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametagItem.java new file mode 100644 index 0000000..512328c --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametagItem.java @@ -0,0 +1,50 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +final class SilenceNametagItem { + // Keep the key and IDs compatible with existing nametags. + private static final NamespacedKey ACTION_KEY = new NamespacedKey("silence-nametag", "nametag-action"); + + private SilenceNametagItem() { + } + + static @Nullable NametagAction readAction(ItemStack item) { + if(item.getType() != Material.NAME_TAG) return null; + var data = item.getPersistentDataContainer(); + if(!data.has(ACTION_KEY, PersistentDataType.INTEGER)) return null; + + Integer id = data.get(ACTION_KEY, PersistentDataType.INTEGER); + return id == null ? null : NametagAction.fromPersistentId(id); + } + + static ItemStack create(ItemStack source, NametagAction action) { + Objects.requireNonNull(action, "Action must not be null."); + if(source.getType() != Material.NAME_TAG) { + throw new IllegalArgumentException("Item must be a nametag."); + } + + ItemStack result = source.clone(); + result.editMeta(meta -> { + meta.getPersistentDataContainer().set(ACTION_KEY, PersistentDataType.INTEGER, action.persistentId()); + List existingLore = meta.lore(); + List lore = existingLore == null ? new ArrayList<>() : new ArrayList<>(existingLore); + for(NametagAction knownAction : NametagAction.values()) { + lore.removeIf(knownAction.lore()::equals); + } + lore.add(action.lore()); + meta.lore(lore); + meta.customName(null); + }); + return result; + } +} From 6505bda43e32df11c2dc1639e614683616581f17 Mon Sep 17 00:00:00 2001 From: besiece Date: Sun, 8 Nov 2026 13:04:30 +0100 Subject: [PATCH 21/21] feat: implement feedback system for silence nametag actions with action bar updates --- .../ActionBarNametagFeedback.java | 46 +++++++++++ .../silenceNametag/NametagEntityListener.java | 7 ++ .../silenceNametag/NametagFeedback.java | 7 ++ .../NametagFeedbackService.java | 82 +++++++++++++++++++ .../silenceNametag/NametagFeedbackUpdate.java | 18 ++++ .../silenceNametag/SilenceNametag.java | 12 +++ 6 files changed, 172 insertions(+) create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/ActionBarNametagFeedback.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedback.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackService.java create mode 100644 craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackUpdate.java diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/ActionBarNametagFeedback.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/ActionBarNametagFeedback.java new file mode 100644 index 0000000..e196287 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/ActionBarNametagFeedback.java @@ -0,0 +1,46 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.JoinConfiguration; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +final class ActionBarNametagFeedback implements NametagFeedback { + @Override + public void send(Player player, NametagFeedbackUpdate update) { + player.sendActionBar(this.render(update)); + } + + Component render(NametagFeedbackUpdate update) { + if(update.summary()) { + var counts = update.counts(); + List parts = new ArrayList<>(); + addCount(parts, counts.silenced(), "verstummt", NamedTextColor.GREEN); + addCount(parts, counts.unsilenced(), "entstummt", NamedTextColor.GREEN); + addCount(parts, counts.alreadySilent(), "bereits stumm", NamedTextColor.YELLOW); + addCount(parts, counts.alreadyAudible(), "bereits hörbar", NamedTextColor.YELLOW); + addCount(parts, counts.unsupported(), "nicht unterstützt", NamedTextColor.RED); + return Component.join(JoinConfiguration.separator(Component.text(" · ", NamedTextColor.GRAY)), parts); + } + + boolean silence = update.action() == NametagAction.SILENCE; + String suffix = switch(update.result()) { + case CHANGED -> silence ? " ist jetzt stumm." : " ist jetzt wieder hörbar."; + case UNCHANGED -> silence ? " ist bereits stumm." : " ist bereits hörbar."; + case UNSUPPORTED -> " unterstützt dieses Namensschild nicht."; + }; + NamedTextColor color = switch(update.result()) { + case CHANGED -> NamedTextColor.GREEN; + case UNCHANGED -> NamedTextColor.YELLOW; + case UNSUPPORTED -> NamedTextColor.RED; + }; + return Component.empty().color(color).append(update.targetName()).append(Component.text(suffix)); + } + + private static void addCount(List parts, int count, String label, NamedTextColor color) { + if(count > 0) parts.add(Component.text(count + " " + label, color)); + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java index 13f5923..e82f897 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagEntityListener.java @@ -6,6 +6,7 @@ import org.bukkit.Material; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -25,6 +26,7 @@ public class NametagEntityListener extends ApplianceListener { if(action == null) return; SilenceNametag.ActionResult result = this.getAppliance().applyNametagAction(event.getRightClicked(), action); + this.getAppliance().feedback().send(event.getPlayer(), event.getRightClicked(), action, result); if(result == SilenceNametag.ActionResult.UNSUPPORTED) return; // Named tags retain vanilla naming and consumption, even if the mob is already in the desired state. @@ -36,4 +38,9 @@ public class NametagEntityListener extends ApplianceListener { item.setAmount(item.getAmount() - 1); } } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + this.getAppliance().feedback().forget(event.getPlayer().getUniqueId()); + } } diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedback.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedback.java new file mode 100644 index 0000000..a7b9e92 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedback.java @@ -0,0 +1,7 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import org.bukkit.entity.Player; + +interface NametagFeedback { + void send(Player player, NametagFeedbackUpdate update); +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackService.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackService.java new file mode 100644 index 0000000..289f771 --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackService.java @@ -0,0 +1,82 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.LongSupplier; + +final class NametagFeedbackService { + private static final long SERIES_TIMEOUT = TimeUnit.SECONDS.toNanos(1); + private final LongSupplier clock; + private final List outputs; + private final Map seriesByPlayer = new HashMap<>(); + + NametagFeedbackService(LongSupplier clock, List outputs) { + this.clock = clock; + this.outputs = List.copyOf(outputs); + } + + void send(Player player, Entity target, NametagAction action, SilenceNametag.ActionResult result) { + Component name = target.customName(); + if(name == null) name = Component.translatable(target.getType().translationKey()); + NametagFeedbackUpdate update = this.recordInteraction(player.getUniqueId(), target.getUniqueId(), name, action, result); + this.outputs.forEach(output -> output.send(player, update)); + } + + // Called synchronously by the entity listener. Series retain no Bukkit objects or display names. + NametagFeedbackUpdate recordInteraction(UUID playerId, UUID targetId, Component name, + NametagAction action, SilenceNametag.ActionResult result) { + long now = this.clock.getAsLong(); + this.seriesByPlayer.values().removeIf(series -> now - series.lastInteraction >= SERIES_TIMEOUT); + boolean newSeries = !this.seriesByPlayer.containsKey(playerId); + Series series = this.seriesByPlayer.computeIfAbsent(playerId, ignored -> new Series()); + series.lastInteraction = now; + if(result == SilenceNametag.ActionResult.UNSUPPORTED) { + series.unsupported.add(targetId); + } else { + series.results.merge(new TargetAction(targetId, action), result, (previous, current) -> + previous == SilenceNametag.ActionResult.CHANGED ? previous : current); + } + return new NametagFeedbackUpdate(targetId, name, action, result, newSeries, !newSeries, series.counts()); + } + + void forget(UUID playerId) { + this.seriesByPlayer.remove(playerId); + } + + void clear() { + this.seriesByPlayer.clear(); + } + + private record TargetAction(UUID targetId, NametagAction action) { + } + + private static final class Series { + private long lastInteraction; + private final Map results = new HashMap<>(); + private final Set unsupported = new HashSet<>(); + + private NametagFeedbackUpdate.Counts counts() { + int silenced = 0, unsilenced = 0, alreadySilent = 0, alreadyAudible = 0; + for(var entry : this.results.entrySet()) { + boolean changed = entry.getValue() == SilenceNametag.ActionResult.CHANGED; + if(entry.getKey().action() == NametagAction.SILENCE) { + if(changed) silenced++; + else alreadySilent++; + } else { + if(changed) unsilenced++; + else alreadyAudible++; + } + } + return new NametagFeedbackUpdate.Counts(silenced, unsilenced, alreadySilent, alreadyAudible, this.unsupported.size()); + } + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackUpdate.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackUpdate.java new file mode 100644 index 0000000..5e9a9bc --- /dev/null +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/NametagFeedbackUpdate.java @@ -0,0 +1,18 @@ +package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.silenceNametag; + +import net.kyori.adventure.text.Component; + +import java.util.UUID; + +record NametagFeedbackUpdate( + UUID targetId, + Component targetName, + NametagAction action, + SilenceNametag.ActionResult result, + boolean newSeries, + boolean summary, + Counts counts +) { + record Counts(int silenced, int unsilenced, int alreadySilent, int alreadyAudible, int unsupported) { + } +} diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java index 4ad51d1..c4691cb 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/silenceNametag/SilenceNametag.java @@ -10,6 +10,18 @@ import java.util.List; import java.util.Objects; public class SilenceNametag extends Appliance { + private final NametagFeedbackService feedback = new NametagFeedbackService( + System::nanoTime, List.of(new ActionBarNametagFeedback())); + + NametagFeedbackService feedback() { + return this.feedback; + } + + @Override + public void onDisable() { + this.feedback.clear(); + } + public enum ActionResult { CHANGED, UNCHANGED,