diff --git a/src/main/java/com/jaoafa/mymaid4/event/Event_AntiToolbar.java b/src/main/java/com/jaoafa/mymaid4/event/Event_AntiToolbar.java
index f3d2b8303..57576f922 100644
--- a/src/main/java/com/jaoafa/mymaid4/event/Event_AntiToolbar.java
+++ b/src/main/java/com/jaoafa/mymaid4/event/Event_AntiToolbar.java
@@ -26,6 +26,8 @@
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
+import org.bukkit.inventory.meta.SkullMeta;
+import org.bukkit.profile.PlayerProfile;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -36,8 +38,26 @@
import java.util.*;
import java.util.regex.Pattern;
+/**
+ * ツールバーの利用を制限します。
+ *
+ * ・クリエイティブモードでクリエイティブインベントリやツールバーからアイテムをインベントリに追加する際に {@link InventoryCreativeEvent} が発生することを利用して制限します。
+ * ・この機能は Admin, Moderator, Regular には適用されません。
+ * ・クリエイティブインベントリに存在するアイテムの一覧はデータフォルダにある creative-items.tsv で定義します。これが未定義の場合はこの機能は動作しません。
+ * → このファイルはフラグ isCollectCreativeItems を True にし、クリエイティブインベントリにあるアイテムをすべて入手(ドロップ)することで出力できます。
+ *
+ * ・クリエイティブインベントリのアイテムと {@link InventoryCreativeEvent#getCursor()} が合致する場合、除外します。
+ * ・InventoryCreativeEvent 発生時、{@link InventoryCreativeEvent#getCurrentItem()} が NULL ではなく AIR ではない場合はアイテムを持ち上げたものとして Map に記録します。
+ * → さらに、次のイベント発生時に記録したアイテムと {@link InventoryCreativeEvent#getCursor()} が合致する場合はツールバーからの取得とみなしません。
+ * → これにより、一度持ち上げて別のスロットに移動させた場合にツールバーとして判定されなくなります。(#429, #913)
+ * ・jaoiumに該当するアイテムは処罰対象としてその後処理されるため、この機能では当該アイテムを削除しません。
+ * ・ImageOnMapのマップをマウス中クリックでコピーするとツールバーとして誤認されてしまう問題を回避するため、{@link Material#FILLED_MAP} のアイテムはすべて除外します。(#533)
+ *
+ * 以上のフローを経て、除外されなかったアイテムはすべてツールバーとして判定し、当該アイテムを削除します。
+ * また当該アイテムの情報をデータフォルダの toolbar-items.tsv に記録します。
+ */
public class Event_AntiToolbar extends MyMaidLibrary implements Listener, EventPremise {
- final Pattern damagePattern = Pattern.compile("\\{Damage:[0-9]+}");
+ final Pattern damagePattern = Pattern.compile("\\{Damage:\\d+}");
final Map pickupItems = new HashMap<>();
final static boolean isCollectCreativeItems = false;
@@ -96,16 +116,26 @@ public void onInventoryCreative(InventoryCreativeEvent event) {
if (MyMaidData.getCreativeInventoryWithNBTs().isEmpty()) {
return;
}
+ ItemStack is = event.getCursor();
+
+ boolean isPickupItem = pickupItems.containsKey(player.getUniqueId()) &&
+ pickupItems.get(player.getUniqueId()).equals(is) &&
+ (pickupItems.get(player.getUniqueId()).getItemMeta().equals(is.getItemMeta()) ||
+ isAllowPlayerHead(pickupItems.get(player.getUniqueId()), is));
if (event.getCurrentItem() != null && event.getCurrentItem().getType() != Material.AIR) {
pickupItems.put(player.getUniqueId(), event.getCurrentItem());
}
- if (event.getCursor().getType() == Material.AIR) {
+
+ if (isPickupItem) {
+ return;
+ }
+
+ if (is.getType() == Material.AIR) {
return;
}
boolean isDeny = isDenyItemStack(event.getCursor());
- ItemStack is = event.getCursor();
if (!isDeny) {
return;
@@ -115,12 +145,6 @@ public void onInventoryCreative(InventoryCreativeEvent event) {
return;
}
- if (pickupItems.containsKey(player.getUniqueId()) &&
- pickupItems.get(player.getUniqueId()).equals(is) &&
- pickupItems.get(player.getUniqueId()).getItemMeta().equals(is.getItemMeta())) {
- return;
- }
-
if (is.getType() == Material.SPLASH_POTION &&
is.getType() == Material.LINGERING_POTION &&
isjaoium(((PotionMeta) is.getItemMeta()).getCustomEffects())) {
@@ -182,7 +206,27 @@ boolean isExistsInventory(Inventory inv, @NotNull ItemStack is) {
.stream(inv.getContents())
.filter(Objects::nonNull)
.anyMatch(item ->
- item.getType() == is.getType() && item.getItemMeta() != null && item.getItemMeta().equals(is.getItemMeta())
+ item.getType() == is.getType() &&
+ item.getItemMeta() != null &&
+ (isAllowPlayerHead(item, is) || item.getItemMeta().equals(is.getItemMeta()))
);
}
+
+ @SuppressWarnings("deprecation")
+ boolean isAllowPlayerHead(ItemStack is1, ItemStack is2) {
+ if (is1.getType() != Material.PLAYER_HEAD || is2.getType() != Material.PLAYER_HEAD) {
+ return false;
+ }
+
+ PlayerProfile profile1 = ((SkullMeta) is1.getItemMeta()).getOwnerProfile();
+ PlayerProfile profile2 = ((SkullMeta) is2.getItemMeta()).getOwnerProfile();
+
+ if (profile1 == null || profile2 == null) {
+ return false;
+ }
+
+ return (profile1.getName() != null && profile2.getName() != null && profile1.getName().equals(profile2.getName())) ||
+ (profile1.getUniqueId() != null && profile2.getUniqueId() != null && profile1.getUniqueId().equals(profile2.getUniqueId())) ||
+ profile1.getTextures().equals(profile2.getTextures());
+ }
}