From 7de1f1e58a0bcf83fd594a4d1c46f450ae1cd7d3 Mon Sep 17 00:00:00 2001
From: Manchick0 <manchicking@gmail.com>
Date: Fri, 17 Jan 2025 15:35:31 +0100
Subject: [PATCH 1/2] Add Island Pickobulus Block

Introduced an option to block the Pickobulus ability on private islands.
---
 .../config/categories/MiningCategory.java     |  8 ++++
 .../config/configs/MiningConfig.java          |  4 ++
 .../skyblock/IslandPickobulusBlock.java       | 39 +++++++++++++++++++
 .../de/hysky/skyblocker/utils/ItemUtils.java  |  8 +++-
 .../assets/skyblocker/lang/en_us.json         |  3 ++
 5 files changed, 61 insertions(+), 1 deletion(-)
 create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java

diff --git a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
index 890d86aa10..607d95572b 100644
--- a/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
+++ b/src/main/java/de/hysky/skyblocker/config/categories/MiningCategory.java
@@ -26,6 +26,14 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig
                 .name(Text.translatable("skyblocker.config.mining"))
 
                 //Uncategorized Options
+				.option(Option.<Boolean>createBuilder()
+						.name(Text.translatable("skyblocker.config.mining.islandPickobulusBlock"))
+						.description(OptionDescription.of(Text.translatable("skyblocker.config.mining.islandPickobulusBlock.@Tooltip")))
+						.binding(defaults.mining.islandPickobulusBlock,
+								() -> config.mining.islandPickobulusBlock,
+								newValue -> config.mining.islandPickobulusBlock = newValue)
+						.controller(ConfigUtils::createBooleanController)
+						.build())
                 .option(Option.<Boolean>createBuilder()
                         .name(Text.translatable("skyblocker.config.mining.enableDrillFuel"))
                         .binding(defaults.mining.enableDrillFuel,
diff --git a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
index f73f38a9b9..29e44a5683 100644
--- a/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
+++ b/src/main/java/de/hysky/skyblocker/config/configs/MiningConfig.java
@@ -8,6 +8,10 @@
 import java.util.List;
 
 public class MiningConfig {
+
+	@SerialEntry
+	public boolean islandPickobulusBlock = false;
+
     @SerialEntry
     public boolean enableDrillFuel = true;
 
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java b/src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java
new file mode 100644
index 0000000000..f789ab91d3
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java
@@ -0,0 +1,39 @@
+package de.hysky.skyblocker.skyblock;
+
+import de.hysky.skyblocker.annotations.Init;
+import de.hysky.skyblocker.config.SkyblockerConfigManager;
+import de.hysky.skyblocker.utils.ItemUtils;
+import de.hysky.skyblocker.utils.Location;
+import de.hysky.skyblocker.utils.Utils;
+import net.fabricmc.fabric.api.event.player.UseBlockCallback;
+import net.fabricmc.fabric.api.event.player.UseItemCallback;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.util.ActionResult;
+import net.minecraft.util.Hand;
+
+public final class IslandPickobulusBlock {
+
+	@Init
+	public static void init() {
+		UseItemCallback.EVENT.register((player, world, hand) ->
+				IslandPickobulusBlock.checkForPickobulus(player, hand));
+		UseBlockCallback.EVENT.register((player, world, hand, blockHitResult) ->
+				IslandPickobulusBlock.checkForPickobulus(player, hand));
+	}
+
+	private static ActionResult checkForPickobulus(PlayerEntity player, Hand hand) {
+		var config = SkyblockerConfigManager.get();
+		if (config.mining.islandPickobulusBlock
+				&& Utils.getLocation() == Location.PRIVATE_ISLAND) {
+			var stack = player.getStackInHand(hand);
+			var ability = ItemUtils.getAbility(stack);
+			if (ability.isPresent()) {
+				var name = ability.get();
+				if (name.equalsIgnoreCase("pickobulus")) {
+					return ActionResult.FAIL; // Cancels and doesn't send a package
+				}
+			}
+		}
+		return ActionResult.PASS;
+	}
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
index b886f40fc3..aaab4e4a1e 100644
--- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
@@ -53,6 +53,7 @@ public final class ItemUtils {
     public static final String ID = "id";
     public static final String UUID = "uuid";
     public static final Pattern NOT_DURABILITY = Pattern.compile("[^0-9 /]");
+	public static final Pattern ABILITY = Pattern.compile("ability:\\s+(?<ability>[\\w\\s]+?)\\s+right\\s+click", Pattern.CASE_INSENSITIVE);
     public static final Predicate<String> FUEL_PREDICATE = line -> line.contains("Fuel: ");
     private static final Codec<RegistryEntry<Item>> EMPTY_ALLOWING_ITEM_CODEC = Registries.ITEM.getEntryCodec();
     public static final Codec<ItemStack> EMPTY_ALLOWING_ITEMSTACK_CODEC = Codec.lazyInitialized(() -> RecordCodecBuilder.create(instance -> instance.group(
@@ -424,6 +425,11 @@ public static Matcher getLoreLineIfContainsMatch(ItemStack stack, Pattern patter
         return stack.getOrDefault(DataComponentTypes.LORE, LoreComponent.DEFAULT).styledLines();
     }
 
+	public static Optional<String> getAbility(ItemStack stack) {
+		var match = ItemUtils.getLoreLineIfMatch(stack, ABILITY);
+		return Optional.ofNullable(match).map(m -> m.group("ability"));
+	}
+
     public static @NotNull PropertyMap propertyMapWithTexture(String textureValue) {
         return Codecs.GAME_PROFILE_PROPERTY_MAP.parse(JsonOps.INSTANCE, JsonParser.parseString("[{\"name\":\"textures\",\"value\":\"" + textureValue + "\"}]")).getOrThrow();
     }
@@ -475,4 +481,4 @@ public static Matcher getLoreLineIfContainsMatch(ItemStack stack, Pattern patter
         }
         return stringBuilder.toString();
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index 3e6b5d30b6..b2dcbc8982 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -542,6 +542,9 @@
 
   "skyblocker.config.mining": "Mining",
 
+  "skyblocker.config.mining.islandPickobulusBlock": "Island Pickobulus Block",
+  "skyblocker.config.mining.islandPickobulusBlock.@Tooltip": "Blocks the pickobulus ability when on your private island.",
+
   "skyblocker.config.mining.commissionWaypoints": "Commission Waypoints",
   "skyblocker.config.mining.commissionWaypoints.mode": "Enable Commission Waypoints",
   "skyblocker.config.mining.commissionWaypoints.mode.@Tooltip[0]": "Off: Do not show Commission waypoint.",

From 1ede26205932ee7fea81956e25aced98d125cedf Mon Sep 17 00:00:00 2001
From: Manchick0 <manchicking@gmail.com>
Date: Fri, 17 Jan 2025 17:11:06 +0100
Subject: [PATCH 2/2] Use null instead of Optional

---
 .../de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java  | 5 ++---
 src/main/java/de/hysky/skyblocker/utils/ItemUtils.java       | 4 ++--
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java b/src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java
index f789ab91d3..149edafdc0 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/IslandPickobulusBlock.java
@@ -27,9 +27,8 @@ private static ActionResult checkForPickobulus(PlayerEntity player, Hand hand) {
 				&& Utils.getLocation() == Location.PRIVATE_ISLAND) {
 			var stack = player.getStackInHand(hand);
 			var ability = ItemUtils.getAbility(stack);
-			if (ability.isPresent()) {
-				var name = ability.get();
-				if (name.equalsIgnoreCase("pickobulus")) {
+			if (ability != null) {
+				if (ability.equalsIgnoreCase("pickobulus")) {
 					return ActionResult.FAIL; // Cancels and doesn't send a package
 				}
 			}
diff --git a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
index aaab4e4a1e..a65b31763a 100644
--- a/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
@@ -425,9 +425,9 @@ public static Matcher getLoreLineIfContainsMatch(ItemStack stack, Pattern patter
         return stack.getOrDefault(DataComponentTypes.LORE, LoreComponent.DEFAULT).styledLines();
     }
 
-	public static Optional<String> getAbility(ItemStack stack) {
+	public static String getAbility(ItemStack stack) {
 		var match = ItemUtils.getLoreLineIfMatch(stack, ABILITY);
-		return Optional.ofNullable(match).map(m -> m.group("ability"));
+		return match == null ? null : match.group("ability");
 	}
 
     public static @NotNull PropertyMap propertyMapWithTexture(String textureValue) {