/*
* This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT).
*
* Copyright (c) JCThePants (www.jcwhatever.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.jcwhatever.nucleus.events.manager;
import com.jcwhatever.nucleus.Nucleus;
import com.jcwhatever.nucleus.collections.ElementCounter;
import com.jcwhatever.nucleus.mixins.IDisposable;
import com.jcwhatever.nucleus.mixins.IPluginOwned;
import com.jcwhatever.nucleus.utils.PreCon;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockCanBuildEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.event.block.BlockExpEvent;
import org.bukkit.event.block.BlockFadeEvent;
import org.bukkit.event.block.BlockFormEvent;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockGrowEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockMultiPlaceEvent;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.EntityBlockFormEvent;
import org.bukkit.event.block.LeavesDecayEvent;
import org.bukkit.event.block.NotePlayEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.enchantment.EnchantItemEvent;
import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.CreeperPowerEvent;
import org.bukkit.event.entity.EntityBreakDoorEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityCombustByBlockEvent;
import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.entity.EntityCombustEvent;
import org.bukkit.event.entity.EntityCreatePortalEvent;
import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityInteractEvent;
import org.bukkit.event.entity.EntityPortalEnterEvent;
import org.bukkit.event.entity.EntityPortalEvent;
import org.bukkit.event.entity.EntityPortalExitEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.EntityTameEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
import org.bukkit.event.entity.EntityTeleportEvent;
import org.bukkit.event.entity.EntityUnleashEvent;
import org.bukkit.event.entity.ExpBottleEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.HorseJumpEvent;
import org.bukkit.event.entity.ItemDespawnEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.entity.PigZapEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.PlayerLeashEntityEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.entity.SheepDyeWoolEvent;
import org.bukkit.event.entity.SlimeSplitEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.hanging.HangingEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.inventory.BrewEvent;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.FurnaceBurnEvent;
import org.bukkit.event.inventory.FurnaceExtractEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryEvent;
import org.bukkit.event.inventory.InventoryInteractEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerAnimationEvent;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.player.PlayerBedLeaveEvent;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerChatTabCompleteEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerEditBookEvent;
import org.bukkit.event.player.PlayerEggThrowEvent;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.event.player.PlayerExpChangeEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerGameModeChangeEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemBreakEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerLevelChangeEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRegisterChannelEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
import org.bukkit.event.player.PlayerStatisticIncrementEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerToggleFlightEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.event.player.PlayerToggleSprintEvent;
import org.bukkit.event.player.PlayerUnleashEntityEvent;
import org.bukkit.event.player.PlayerUnregisterChannelEvent;
import org.bukkit.event.player.PlayerVelocityEvent;
import org.bukkit.event.vehicle.VehicleCreateEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.vehicle.VehicleEntityCollisionEvent;
import org.bukkit.event.vehicle.VehicleEvent;
import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.event.vehicle.VehicleUpdateEvent;
import org.bukkit.event.weather.LightningStrikeEvent;
import org.bukkit.event.weather.ThunderChangeEvent;
import org.bukkit.event.weather.WeatherChangeEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkPopulateEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.PortalCreateEvent;
import org.bukkit.event.world.SpawnChangeEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.Plugin;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
/**
* Used to forward Bukkit events.
*
* <p>The forwarder listens to events that are registered via {@link #register}
* and forwards the events to one of the appropriate abstract methods.</p>
*
* <p>An event forwarder can be used to forward the received Bukkit events to
* another event manager instance that is used in a context that might be
* interested in the event.</p>
*
* <p>If you need to unregister the forwarder, invoke the {@link #dispose} method.</p>
*/
public abstract class BukkitEventForwarder implements IPluginOwned, IDisposable {
private static final Listener GLOBAL_DUMMY_LISTENER = new Listener() {};
private static final ElementCounter<Class<? extends Event>> ALL_REGISTERED =
new ElementCounter<Class<? extends Event>>(ElementCounter.RemovalPolicy.REMOVE);
private static final Set<Class<? extends Event>> GLOBAL_REGISTERED = new HashSet<>(35);
private static final Map<Forwarder, Void> FORWARDERS = new WeakHashMap<>(35);
private static final EventExecutor GLOBAL_EXECUTOR = new EventExecutor() {
@Override
public void execute(Listener listener, Event event) throws EventException {
for (Forwarder forwarder : FORWARDERS.keySet()) {
forwarder.on(event);
}
}
};
private static boolean _isInitialized;
public static void registerGlobal(Plugin plugin, Class<? extends Event> event) {
PreCon.notNull(event);
if (GLOBAL_REGISTERED.contains(event))
return;
GLOBAL_REGISTERED.add(event);
ALL_REGISTERED.add(event);
Bukkit.getPluginManager().registerEvent(event, GLOBAL_DUMMY_LISTENER,
EventPriority.HIGHEST, GLOBAL_EXECUTOR, plugin, false);
}
public static void init() {
if (_isInitialized)
return;
_isInitialized = true;
new RegistrationHelper()
/* Block events */
.reg(BlockBreakEvent.class)
.reg(BlockBurnEvent.class)
.reg(BlockCanBuildEvent.class)
.reg(BlockDamageEvent.class)
.reg(BlockDispenseEvent.class)
.reg(BlockExpEvent.class)
.reg(BlockFadeEvent.class)
.reg(BlockFormEvent.class)
.reg(BlockFromToEvent.class)
.reg(BlockGrowEvent.class)
.reg(BlockIgniteEvent.class)
.reg(BlockMultiPlaceEvent.class)
.reg(BlockPhysicsEvent.class)
.reg(BlockPistonExtendEvent.class)
.reg(BlockPistonRetractEvent.class)
.reg(BlockPlaceEvent.class)
.reg(BlockRedstoneEvent.class)
.reg(BlockSpreadEvent.class)
.reg(EntityBlockFormEvent.class)
.reg(LeavesDecayEvent.class)
.reg(NotePlayEvent.class)
.reg(SignChangeEvent.class)
/* Enchantment events */
.reg(EnchantItemEvent.class)
.reg(PrepareItemEnchantEvent.class)
/* Entity events*/
.reg(CreatureSpawnEvent.class)
.reg(CreeperPowerEvent.class)
.reg(EntityBreakDoorEvent.class)
.reg(EntityChangeBlockEvent.class)
.reg(EntityCombustByBlockEvent.class)
.reg(EntityCombustByEntityEvent.class)
.reg(EntityCombustEvent.class)
.reg(EntityCreatePortalEvent.class)
.reg(EntityDamageByBlockEvent.class)
.reg(EntityDamageByEntityEvent.class)
.reg(EntityDamageEvent.class)
.reg(EntityDeathEvent.class)
.reg(EntityExplodeEvent.class)
.reg(EntityInteractEvent.class)
.reg(EntityPortalEnterEvent.class)
.reg(EntityPortalEvent.class)
.reg(EntityPortalExitEvent.class)
.reg(EntityRegainHealthEvent.class)
.reg(EntityShootBowEvent.class)
.reg(EntityTameEvent.class)
.reg(EntityTargetEvent.class)
.reg(EntityTargetLivingEntityEvent.class)
.reg(EntityTeleportEvent.class)
.reg(EntityUnleashEvent.class)
.reg(ExpBottleEvent.class)
.reg(ExplosionPrimeEvent.class)
.reg(FoodLevelChangeEvent.class)
.reg(HorseJumpEvent.class)
.reg(ItemDespawnEvent.class)
.reg(ItemSpawnEvent.class)
.reg(PigZapEvent.class)
.reg(PlayerDeathEvent.class)
.reg(PlayerLeashEntityEvent.class)
.reg(PotionSplashEvent.class)
.reg(ProjectileHitEvent.class)
.reg(ProjectileLaunchEvent.class)
.reg(SheepDyeWoolEvent.class)
.reg(SlimeSplitEvent.class)
/* Hanging events*/
.reg(HangingBreakByEntityEvent.class)
.reg(HangingBreakEvent.class)
.reg(HangingPlaceEvent.class)
/* Inventory events */
.reg(BrewEvent.class)
.reg(CraftItemEvent.class)
.reg(FurnaceBurnEvent.class)
.reg(FurnaceExtractEvent.class)
.reg(FurnaceSmeltEvent.class)
.reg(InventoryClickEvent.class)
.reg(InventoryCloseEvent.class)
.reg(InventoryCreativeEvent.class)
.reg(InventoryDragEvent.class)
.reg(InventoryInteractEvent.class)
.reg(InventoryMoveItemEvent.class)
.reg(InventoryOpenEvent.class)
.reg(InventoryPickupItemEvent.class)
.reg(PrepareItemCraftEvent.class)
/* Player events*/
.reg(PlayerAnimationEvent.class)
.reg(PlayerBedEnterEvent.class)
.reg(PlayerBedLeaveEvent.class)
.reg(PlayerBucketEmptyEvent.class)
.reg(PlayerBucketFillEvent.class)
.reg(PlayerChangedWorldEvent.class)
.reg(PlayerChatTabCompleteEvent.class)
.reg(PlayerCommandPreprocessEvent.class)
.reg(PlayerDropItemEvent.class)
.reg(PlayerEditBookEvent.class)
.reg(PlayerEggThrowEvent.class)
.reg(PlayerExpChangeEvent.class)
.reg(PlayerFishEvent.class)
.reg(PlayerGameModeChangeEvent.class)
.reg(PlayerInteractEntityEvent.class)
.reg(PlayerInteractEvent.class)
.reg(PlayerItemBreakEvent.class)
.reg(PlayerItemConsumeEvent.class)
.reg(PlayerItemHeldEvent.class)
.reg(PlayerJoinEvent.class)
.reg(PlayerKickEvent.class)
.reg(PlayerLevelChangeEvent.class)
.reg(PlayerLoginEvent.class)
.reg(PlayerMoveEvent.class)
.reg(PlayerPickupItemEvent.class)
.reg(PlayerPortalEvent.class)
.reg(PlayerQuitEvent.class)
.reg(PlayerRegisterChannelEvent.class)
.reg(PlayerRespawnEvent.class)
.reg(PlayerShearEntityEvent.class)
.reg(PlayerStatisticIncrementEvent.class)
.reg(PlayerTeleportEvent.class)
.reg(PlayerToggleFlightEvent.class)
.reg(PlayerToggleSneakEvent.class)
.reg(PlayerToggleSprintEvent.class)
.reg(PlayerUnleashEntityEvent.class)
.reg(PlayerUnregisterChannelEvent.class)
.reg(PlayerVelocityEvent.class)
/* Vehicle events */
.reg(VehicleCreateEvent.class)
.reg(VehicleDamageEvent.class)
.reg(VehicleDestroyEvent.class)
.reg(VehicleEnterEvent.class)
.reg(VehicleEntityCollisionEvent.class)
.reg(VehicleExitEvent.class)
.reg(VehicleMoveEvent.class)
.reg(VehicleUpdateEvent.class)
/* Weather events */
.reg(LightningStrikeEvent.class)
.reg(ThunderChangeEvent.class)
.reg(WeatherChangeEvent.class)
/* World events */
.reg(ChunkLoadEvent.class)
.reg(ChunkPopulateEvent.class)
.reg(ChunkUnloadEvent.class)
.reg(PortalCreateEvent.class)
.reg(SpawnChangeEvent.class)
.reg(StructureGrowEvent.class)
.reg(WorldInitEvent.class)
.reg(WorldLoadEvent.class)
.reg(WorldSaveEvent.class)
.reg(WorldUnloadEvent.class);
}
private final Plugin _plugin;
private final Forwarder _forwarder;
private final EventPriority _priority;
private final Listener _dummyListener = new Listener() {};
private final Set<Class<? extends Event>> _registered = new HashSet<>(35);
private final EventExecutor _executor = new EventExecutor() {
@Override
public void execute(Listener listener, Event event) throws EventException {
_forwarder.on(event);
}
};
private boolean _isDisposed;
/**
* Constructor.
*
* @param plugin The owning plugin.
* @param priority The priority of the forwarded events.
*/
public BukkitEventForwarder(Plugin plugin, EventPriority priority) {
PreCon.notNull(plugin);
PreCon.notNull(priority);
_plugin = plugin;
_priority = priority;
_forwarder = new Forwarder();
FORWARDERS.put(_forwarder, null);
}
/**
* Register an event to forward.
*
* @param event The event to forward.
*/
public void register(Class<? extends Event> event) {
PreCon.notNull(event);
if (_registered.contains(event))
return;
_registered.add(event);
Bukkit.getPluginManager().registerEvent(event, _dummyListener,
_priority, _executor, _plugin, false);
}
@Override
public Plugin getPlugin() {
return _plugin;
}
@Override
public boolean isDisposed() {
return _isDisposed;
}
@Override
public void dispose() {
_isDisposed = true;
HandlerList.unregisterAll(_dummyListener);
ALL_REGISTERED.subtractAll(_registered);
}
/**
* Invoked whenever a registered event is called.
*
* @param event The called event
*/
protected abstract void onEvent(Event event);
/**
* Invoked whenever a registered block event is called.
*
* <p>Intended for optional override.</p>
*
* @param event The called event.
*/
protected void onBlockEvent(BlockEvent event) {}
/**
* Invoked whenever a registered player event is called.
*
* <p>Intended for optional override.</p>
*
* @param event The called event.
*/
protected void onPlayerEvent(PlayerEvent event) {}
/**
* Invoked whenever a registered inventory event is called.
*
* <p>Intended for optional override.</p>
*
* @param event The called event.
*/
protected void onInventoryEvent(InventoryEvent event) {}
/**
* Invoked whenever a registered hanging event is called.
*
* <p>Intended for optional override.</p>
*
* @param event The called event.
*/
protected void onHangingEvent(HangingEvent event) {}
/**
* Invoked whenever a registered vehicle event is called.
*
* <p>Intended for optional override.</p>
*
* @param event The called event.
*/
protected void onVehicleEvent(VehicleEvent event) {}
/**
* Invoked whenever a registered entity event is called.
*
* <p>Intended for optional override.</p>
*
* @param event The called event.
*/
protected void onEntityEvent(EntityEvent event) {}
private class Forwarder {
public void on(Object e) {
if (!(e instanceof Event))
return;
Event event = (Event) e;
onEvent(event);
if (event instanceof PlayerEvent) {
onPlayerEvent((PlayerEvent)event);
}
else if (event instanceof BlockEvent) {
onBlockEvent((BlockEvent)event);
}
else if (event instanceof HangingEvent) {
onHangingEvent((HangingEvent)event);
}
else if (event instanceof InventoryEvent) {
onInventoryEvent((InventoryEvent) event);
}
else if (event instanceof VehicleEvent) {
onVehicleEvent((VehicleEvent) event);
}
else if (event instanceof EntityEvent) {
onEntityEvent((EntityEvent) event);
}
}
}
private static class RegistrationHelper {
RegistrationHelper reg(Class<? extends Event> event) {
registerGlobal(Nucleus.getPlugin(), event);
return this;
}
}
}