diff --git a/pom.xml b/pom.xml
index d4aeddb..c2ff00a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,6 +16,7 @@
UTF-8
2.0.0
2.0.0
+ 3.7.0
0.2.1
0.2.0
2.0.0
@@ -248,6 +249,19 @@
+
+
+ com.dre.brewery
+ BreweryX
+ ${breweryx.version}
+ provided
+
+
+ *
+ *
+
+
+
org.objenesis
@@ -273,6 +287,10 @@
placeholderapi
https://repo.extendedclip.com/releases/
+
+ breweryx
+ https://repo.jsinco.dev/releases/
+
diff --git a/src/main/java/net/tfminecraft/activitytf/ActivityPlugin.java b/src/main/java/net/tfminecraft/activitytf/ActivityPlugin.java
index 2f2f486..6c73b41 100644
--- a/src/main/java/net/tfminecraft/activitytf/ActivityPlugin.java
+++ b/src/main/java/net/tfminecraft/activitytf/ActivityPlugin.java
@@ -8,6 +8,7 @@
import net.tfminecraft.activitytf.listeners.AdvancedCraftListener;
import net.tfminecraft.activitytf.listeners.ArchaeologyListener;
import net.tfminecraft.activitytf.listeners.BattleListener;
+import net.tfminecraft.activitytf.listeners.BreweryListener;
import net.tfminecraft.activitytf.listeners.CasinoWinListener;
import net.tfminecraft.activitytf.listeners.CharacterChatListener;
import net.tfminecraft.activitytf.listeners.CraftListener;
@@ -162,6 +163,12 @@ private void registerHooks() {
getLogger().info("Hooked into Cooking.");
}
+ if (Bukkit.getPluginManager().isPluginEnabled("BreweryX")) {
+ getServer().getPluginManager().registerEvents(
+ new BreweryListener(ActivityManager.getInstance()), this);
+ getLogger().info("Hooked into BreweryX.");
+ }
+
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
placeholderHook = new PlaceholderHook(ActivityManager.getInstance());
placeholderHook.register();
diff --git a/src/main/java/net/tfminecraft/activitytf/listeners/BreweryListener.java b/src/main/java/net/tfminecraft/activitytf/listeners/BreweryListener.java
new file mode 100644
index 0000000..c5df615
--- /dev/null
+++ b/src/main/java/net/tfminecraft/activitytf/listeners/BreweryListener.java
@@ -0,0 +1,25 @@
+package net.tfminecraft.activitytf.listeners;
+
+import com.dre.brewery.api.events.IngedientAddEvent;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import net.tfminecraft.activitytf.managers.ActivityManager;
+
+public class BreweryListener implements Listener {
+
+ private final ActivityManager manager;
+
+ public BreweryListener(ActivityManager manager) {
+ this.manager = manager;
+ }
+
+ // BreweryX only fires this for an item a cauldron recipe accepts, once per item added.
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onIngredientAdd(IngedientAddEvent event) {
+ if (event.getPlayer() == null) {
+ return;
+ }
+ manager.recordAction(event.getPlayer().getUniqueId(), "brew_ingredient", 1);
+ }
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index c21d417..0e74481 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -311,6 +311,20 @@ activities:
every: 5
points: 1
daily-cap: 2
+ # BreweryX activities (brew_*). The shipped config.yml is only written on a fresh
+ # install, so an existing server must copy these entries into its own config.yml
+ # and run /activity reload; until then they are unknown ids and earn nothing.
+ # BreweryX: ingredients put into a brewing cauldron
+ brew_ingredient:
+ display: "#e6ca40&lGather Brewing Ingredients"
+ description:
+ - "&7Add &a%every% &7ingredients to a brewing cauldron."
+ - "&7Earn &a%points% &7activity points per completion."
+ - "&7"
+ material: CAULDRON
+ every: 10
+ points: 1
+ daily-cap: 1
# RPCharacters: profession upgrades purchased
profession_upgrade:
display: "#e6ca40&lProfession Upgrade"
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 1681c90..ada98cc 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -5,7 +5,7 @@ author: Justin
api-version: '1.21.10'
softdepend: [VotingPlugin, MusicalInstruments, geiger_counter, MMOCore, MMOItems, MythicLib, PlaceholderAPI,
VFBuilders, RPCharacters, InteractibleFurniture, SimpleFactions, AdvancedCrafting, TLibs, Archaeo,
- MarketBlock, Games, Cooking, ItemsAdder]
+ MarketBlock, Games, Cooking, ItemsAdder, BreweryX]
commands:
activity:
description: Open the weekly activity bar, or run admin subcommands
diff --git a/src/test/java/net/tfminecraft/activitytf/listeners/BreweryListenerHandlersTest.java b/src/test/java/net/tfminecraft/activitytf/listeners/BreweryListenerHandlersTest.java
new file mode 100644
index 0000000..920ff20
--- /dev/null
+++ b/src/test/java/net/tfminecraft/activitytf/listeners/BreweryListenerHandlersTest.java
@@ -0,0 +1,29 @@
+package net.tfminecraft.activitytf.listeners;
+
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class BreweryListenerHandlersTest {
+
+ // BreweryListenerTest calls the handlers directly, which skips Bukkit's ignoreCancelled filter.
+ @Test
+ void everyHandlerSkipsCancelledEventsAtMonitor() {
+ int handlers = 0;
+ for (Method method : BreweryListener.class.getDeclaredMethods()) {
+ EventHandler handler = method.getAnnotation(EventHandler.class);
+ if (handler == null) {
+ continue;
+ }
+ handlers++;
+ assertTrue(handler.ignoreCancelled(), method.getName() + " must ignore cancelled events");
+ assertEquals(EventPriority.MONITOR, handler.priority(), method.getName());
+ }
+ assertTrue(handlers > 0);
+ }
+}
diff --git a/src/test/java/net/tfminecraft/activitytf/listeners/BreweryListenerTest.java b/src/test/java/net/tfminecraft/activitytf/listeners/BreweryListenerTest.java
new file mode 100644
index 0000000..0bc62e6
--- /dev/null
+++ b/src/test/java/net/tfminecraft/activitytf/listeners/BreweryListenerTest.java
@@ -0,0 +1,90 @@
+package net.tfminecraft.activitytf.listeners;
+
+import com.dre.brewery.api.events.IngedientAddEvent;
+import net.tfminecraft.activitytf.managers.ActivityManager;
+import net.tfminecraft.activitytf.managers.TestManagers;
+import net.tfminecraft.activitytf.models.ActivityDef;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerEvent;
+import org.junit.jupiter.api.Test;
+import org.objenesis.ObjenesisStd;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class BreweryListenerTest {
+
+ private static Player stubPlayer(UUID uuid) {
+ InvocationHandler handler = (proxy, method, args) -> switch (method.getName()) {
+ case "getUniqueId" -> uuid;
+ case "toString" -> "stub-player";
+ case "hashCode" -> uuid.hashCode();
+ case "equals" -> proxy == args[0];
+ default -> throw new UnsupportedOperationException(
+ "unexpected call to Player#" + method.getName() + " - this test double only answers getUniqueId()");
+ };
+ return (Player) Proxy.newProxyInstance(
+ BreweryListenerTest.class.getClassLoader(), new Class>[]{Player.class}, handler);
+ }
+
+ static void set(Class> owner, Object target, String name, Object value) {
+ try {
+ Field field = owner.getDeclaredField(name);
+ field.setAccessible(true);
+ field.set(target, value);
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static IngedientAddEvent ingredient(Player player) {
+ IngedientAddEvent event = new ObjenesisStd().newInstance(IngedientAddEvent.class);
+ set(PlayerEvent.class, event, "player", player);
+ return event;
+ }
+
+ /** A manager with every given activity revealed for the returned player. */
+ static UUID revealed(ActivityManager manager) {
+ TestManagers.bukkit();
+ TestManagers.storeLoaded(manager);
+ UUID uuid = UUID.randomUUID();
+ for (int slot = 0; slot < manager.tasks(uuid).tasks().size(); slot++) {
+ manager.reveal(uuid, slot);
+ }
+ return uuid;
+ }
+
+ static ActivityManager managerWith(String... ids) {
+ ActivityDef[] defs = new ActivityDef[ids.length];
+ for (int i = 0; i < ids.length; i++) {
+ defs[i] = new ActivityDef(ids[i], ids[i], Material.POTION, null, 1, 1, 0);
+ }
+ ActivityManager manager = TestManagers.manager(defs);
+ TestManagers.guarantee(manager, ids);
+ return manager;
+ }
+
+ @Test
+ void anIngredientWithoutAPlayerIsIgnored() {
+ BreweryListener listener = new BreweryListener(null);
+ assertDoesNotThrow(() -> listener.onIngredientAdd(ingredient(null)));
+ }
+
+ @Test
+ void eachIngredientAddedCreditsOne() {
+ ActivityManager manager = managerWith("brew_ingredient");
+ UUID uuid = revealed(manager);
+ BreweryListener listener = new BreweryListener(manager);
+
+ listener.onIngredientAdd(ingredient(stubPlayer(uuid)));
+ listener.onIngredientAdd(ingredient(stubPlayer(uuid)));
+
+ assertEquals(2, manager.tasks(uuid).count("brew_ingredient"));
+ }
+}