diff options
Diffstat (limited to 'src/main/java')
31 files changed, 170 insertions, 129 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt index d164e0e77..63d3e14cf 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt @@ -8,77 +8,25 @@ import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.inAnyIsland import at.hannibal2.skyhanni.utils.StringUtils import at.hannibal2.skyhanni.utils.chat.Text -import java.lang.invoke.LambdaMetafactory -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType -import java.lang.reflect.Method -import java.lang.reflect.ParameterizedType -import java.util.function.Consumer -class EventHandler<T : SkyHanniEvent> private constructor(val name: String, private val isGeneric: Boolean) { - - private val listeners: MutableList<Listener> = mutableListOf() - - private var isFrozen = false - private var canReceiveCancelled = false +class EventHandler<T : SkyHanniEvent> private constructor( + val name: String, + private val listeners: List<EventListeners.Listener>, + private val canReceiveCancelled: Boolean, +) { var invokeCount: Long = 0L private set - constructor(event: Class<T>) : this( + constructor(event: Class<T>, listeners: List<EventListeners.Listener>) : this( (event.name.split(".").lastOrNull() ?: event.name).replace("$", "."), - GenericSkyHanniEvent::class.java.isAssignableFrom(event) + listeners.sortedBy { it.options.priority }.toList(), + listeners.any { it.options.receiveCancelled } ) - fun addListener(method: Method, instance: Any, options: HandleEvent) { - if (isFrozen) throw IllegalStateException("Cannot add listener to frozen event handler") - val generic: Class<*>? = if (isGeneric) { - method.genericParameterTypes - .firstNotNullOfOrNull { it as? ParameterizedType } - ?.let { it.actualTypeArguments.firstOrNull() as? Class<*> } - ?: throw IllegalArgumentException("Generic event handler must have a generic type") - } else { - null - } - val name = "${method.declaringClass.name}.${method.name}${ - method.parameterTypes.joinTo( - StringBuilder(), - prefix = "(", - postfix = ")", - separator = ", ", - transform = Class<*>::getTypeName - ) - }" - listeners.add(Listener(name, createEventConsumer(name, instance, method), options, generic)) - } - - @Suppress("UNCHECKED_CAST") - private fun createEventConsumer(name: String, instance: Any, method: Method): Consumer<Any> { - try { - val handle = MethodHandles.lookup().unreflect(method) - return LambdaMetafactory.metafactory( - MethodHandles.lookup(), - "accept", - MethodType.methodType(Consumer::class.java, instance::class.java), - MethodType.methodType(Nothing::class.javaPrimitiveType, Object::class.java), - handle, - MethodType.methodType(Nothing::class.javaPrimitiveType, method.parameterTypes[0]) - ).target.bindTo(instance).invokeExact() as Consumer<Any> - } catch (e: Throwable) { - throw IllegalArgumentException("Method $name is not a valid consumer", e) - } - } - - fun freeze() { - isFrozen = true - listeners.sortBy { it.options.priority } - canReceiveCancelled = listeners.any { it.options.receiveCancelled } - } - fun post(event: T, onError: ((Throwable) -> Unit)? = null): Boolean { invokeCount++ if (this.listeners.isEmpty()) return false - if (!isFrozen) error("Cannot invoke event on unfrozen event handler") if (SkyHanniEvents.isDisabledHandler(name)) return false @@ -112,7 +60,7 @@ class EventHandler<T : SkyHanniEvent> private constructor(val name: String, priv return event.isCancelled } - private fun shouldInvoke(event: SkyHanniEvent, listener: Listener): Boolean { + private fun shouldInvoke(event: SkyHanniEvent, listener: EventListeners.Listener): Boolean { if (SkyHanniEvents.isDisabledInvoker(listener.name)) return false if (listener.options.onlyOnSkyblock && !LorenzUtils.inSkyBlock) return false if (IslandType.ANY !in listener.onlyOnIslandTypes && !inAnyIsland(listener.onlyOnIslandTypes)) return false @@ -126,19 +74,4 @@ class EventHandler<T : SkyHanniEvent> private constructor(val name: String, priv } return true } - - private class Listener( - val name: String, - val invoker: Consumer<Any>, - val options: HandleEvent, - val generic: Class<*>?, - ) { - val onlyOnIslandTypes: Set<IslandType> = getIslands(options) - - companion object { - private fun getIslands(options: HandleEvent): Set<IslandType> = - if (options.onlyOnIslands.isEmpty()) setOf(options.onlyOnIsland) - else options.onlyOnIslands.toSet() - } - } } diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt new file mode 100644 index 000000000..ce8194ebc --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventListeners.kt @@ -0,0 +1,78 @@ +package at.hannibal2.skyhanni.api.event + +import at.hannibal2.skyhanni.data.IslandType +import java.lang.invoke.LambdaMetafactory +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType +import java.lang.reflect.Method +import java.lang.reflect.ParameterizedType +import java.util.function.Consumer + +class EventListeners private constructor(val name: String, private val isGeneric: Boolean) { + + private val listeners: MutableList<Listener> = mutableListOf() + + constructor(event: Class<*>) : this( + (event.name.split(".").lastOrNull() ?: event.name).replace("$", "."), + GenericSkyHanniEvent::class.java.isAssignableFrom(event) + ) + + fun addListener(method: Method, instance: Any, options: HandleEvent) { + val generic: Class<*>? = if (isGeneric) { + method.genericParameterTypes + .firstNotNullOfOrNull { it as? ParameterizedType } + ?.let { it.actualTypeArguments.firstOrNull() as? Class<*> } + ?: throw IllegalArgumentException("Generic event handler must have a generic type") + } else { + null + } + val name = "${method.declaringClass.name}.${method.name}${ + method.parameterTypes.joinTo( + StringBuilder(), + prefix = "(", + postfix = ")", + separator = ", ", + transform = Class<*>::getTypeName + ) + }" + listeners.add(Listener(name, createEventConsumer(name, instance, method), options, generic)) + } + + /** + * Creates a consumer using LambdaMetafactory, this is the most efficient way to reflectively call + * a method from within code. + */ + @Suppress("UNCHECKED_CAST") + private fun createEventConsumer(name: String, instance: Any, method: Method): Consumer<Any> { + try { + val handle = MethodHandles.lookup().unreflect(method) + return LambdaMetafactory.metafactory( + MethodHandles.lookup(), + "accept", + MethodType.methodType(Consumer::class.java, instance::class.java), + MethodType.methodType(Nothing::class.javaPrimitiveType, Object::class.java), + handle, + MethodType.methodType(Nothing::class.javaPrimitiveType, method.parameterTypes[0]) + ).target.bindTo(instance).invokeExact() as Consumer<Any> + } catch (e: Throwable) { + throw IllegalArgumentException("Method $name is not a valid consumer", e) + } + } + + fun getListeners(): List<Listener> = listeners + + class Listener( + val name: String, + val invoker: Consumer<Any>, + val options: HandleEvent, + val generic: Class<*>?, + ) { + val onlyOnIslandTypes: Set<IslandType> = getIslands(options) + + companion object { + private fun getIslands(options: HandleEvent): Set<IslandType> = + if (options.onlyOnIslands.isEmpty()) setOf(options.onlyOnIsland) + else options.onlyOnIslands.toSet() + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt index e3dff2014..ace86b224 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvents.kt @@ -11,6 +11,7 @@ import java.lang.reflect.Method @SkyHanniModule object SkyHanniEvents { + private val listeners: MutableMap<Class<*>, EventListeners> = mutableMapOf() private val handlers: MutableMap<Class<*>, EventHandler<*>> = mutableMapOf() private var disabledHandlers = emptySet<String>() private var disabledHandlerInvokers = emptySet<String>() @@ -21,12 +22,14 @@ object SkyHanniEvents { registerMethod(it, instance) } } - handlers.values.forEach { it.freeze() } } @Suppress("UNCHECKED_CAST") fun <T : SkyHanniEvent> getEventHandler(event: Class<T>): EventHandler<T> = handlers.getOrPut(event) { - EventHandler(event) + EventHandler( + event, + getEventClasses(event).mapNotNull { listeners[it] }.flatMap(EventListeners::getListeners) + ) } as EventHandler<T> fun isDisabledHandler(handler: String): Boolean = handler in disabledHandlers @@ -38,8 +41,8 @@ object SkyHanniEvents { val options = method.getAnnotation(HandleEvent::class.java) ?: return val event = method.parameterTypes[0] if (!SkyHanniEvent::class.java.isAssignableFrom(event)) return - val handler = getEventHandler(event as Class<SkyHanniEvent>) - handler.addListener(method, instance, options) + listeners.getOrPut(event as Class<SkyHanniEvent>) { EventListeners(event) } + .addListener(method, instance, options) } @SubscribeEvent @@ -61,4 +64,23 @@ object SkyHanniEvents { } } } + + /** + * Returns a list of all super classes and the class itself up to [SkyHanniEvent]. + */ + private fun getEventClasses(clazz: Class<*>): List<Class<*>> { + val classes = mutableListOf<Class<*>>() + classes.add(clazz) + + var current = clazz + while (current.superclass != null) { + val superClass = current.superclass + if (superClass == SkyHanniEvent::class.java) break + if (superClass == GenericSkyHanniEvent::class.java) break + if (superClass == CancellableSkyHanniEvent::class.java) break + classes.add(superClass) + current = superClass + } + return classes + } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/ItemClickData.kt b/src/main/java/at/hannibal2/skyhanni/data/ItemClickData.kt index e7fa75331..2bcf589a3 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ItemClickData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ItemClickData.kt @@ -24,23 +24,23 @@ object ItemClickData { packet is C08PacketPlayerBlockPlacement -> { if (packet.placedBlockDirection != 255) { val position = packet.position.toLorenzVec() - BlockClickEvent(ClickType.RIGHT_CLICK, position, packet.stack).postAndCatch() + BlockClickEvent(ClickType.RIGHT_CLICK, position, packet.stack).post() } else { - ItemClickEvent(InventoryUtils.getItemInHand(), ClickType.RIGHT_CLICK).postAndCatch() + ItemClickEvent(InventoryUtils.getItemInHand(), ClickType.RIGHT_CLICK).post() } } packet is C07PacketPlayerDigging && packet.status == C07PacketPlayerDigging.Action.START_DESTROY_BLOCK -> { val position = packet.position.toLorenzVec() val blockClickCancelled = - BlockClickEvent(ClickType.LEFT_CLICK, position, InventoryUtils.getItemInHand()).postAndCatch() + BlockClickEvent(ClickType.LEFT_CLICK, position, InventoryUtils.getItemInHand()).post() ItemClickEvent(InventoryUtils.getItemInHand(), ClickType.LEFT_CLICK).also { - it.isCanceled = blockClickCancelled - }.postAndCatch() + if (blockClickCancelled) it.cancel() + }.post() } packet is C0APacketAnimation -> { - ItemClickEvent(InventoryUtils.getItemInHand(), ClickType.LEFT_CLICK).postAndCatch() + ItemClickEvent(InventoryUtils.getItemInHand(), ClickType.LEFT_CLICK).post() } packet is C02PacketUseEntity -> { @@ -51,7 +51,7 @@ object ItemClickData { else -> return } val clickedEntity = packet.getEntityFromWorld(Minecraft.getMinecraft().theWorld) ?: return - EntityClickEvent(clickType, clickedEntity, InventoryUtils.getItemInHand()).postAndCatch() + EntityClickEvent(clickType, clickedEntity, InventoryUtils.getItemInHand()).post() } else -> { diff --git a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt index 47133f199..54d186ae5 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt @@ -163,7 +163,7 @@ object MiningAPI { } } - @SubscribeEvent + @HandleEvent fun onBlockClick(event: BlockClickEvent) { if (!inCustomMiningIsland()) return if (event.clickType != ClickType.LEFT_CLICK) return diff --git a/src/main/java/at/hannibal2/skyhanni/events/BlockClickEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/BlockClickEvent.kt index 2822c28a9..42587b390 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/BlockClickEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/BlockClickEvent.kt @@ -4,9 +4,7 @@ import at.hannibal2.skyhanni.data.ClickType import at.hannibal2.skyhanni.utils.BlockUtils.getBlockStateAt import at.hannibal2.skyhanni.utils.LorenzVec import net.minecraft.item.ItemStack -import net.minecraftforge.fml.common.eventhandler.Cancelable -@Cancelable class BlockClickEvent(clickType: ClickType, val position: LorenzVec, itemInHand: ItemStack?) : WorldClickEvent(itemInHand, clickType) { diff --git a/src/main/java/at/hannibal2/skyhanni/events/EntityClickEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/EntityClickEvent.kt index d0cf14214..2c85ef110 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/EntityClickEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/EntityClickEvent.kt @@ -3,8 +3,6 @@ package at.hannibal2.skyhanni.events import at.hannibal2.skyhanni.data.ClickType import net.minecraft.entity.Entity import net.minecraft.item.ItemStack -import net.minecraftforge.fml.common.eventhandler.Cancelable -@Cancelable class EntityClickEvent(clickType: ClickType, val clickedEntity: Entity?, itemInHand: ItemStack?) : WorldClickEvent(itemInHand, clickType) diff --git a/src/main/java/at/hannibal2/skyhanni/events/ItemClickEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/ItemClickEvent.kt index a34cb43f1..e0a96d7e5 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/ItemClickEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/ItemClickEvent.kt @@ -2,7 +2,5 @@ package at.hannibal2.skyhanni.events import at.hannibal2.skyhanni.data.ClickType import net.minecraft.item.ItemStack -import net.minecraftforge.fml.common.eventhandler.Cancelable -@Cancelable class ItemClickEvent(itemInHand: ItemStack?, clickType: ClickType) : WorldClickEvent(itemInHand, clickType) diff --git a/src/main/java/at/hannibal2/skyhanni/events/WorldClickEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/WorldClickEvent.kt index 4597041a1..ff3892859 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/WorldClickEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/WorldClickEvent.kt @@ -1,8 +1,7 @@ package at.hannibal2.skyhanni.events +import at.hannibal2.skyhanni.api.event.CancellableSkyHanniEvent import at.hannibal2.skyhanni.data.ClickType import net.minecraft.item.ItemStack -import net.minecraftforge.fml.common.eventhandler.Cancelable -@Cancelable -open class WorldClickEvent(val itemInHand: ItemStack?, val clickType: ClickType) : LorenzEvent() +open class WorldClickEvent(val itemInHand: ItemStack?, val clickType: ClickType) : CancellableSkyHanniEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonAPI.kt index f95c846b2..7ea372b20 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonAPI.kt @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.features.dungeon +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.ClickType import at.hannibal2.skyhanni.data.ClickedBlockType import at.hannibal2.skyhanni.data.IslandType @@ -360,9 +361,9 @@ object DungeonAPI { } } - @SubscribeEvent + @HandleEvent(onlyOnIsland = IslandType.CATACOMBS) fun onBlockClick(event: BlockClickEvent) { - if (!inDungeon() || event.clickType != ClickType.RIGHT_CLICK) return + if (event.clickType != ClickType.RIGHT_CLICK) return val position = event.position val blockType: ClickedBlockType = when (position.getBlockAt()) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt index 2257772c8..fe7a73d09 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.features.event.carnival import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.Perk import at.hannibal2.skyhanni.events.EntityClickEvent import at.hannibal2.skyhanni.events.LorenzChatEvent @@ -34,7 +35,7 @@ object CarnivalQuickStart { private var lastChat = SimpleTimeMark.farPast() private var lastClicked = SimpleTimeMark.farPast() - @SubscribeEvent + @HandleEvent fun onEntityClick(event: EntityClickEvent) { if (!isEnabled()) return if (lastChat.passedSince() > 5.0.seconds) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaFixChat.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaFixChat.kt index 2f3d19c24..aefce4e58 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaFixChat.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaFixChat.kt @@ -1,7 +1,9 @@ package at.hannibal2.skyhanni.features.event.diana import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.ClickType +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.events.BurrowGuessEvent import at.hannibal2.skyhanni.events.ItemClickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent @@ -102,7 +104,7 @@ object DianaFixChat { } } - @SubscribeEvent + @HandleEvent(onlyOnIsland = IslandType.HUB) fun onItemClick(event: ItemClickEvent) { if (!isEnabled()) return if (event.clickType != ClickType.RIGHT_CLICK) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt index 57cc77df5..64b33c934 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowHelper.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.features.event.diana import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.data.EntityMovementData import at.hannibal2.skyhanni.data.IslandType @@ -358,7 +359,7 @@ object GriffinBurrowHelper { event.move(2, "diana", "event.diana") } - @SubscribeEvent + @HandleEvent(onlyOnIsland = IslandType.HUB) fun onBlockClick(event: BlockClickEvent) { if (!isEnabled()) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt index 80d6ea0e0..f3860276a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt @@ -165,7 +165,7 @@ object GriffinBurrowParticleFinder { return true } - @SubscribeEvent + @HandleEvent(onlyOnIsland = IslandType.HUB) fun onBlockClick(event: BlockClickEvent) { if (!isEnabled()) return if (!config.burrowsSoopyGuess) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt index bef61bfbf..92dbd9dcb 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt @@ -208,7 +208,7 @@ object HoppityEggLocator { lastParticlePosition = null } - @SubscribeEvent + @HandleEvent(onlyOnSkyblock = true) fun onItemClick(event: ItemClickEvent) { if (!isEnabled()) return val item = event.itemInHand ?: return diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt index 4e80bdbea..7e1800931 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt @@ -213,10 +213,8 @@ object GardenAPI { private var lastLocation: LorenzVec? = null - @SubscribeEvent + @HandleEvent(onlyOnIsland = IslandType.GARDEN) fun onBlockClick(event: BlockClickEvent) { - if (!inGarden()) return - val blockState = event.getBlockState val cropBroken = blockState.getCropType() ?: return if (cropBroken.multiplier == 1 && blockState.isBabyCrop()) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleLine.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleLine.kt index ff9af9cff..bd8636b9f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleLine.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleLine.kt @@ -1,7 +1,9 @@ package at.hannibal2.skyhanni.features.garden.pests import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.ClickType +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.events.ItemClickEvent import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent import at.hannibal2.skyhanni.events.ReceiveParticleEvent @@ -33,7 +35,7 @@ object PestParticleLine { private var lastPestTrackerUse = SimpleTimeMark.farPast() private val locations = mutableListOf<MutableList<ParticleLocation>>() |
