Refactored listener into multiple classes

Also added a class for egg-related helper methods. Deleted the now-redundant EggRespawn class.
This commit is contained in:
J0nasL 2023-07-01 02:39:39 -04:00
parent c48141239f
commit 3dfecb5226
10 changed files with 939 additions and 774 deletions

View file

@ -9,6 +9,9 @@ import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
/**
* Misc helper methods relating to player notification
*/
public class Announcement {
public static void announce(String message, Logger logger) {
List<Player> players = new ArrayList<>(Bukkit.getOnlinePlayers());
@ -23,7 +26,10 @@ public class Announcement {
logger.info(String.format("Told %d player(s) \"%s\"", playersNotified, message));
}
public static void claimEggEffects(Player Player){
/**
* Creates sound/particle effects to let the given player know that they have claimed the dragon egg
*/
public static void ShowEggClaimEffects(Player Player){
Player.playSound(Player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 10, 0);
Player.spawnParticle(Particle.SPELL_WITCH, Player.getLocation(), 50, 0.3, 0.1, 0.3);
Player.spawnParticle(Particle.PORTAL, Player.getLocation(), 50, 0.3, 0.1, 0.3);

View file

@ -0,0 +1,297 @@
package io.github.J0hnL0cke.egghunt.Controller;
import java.util.List;
import java.util.logging.Logger;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Container;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityCreatePortalEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.ItemDespawnEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.ItemStack;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
import io.github.J0hnL0cke.egghunt.Model.Data.Egg_Storage_Type;
import io.github.J0hnL0cke.egghunt.Model.Egg;
/**
* Listens for Bukkit events related to destruction of the dragon egg
* Prevents destruction or respawns the egg, depending on config settings
*/
public class EggDestroyListener implements Listener {
private Logger logger;
private Configuration config;
private Data data;
public EggDestroyListener(Logger logger, Configuration config, Data data) {
this.logger = logger;
this.config = config;
this.data = data;
}
/**
* Listen for the egg being destroyed
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDamageEvent(EntityDamageEvent event) {
Entity entity = event.getEntity();
if (entity.getType().equals(EntityType.DROPPED_ITEM)) {
ItemStack item = ((Item)entity).getItemStack();
if (Egg.isEgg(item)) {
//make sure item is destroyed to prevent dupes
event.getEntity().remove();
eggDestroyed();
}
}
}
/**
* Notifies that the egg is destroyed if the egg item dies
* Also respawns the egg when the dragon is killed
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent event) {
//if the egg item dies, notify that it has been destroyed
if (event.getEntityType().equals(EntityType.DROPPED_ITEM)) {
if (Egg.isEgg((ItemStack) event.getEntity())) {
//remove just in case to prevent dupes
event.getEntity().remove();
eggDestroyed();
}
}
else if (event.getEntity().getType().equals(EntityType.ITEM_FRAME)
|| event.getEntity().getType().equals(EntityType.GLOW_ITEM_FRAME)) {
ItemFrame frame = (ItemFrame) event.getEntity();
if (Egg.isEgg(frame.getItem())) {
frame.setItem(null); //make sure the item is destroyed
eggDestroyed();
}
}
//if the dragon is killed, respawn the egg
else if (config.getRespawnEgg()) {
if (data.getEggType() == Egg_Storage_Type.DNE) {
//if the egg does not exist
if (event.getEntityType().equals(EntityType.ENDER_DRAGON)) {
//if the dragon is killed
if (config.getEndWorld().getEnderDragonBattle().hasBeenPreviouslyKilled()) {
//if the dragon has already been beaten
respawnEgg();
}
}
}
}
}
/**
* Stop portals from removing the egg
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onCreatePortal(EntityCreatePortalEvent event) {
//not specific to any particular creation reason because multiple events could cause the egg to be removed (obby platform regen, gateway portal spawning, stronghold portal activation)
boolean egg_affected = false;
Location l = null;
List<BlockState> blocks = event.getBlocks();
console_log(String.format("blocks: %s", blocks.toString()));
for (BlockState blockState : blocks) {
console_log(String.format("Block update at %s: from %s to %s", blockState.getLocation(),
blockState.getBlock().getType(), blockState.getType()));
if (blockState.getBlock().getType().equals(Material.DRAGON_EGG)) {
egg_affected = true;
l = blockState.getLocation();
//extra check to make sure egg is removed
blockState.getBlock().setType(Material.AIR);
}
}
if (egg_affected) {
String entityName = "Unknown entity";
if (event.getEntity() != null) {
if (event.getEntity().getCustomName() != null) {
entityName = event.getEntity().getCustomName();
}
}
console_log(String.format("%s tried to overwrite egg with a portal", entityName));
data.resetEggOwner(false);
if (l != null) {
data.updateEggLocation(Egg.spawnEggItem(l, config, data));
} else {
console_log("Could not spawn egg item! Invalid block location.");
}
}
}
/**
* Prevent the egg from despawning
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onDespawn(ItemDespawnEvent event) {
if (Egg.isEgg(event.getEntity().getItemStack())) {
event.setCancelled(true);
//set the age back to 1 so it doesn't try to despawn every tick
event.getEntity().setTicksLived(1);
console_log("Canceled egg despawn");
}
}
/**
* Prevent growing mushrooms from overwriting the egg
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onGrow(StructureGrowEvent event) {
boolean destroy = false;
if (event.getSpecies().equals(TreeType.RED_MUSHROOM)) {
List<BlockState> blocks = event.getBlocks();
for (BlockState blockState : blocks) {
Block block = blockState.getBlock();
if (Egg.isEgg(block)) {
destroy = true;
if (!config.getEggInvincible()) { //if egg will be replaced, make sure it gets removed
block.setType(Material.AIR);
}
} else {
if (blockState instanceof Container) { //TODO exclude item frames, which aren't destroyed by this
Container cont = (Container) blockState;
if (cont.getInventory().contains(Material.DRAGON_EGG)) {
destroy = true;
cont.getInventory().remove(Material.DRAGON_EGG); //make sure egg is removed from container
}
}
}
}
if (destroy) {
if (config.getEggInvincible()) {
event.setCancelled(true);
Player p = event.getPlayer();
if (p != null) {
p.playSound(p.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 1);
p.sendMessage("Cannot grow mushroom: obstructed by dragon egg");
p.setCooldown(Material.BONE_MEAL, 100);
console_log(String.format("%s tried to mushroom the dragon egg", p.getName()));
}
} else {
eggDestroyed();
}
}
}
}
/**
* Cancel events that damage the egg item if enabled in config
* TODO: figure out if this is still needed, since when active, egg is set to be invlunerable
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onConsiderEntityDamageEvent(EntityDamageEvent event) {
if (config.getEggInvincible()) {
Entity entity = event.getEntity();
if (entity.getType().equals(EntityType.DROPPED_ITEM)) {
if (Egg.isEgg((Item) entity)) {
event.setCancelled(true);
}
}
}
}
/**
* When a portal is updated, check if the egg will be replaced
*/
private void checkPortalBlocks() {
//TODO there has to be a better way to do this
//Check end platform
Location l1 = new Location(config.getEndWorld(), 102, 48, 2);
Location l2 = new Location(config.getEndWorld(), 98, 51, -2);
Location res = checkBlockMaterialFromLocation(config.getEndWorld(), Material.DRAGON_EGG, l1, l2);
if (res != null) {
portalOverwriteEgg(res);
}
}
/**
* Update data and spawn a new egg when the egg is overwritten with a portal
*/
private void portalOverwriteEgg(Location res) {
res.getBlock().setType(Material.AIR);
console_log("Egg was overwritten with a portal");
if (config.getEggInvincible()) {
console_log("Spawning new egg");
data.updateEggLocation(Egg.spawnEggItem(res, config, data));
} else {
eggDestroyed();
}
}
/**
* Checks blocks within the cube created by the given locations.
* Returns the first location corresponding to the block found with the given material.
* Returns null if no matching block is found or locations are in different worlds.
*/
private static Location checkBlockMaterialFromLocation(World w, Material m, Location l1, Location l2) {
if (l1.getWorld().equals(l2.getWorld())) {
for (int x = l1.getBlockX(); x < l2.getBlockX(); x++) {
for (int y = l1.getBlockY(); y < l2.getBlockY(); y++) {
for (int z = l1.getBlockZ(); z < l2.getBlockZ(); z++) {
if (w.getBlockAt(x, y, z).getType().equals(m)) {
return new Location(w, x, y, z);
}
}
}
}
}
return null;
}
/**
* Alerts when the egg is destroyed and respawns it if needed
*/
public void eggDestroyed() {
announce("The dragon egg has been destroyed!");
data.resetEggOwner(false);
if (config.getRespawnEgg()) {
if (config.getRespawnImmediately()) {
respawnEgg();
} else {
data.resetEggLocation();
announce("It will respawn the next time the dragon is defeated");
}
}
}
/**
* Respawns the dragon egg in the end
*/
private void respawnEgg() {
data.updateEggLocation(Egg.respawnEgg(config));
announce("The dragon egg has spawned in the end!");
}
private void announce(String msg) {
Announcement.announce(msg, logger);
}
private void console_log(String message) {
logger.info(message);
}
}

View file

@ -1,735 +0,0 @@
package io.github.J0hnL0cke.egghunt.Controller;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Container;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.*;
import org.bukkit.event.inventory.*;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.inventory.AbstractHorseInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
import io.github.J0hnL0cke.egghunt.Model.Data.Egg_Storage_Type;
import java.util.List;
import java.util.logging.Logger;
public class EggHuntListener implements Listener {
/*Store either the location of the block/inventory it is stored in,
or store a reference to the entity that is holding the egg.
Stored entity is separate from the owner because the egg can be stored in any entity
(ex: held by a zombie or item frame), but only players can "own" the egg*/
private Logger logger;
private Configuration config;
private Data data;
public EggHuntListener(Logger logger, Configuration config, Data data) {
this.logger = logger;
this.config = config;
this.data = data;
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onAutosave(WorldSaveEvent event) {
//TODO: don't save data until an autosave happens
data.saveData();
}
// Drop egg if a player logs off with it in their inventory
//TODO: check if item spawn and item drop events overlap, and check which can be replaced
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onLogoff(PlayerQuitEvent event) {
Player player = event.getPlayer();
// Check if the player has a dragon egg
if (player.getInventory().contains(Material.DRAGON_EGG)) {
// Set owner and remove
data.setEggOwner(player); //TODO is this necessary? player will likely already be owner
player.getInventory().remove(Material.DRAGON_EGG);
// Drop it on the floor and set its location
//TODO use drop egg method in EggRespawn
Item egg_drop = event.getPlayer().getWorld().dropItem(player.getLocation(), new ItemStack(Material.DRAGON_EGG));
data.updateEggLocation(egg_drop);
}
}
// Handle egg removal and drop upon the player dropping it
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemDrop(PlayerDropItemEvent event) {
Item item = event.getItemDrop();
ItemStack stack=item.getItemStack();
// Check if the dropped item is the egg
if(isEgg(stack)) {
data.setEggOwner(event.getPlayer());
data.updateEggLocation(item);
makeEggInvulnerable(event.getItemDrop());
}
}
// No handler to check if the falling egg drops an item, so we have to check every item spawn
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemSpawn(ItemSpawnEvent event) {
// Check if the spawned item is the egg
Item item = event.getEntity();
if (isEgg(item)) {
data.updateEggLocation(item);
makeEggInvulnerable(event.getEntity());
}
}
/**
* Handle the egg being picked up by an entity
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPickupItem(EntityPickupItemEvent event) {
// Check if item picked up is an egg
if (isEgg(event.getItem())) {
data.updateEggLocation(event.getEntity());
if (event.getEntity() instanceof Player) {
data.setEggOwner((Player)event.getEntity());
}
}
}
/**
* Handle the egg being picked up by a container (hopper or hopper minecart)
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onHopperCollect(InventoryPickupItemEvent event) {
// Check if the dragon egg was picked up
ItemStack item = event.getItem().getItemStack();
if (isEgg(item)) {
//check if the inventory has open space
//TODO test this with edge cases for hopper pull/push
if (event.getInventory().firstEmpty() != -1 || event.getInventory().contains(Material.DRAGON_EGG)) {
data.updateEggLocation(event.getInventory());
}
}
}
/**
* When the player closes an inventory,
* check the player and the inventory for the egg when the inventory closes.
* This removes the need to check specifics about a player's clicks in an inventory
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClose(InventoryCloseEvent event) {
Player player = (Player) event.getPlayer();
Inventory otherInv = event.getInventory();
//force an egg in the ender chest to be dropped if enabled in config and if the player is not in creative
if (otherInv.getType().equals(InventoryType.ENDER_CHEST)){
if (config.getDropEnderchestedEgg() && player.getGameMode() != GameMode.CREATIVE) {
if (otherInv.contains(Material.DRAGON_EGG)) {
ItemStack egg = otherInv.getItem(otherInv.first(Material.DRAGON_EGG));
Location playerLoc = player.getLocation();
otherInv.remove(egg);
Item i = playerLoc.getWorld().dropItem(playerLoc, egg); //TODO use drop item function
console_log(String.format(
"Dropped the dragon egg on the ground since %s had it in their ender chest.",
player.getName()));
console_log(
"Set ignore_echest_egg to \"true\" in the config file to disable this feature.");
data.updateEggLocation(i);
}
}
//whether the egg is dropped or not, ignore all other checking
//since either egg should be dropped and location has already been updated
//or it should not move and this egg should be ignored entirely
return;
}
if (player.getInventory().contains(Material.DRAGON_EGG)) {
//if the player has the egg in their inventory, it will stay there
data.updateEggLocation(player);
data.setEggOwner(player);
} else if (otherInv.contains(Material.DRAGON_EGG)) {
if (otherInv.getType() != InventoryType.PLAYER) { //TODO check how this affects player viewing own inventory (egg on head/offhand?)
if (otherInv.getHolder() instanceof Container || otherInv instanceof AbstractHorseInventory) { //not instanceof entity- chest llama but not wandering trader
//this is a container (chest, furnace, hopper minecart, etc), so the egg will remain here when the inventory is closed
data.updateEggLocation(otherInv);
} else {
//this is not a container (anvil, crafting table, villager, etc), so it will move back to the player's inventory
//note- if the player's inventory is full, it will instead drop as an item, which will trigger the item drop event
data.updateEggLocation(player);
}
}
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryMove (InventoryMoveItemEvent event) {
//called when an inventory item is moved between blocks (hoppers, dispensers, etc)
//check if the item being moved is the egg
if (isEgg(event.getItem())) {
if (event.getDestination().firstEmpty() != -1 || event.getDestination().contains(Material.DRAGON_EGG)) {
data.updateEggLocation(event.getDestination());
}
}
}
/**
* Handle the egg being placed as a block
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace (BlockPlaceEvent event) {
if (isEgg(event.getBlock())) {
data.updateEggLocation(event.getBlock());
data.setEggOwner(event.getPlayer());
}
}
/**
* Handle the egg being placed in an item frame
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInteract(PlayerInteractEntityEvent event) {
if (event.getRightClicked() instanceof ItemFrame) {
PlayerInventory player_inv = event.getPlayer().getInventory();
if (isEgg(player_inv.getItemInMainHand()) || isEgg(player_inv.getItemInOffHand())) {
data.updateEggLocation(event.getRightClicked());
data.setEggOwner(event.getPlayer());
}
}
}
/**
* Handle the egg teleporting
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpread(BlockFromToEvent event) {
if (isEgg(event.getBlock())) {
data.updateEggLocation(event.getToBlock());
if (!config.getAccurateLocation()) {
//TODO disable accuracy here
console_log("The egg teleported, showing players the egg's location before teleport");
} else {
console_log("The egg teleported, showing players the egg's up-to-date location");
}
if (config.resetOwnerOnTeleport()) {
if (data.getEggOwner() != null) {
announce(String.format("The dragon egg has teleported. %s is no longer the owner.", data.getEggOwner().getName()));
data.resetEggOwner(false);
}
}
}
}
/**
* Handle the egg as a falling block entity
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onFallingBlock(final EntityChangeBlockEvent event){
//check if this is dealing with a falling block, since EntityChangeBlockEvent is generic
if (event.getEntityType() == EntityType.FALLING_BLOCK) {
//if the falling block is the egg
if (isEgg((FallingBlock)event.getEntity())) {
console_log("Gravity event involving dragon egg occured");
if (event.getBlock().getType() == Material.AIR) {
//egg lands
data.updateEggLocation(event.getBlock());
} else if (event.getBlock().getType() == Material.DRAGON_EGG) {
//egg begins falling
data.updateEggLocation(event.getEntity());
}
}
}
}
//if the egg item takes damage, call eggDestroyed
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDamageEvent(EntityDamageEvent event) {
Entity entity = event.getEntity();
if (entity.getType().equals(EntityType.DROPPED_ITEM)) {
ItemStack item = ((Item)entity).getItemStack();
if (isEgg(item)) {
//make sure item is destroyed to prevent dupes
event.getEntity().remove();
eggDestroyed();
}
}
}
/**
* Notifies that the egg is destroyed if the egg item dies
* Also respawns the egg when the dragon is killed
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent event) {
//if the egg item dies, notify that it has been destroyed
if (event.getEntityType().equals(EntityType.DROPPED_ITEM)) {
if (isEgg((ItemStack) event.getEntity())) {
//remove just in case to prevent dupes
event.getEntity().remove();
eggDestroyed();
}
}
else if (event.getEntity().getType().equals(EntityType.ITEM_FRAME)
|| event.getEntity().getType().equals(EntityType.GLOW_ITEM_FRAME)) {
ItemFrame frame = (ItemFrame) event.getEntity();
if (isEgg(frame.getItem())) {
frame.setItem(null); //make sure the item is destroyed
eggDestroyed();
}
}
//if the dragon is killed, respawn the egg
else if (config.getRespawnEgg()) {
if (data.getEggType() == Egg_Storage_Type.DNE) {
//if the egg does not exist
if (event.getEntityType().equals(EntityType.ENDER_DRAGON)) {
//if the dragon is killed
if (config.getEndWorld().getEnderDragonBattle().hasBeenPreviouslyKilled()) {
//if the dragon has already been beaten
spawnEggBlock();
}
}
}
}
}
//stop portals from removing the egg
@EventHandler(priority = EventPriority.MONITOR)
public void onCreatePortal(EntityCreatePortalEvent event) {
//not specific to any particular creation reason because multiple events could cause the egg to be removed (obby platform regen, gateway portal spawning, stronghold portal activation)
boolean egg_affected=false;
Location l = null;
List<BlockState> blocks=event.getBlocks();
console_log(String.format("blocks: %s",blocks.toString()));
for (BlockState blockState : blocks) {
console_log(String.format("Block update at %s: from %s to %s", blockState.getLocation(),
blockState.getBlock().getType(), blockState.getType()));
if (blockState.getBlock().getType().equals(Material.DRAGON_EGG)) {
egg_affected = true;
l = blockState.getLocation();
//extra check to make sure egg is removed
blockState.getBlock().setType(Material.AIR);
}
}
if (egg_affected) {
String entityName="Unknown entity";
if (event.getEntity()!=null) {
if (event.getEntity().getCustomName()!=null) {
entityName=event.getEntity().getCustomName();
}
}
console_log(String.format("%s tried to overwrite egg with a portal",entityName));
data.resetEggOwner(false);
if (l!=null) {
EggRespawn.spawnEggItem(l, config, data);
} else {
console_log("Could not spawn egg item! Invalid block location.");
}
}
}
//Other event handlers
@EventHandler(priority = EventPriority.HIGHEST)
public void onDespawn (ItemDespawnEvent event) {
//if the egg is going to despawn, cancel it
if (isEgg(event.getEntity().getItemStack())) {
event.setCancelled(true);
//set the age back to 1 so it doesn't try to despawn every tick
event.getEntity().setTicksLived(1);
console_log("Canceled egg despawn");
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerDeath(PlayerDeathEvent event) {
if (!event.getKeepInventory() && event.getEntity().getInventory().contains(Material.DRAGON_EGG)) {
data.resetEggOwner(false);
//change the death message
String deathmsg = event.getDeathMessage();
if (deathmsg == null || deathmsg.isBlank()) {
announce(String.format("%s died and lost the dragon egg!", event.getEntity().getDisplayName()));
} else {
if (deathmsg.endsWith(".")) {
deathmsg = deathmsg.substring(0, deathmsg.length() - 1);
}
event.setDeathMessage(String.format("%s and lost the dragon egg!", deathmsg));
}
}
}
/**
* stop mushrooms from removing the egg
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onGrow(StructureGrowEvent event) {
boolean destroy = false;
if (event.getSpecies().equals(TreeType.RED_MUSHROOM)) {
List<BlockState> blocks = event.getBlocks();
for (BlockState blockState : blocks) {
Block block = blockState.getBlock();
if (isEgg(block)) {
destroy = true;
if (!config.getEggInvincible()) { //if egg will be replaced, make sure it gets removed
block.setType(Material.AIR);
}
} else {
if (blockState instanceof Container) { //TODO exclude item frames, which aren't destroyed by this
Container cont = (Container) blockState;
if (cont.getInventory().contains(Material.DRAGON_EGG)) {
destroy = true;
cont.getInventory().remove(Material.DRAGON_EGG); //make sure egg is removed from container
}
}
}
}
if (destroy) {
if (config.getEggInvincible()) {
event.setCancelled(true);
Player p = event.getPlayer();
if (p != null) {
p.playSound(p.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 1);
p.sendMessage("Cannot grow mushroom: obstructed by dragon egg");
p.setCooldown(Material.BONE_MEAL, 100);
console_log(String.format("%s tried to mushroom the dragon egg", p.getName()));
}
} else {
eggDestroyed();
}
}
}
}
/**
* Stops players from holding the egg in their cursor then dragging to drop it into an ender chest or shulker box.
*
* Note: due to limitations with the API, this prevents dragging the egg when viewing an ender chest or shulker box,
* even if the egg is only dragged over slots in the player's inventory.
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryDragConsider(InventoryDragEvent event) {
InventoryType inv = event.getInventory().getType(); //this only gets the currently viewed ("top") inventory, which is not necessairly where the items are dragged in/over
if (event.getWhoClicked().getGameMode() != GameMode.CREATIVE) {
if (inv.equals(InventoryType.ENDER_CHEST) || inv.equals(InventoryType.SHULKER_BOX)) {
boolean holdEgg = isEgg(event.getOldCursor());
if (holdEgg) {
event.setCancelled(true);
console_log(String.format("Stopped %s from dragging egg while viewing shulker/ender chest",
event.getWhoClicked().getName()));
}
}
}
}
/**
* Stop players from storing the egg in an ender chest or shulker box.
* Also stops the player from putting the egg into a bundle regardless of open inventory.
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryMoveConsider(InventoryClickEvent event) {
InventoryType inv = event.getInventory().getType();
if (event.getWhoClicked().getGameMode() != GameMode.CREATIVE) {
if (inv.equals(InventoryType.ENDER_CHEST) || inv.equals(InventoryType.SHULKER_BOX)) {
boolean hoverEgg = isEgg(event.getCurrentItem());
boolean holdEgg = isEgg(event.getCursor());
Boolean clickedContainer = null;
if (event.getClickedInventory() != null) {
clickedContainer = event.getClickedInventory().equals(event.getInventory());
}
//if the other inventory is an ender chest or shulker box
if (hoverEgg || holdEgg) {
//clicked on the egg or holding the egg with the cursor
boolean cancel = false;
if (clickedContainer == null){
logger.info(event.getAction().toString());
} else if (clickedContainer) {
//player clicked the container
switch (event.getAction()) {
case COLLECT_TO_CURSOR:
case HOTBAR_MOVE_AND_READD:
case MOVE_TO_OTHER_INVENTORY:
case HOTBAR_SWAP:
if (hoverEgg) {
//the egg is on the current item so these are not allowed
cancel = true;
}
//if the current item is not an egg, allow this action
//(eg allow shift+clicking items out of the ender chest while cursor holding the egg)
break;
default:
cancel = true; //no interaction is allowed in this case
}
} else {
//player clicked on own inventory
//prevent any action that would move the egg into/from the ender chest (other than hotkey, which is prevented below)
switch (event.getAction()) {
case MOVE_TO_OTHER_INVENTORY:
if(hoverEgg){ //prevent only if hovering over the egg, not if holding it
cancel=true;
}
break;
case COLLECT_TO_CURSOR:
cancel = true; //cancel these actions
default:
break;
}
}
if (cancel) {
//if the item clicked was the egg
event.setCancelled(true);
console_log(String.format("Stopped %s from moving egg to shulker/ender chest",
event.getWhoClicked().getName()));
}
}
//don't allow hotkeying either
if (event.getClick().equals(ClickType.NUMBER_KEY)) {
ItemStack item = event.getWhoClicked().getInventory().getItem(event.getHotbarButton());
if (item != null) {
if (event.getClickedInventory().equals(event.getInventory())) {
//make sure the destination is the ender chest
//this allows hotkeying the egg around in the player's inventory
if (isEgg(item)) {
event.setCancelled(true);
console_log(String.format("Stopped %s from hotkeying egg to shulker/ender chest",
event.getWhoClicked().getName()));
}
}
}
}
}
//prevent using bundles on the egg in *any* inventory
if(event.getCurrentItem() != null){
if(event.getCursor()!=null){
ItemStack clicked=event.getCurrentItem();
ItemStack cursor=event.getCursor();
if ((isEgg(cursor) && clicked.getType() == Material.BUNDLE)
|| (isEgg(clicked) && cursor.getType() == Material.BUNDLE)) {
event.setCancelled(true);
console_log(String.format("Stopped %s from bundling the egg",
event.getWhoClicked().getName()));
}
}
}
}
}
/**
* stop players from pushing the egg into a shulker using a hopper/hopper minecart
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onPushConsider (InventoryMoveItemEvent event) {
//nice try, but it won't work
if (event.getDestination().getType().equals(InventoryType.SHULKER_BOX)){
if (isEgg(event.getItem())) {
event.setCancelled(true);
}
}
}
//Prevent egg destruction
//TODO: figure out if this is still needed
@EventHandler(priority = EventPriority.HIGHEST)
public void onConsiderEntityDamageEvent(EntityDamageEvent event) {
if (config.getEggInvincible()) {
Entity entity=event.getEntity();
if (entity.getType().equals(EntityType.DROPPED_ITEM)) {
if (isEgg((Item)entity)) {
event.setCancelled(true);
}
}
}
}
//Helper methods
//When a portal is updated, check if the egg will be replaced
private void checkPortalBlocks() {
//TODO there has to be a better way to do this
//Check end platform
Location l1=new Location(config.getEndWorld(),102,48,2);
Location l2=new Location(config.getEndWorld(),98,51,-2);
Location res=checkBlockMaterialFromLocation(config.getEndWorld(),Material.DRAGON_EGG,l1,l2);
if (res!=null) {
portalOverwriteEgg(res);
}
}
private void portalOverwriteEgg(Location res) {
res.getBlock().setType(Material.AIR);
console_log("Egg was overwritten with a portal");
if (config.getEggInvincible()) {
console_log("Spawning new egg");
EggRespawn.spawnEggItem(res, config, data);
} else {
eggDestroyed();
}
}
/**
* Checks various blocks for the given material
* @param w world the position is in
* @param m material to check
* @param x1 starting x pos
* @param x2 ending x pos
* @param y1 starting y pos
* @param y2 ending y pos
* @param z1 starting z pos
* @param z2 ending z pos
* @return
*/
private static Location checkBlockMaterial(World w, Material m, int x1, int x2, int y1, int y2, int z1, int z2) {
for (int x=x1; x<x2; x++) {
for (int y=y1; y<y2; y++) {
for (int z=z1; z<z2; z++) {
if (w.getBlockAt(x, y, z).getType().equals(m)) {
return new Location(w,x,y,z);
}
}
}
}
return null;
}
private static Location checkBlockMaterialFromLocation(World w, Material m, Location l1, Location l2) {
return checkBlockMaterial(w,m,l1.getBlockX(),l1.getBlockY(),l1.getBlockZ(),l2.getBlockX(),l2.getBlockY(),l2.getBlockZ());
}
/**
* Calls CheckBlockMaterial with deltas
*/
private static Location checkDeltaBlockMaterial(World w, Material m, int x, int dx, int y, int dy, int z, int dz) {
return (checkBlockMaterial(w, m, x, x+dx, y, y+dy, z, z+dz));
}
private void makeEggInvulnerable(Entity egg_stack) {
if (config.getEggInvincible()) {
egg_stack.setInvulnerable(true);
console_log("made drop invulnerable");
}
}
public void eggDestroyed() {
announce("The dragon egg has been destroyed!");
data.resetEggOwner(false);
if (config.getRespawnEgg()) {
if (config.getRespawnImmediately()) {
spawnEggBlock();
} else {
data.resetEggLocation();
announce("It will respawn the next time the dragon is defeated");
}
}
}
private void spawnEggBlock() {
Block newEggLoc = config.getEndWorld().getEnderDragonBattle().getEndPortalLocation().add(0, 4, 0).getBlock();
newEggLoc.setType(Material.DRAGON_EGG);
data.updateEggLocation(newEggLoc);
announce("The dragon egg has spawned in the end!");
}
private boolean isEgg(ItemStack stack) {
if (stack == null) {
return false;
}
return stack.getType().equals(Material.DRAGON_EGG);
}
private boolean isEgg(Item item) {
if (item == null) {
return false;
}
return item.getItemStack().getType().equals(Material.DRAGON_EGG);
}
private boolean isEgg(Block block) {
if (block == null) {
return false;
}
return block.getType().equals(Material.DRAGON_EGG);
}
private boolean isEgg(FallingBlock block) {
if (block == null) {
return false;
}
return block.getBlockData().getMaterial().equals(Material.DRAGON_EGG);
}
private ItemStack makeEgg() {
return new ItemStack(Material.DRAGON_EGG);
}
private void announce(String msg) {
Announcement.announce(msg, logger);
}
private void console_log(String message) {
logger.info(message);
}
}

View file

@ -1,25 +0,0 @@
package io.github.J0hnL0cke.egghunt.Controller;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
public class EggRespawn {
public static void spawnEggItem(Location loc, Configuration config, Data data){
ItemStack egg=new ItemStack(Material.DRAGON_EGG);
egg.setAmount(1);
Item drop=loc.getWorld().dropItem(loc, egg);
drop.setGravity(false);
drop.setGlowing(true);
drop.setVelocity(new Vector().setX(0).setY(0).setZ(0));
if (config.getEggInvincible()) {
drop.setInvulnerable(true);
}
data.updateEggLocation(drop);
}
}

View file

@ -15,6 +15,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
import io.github.J0hnL0cke.egghunt.Model.Egg;
public class EventScheduler extends BukkitRunnable {
@ -52,7 +53,7 @@ public class EventScheduler extends BukkitRunnable {
yPos = respawnLoc.getWorld().getMaxHeight() / 2;
}
respawnLoc.setY(yPos);
EggRespawn.spawnEggItem(respawnLoc, config, data);
Egg.spawnEggItem(respawnLoc, config, data); //do not need to update data with this location since item spawn event will be called
} else {
eggDestroyed();
respawnEgg(respawnLoc);

View file

@ -0,0 +1,312 @@
package io.github.J0hnL0cke.egghunt.Controller;
import java.util.logging.Logger;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Container;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.inventory.AbstractHorseInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
import io.github.J0hnL0cke.egghunt.Model.Egg;
/**
* Listens for Bukkit events related to inventories
*/
public class InventoryListener implements Listener {
private Logger logger;
private Configuration config;
private Data data;
public InventoryListener(Logger logger, Configuration config, Data data) {
this.logger = logger;
this.config = config;
this.data = data;
}
/**
* Track the player dropping the egg
* TODO see if this always overlaps with item spawn event (also check when standing over hopper, etc)
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemDrop(PlayerDropItemEvent event) {
Item item = event.getItemDrop();
ItemStack stack = item.getItemStack();
// Check if the dropped item is the egg
if (Egg.isEgg(stack)) {
data.setEggOwner(event.getPlayer());
data.updateEggLocation(item);
Egg.makeEggInvulnerable(event.getItemDrop(), config, logger);
}
}
/**
* Handle the egg being picked up by an entity
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPickupItem(EntityPickupItemEvent event) {
// Check if item picked up is an egg
if (Egg.isEgg(event.getItem())) {
data.updateEggLocation(event.getEntity());
if (event.getEntity() instanceof Player) {
data.setEggOwner((Player) event.getEntity());
}
}
}
/**
* Handle the egg being picked up by a container (hopper or hopper minecart)
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onHopperCollect(InventoryPickupItemEvent event) {
// Check if the dragon egg was picked up
ItemStack item = event.getItem().getItemStack();
if (Egg.isEgg(item)) {
//check if the inventory has open space
//TODO test this with edge cases for hopper pull/push
if (event.getInventory().firstEmpty() != -1 || event.getInventory().contains(Material.DRAGON_EGG)) {
data.updateEggLocation(event.getInventory());
}
}
}
/**
* When the player closes an inventory, check the player and the inventory for the egg.
* This removes the need to check specifics about a player's clicks in an inventory
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClose(InventoryCloseEvent event) {
Player player = (Player) event.getPlayer();
Inventory otherInv = event.getInventory();
//force an egg in the ender chest to be dropped if enabled in config and if the player is not in creative
if (otherInv.getType().equals(InventoryType.ENDER_CHEST)) {
if (config.getDropEnderchestedEgg() && player.getGameMode() != GameMode.CREATIVE) {
if (otherInv.contains(Material.DRAGON_EGG)) {
ItemStack egg = otherInv.getItem(otherInv.first(Material.DRAGON_EGG));
Location playerLoc = player.getLocation();
otherInv.remove(egg);
Item i = playerLoc.getWorld().dropItem(playerLoc, egg); //TODO use drop item function
console_log(String.format(
"Dropped the dragon egg on the ground since %s had it in their ender chest.",
player.getName()));
console_log(
"Set ignore_echest_egg to \"true\" in the config file to disable this feature.");
data.updateEggLocation(i);
}
}
//whether the egg is dropped or not, ignore all other checking
//since either egg should be dropped and location has already been updated
//or it should not move and this egg should be ignored entirely
return;
}
if (player.getInventory().contains(Material.DRAGON_EGG)) {
//if the player has the egg in their inventory, it will stay there
data.updateEggLocation(player);
data.setEggOwner(player);
} else if (otherInv.contains(Material.DRAGON_EGG)) {
if (otherInv.getType() != InventoryType.PLAYER) { //TODO check how this affects player viewing own inventory (egg on head/offhand?)
if (otherInv.getHolder() instanceof Container || otherInv instanceof AbstractHorseInventory) { //not instanceof entity- chest llama but not wandering trader
//this is a container (chest, furnace, hopper minecart, etc), so the egg will remain here when the inventory is closed
data.updateEggLocation(otherInv);
} else {
//this is not a container (anvil, crafting table, villager, etc), so it will move back to the player's inventory
//note- if the player's inventory is full, it will instead drop as an item, which will trigger the item drop event
data.updateEggLocation(player);
}
}
}
}
/**
* Update the egg location when it is moved between blocks/entities (hoppers, dispensers, hopper minecarts, chest boats, etc)
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryMove(InventoryMoveItemEvent event) {
//check if the item being moved is the egg
if (Egg.isEgg(event.getItem())) {
if (event.getDestination().firstEmpty() != -1 || event.getDestination().contains(Material.DRAGON_EGG)) {
data.updateEggLocation(event.getDestination());
}
}
}
/**
* Stop players from holding the egg in their cursor then dragging to drop it into an ender chest or shulker box.
*
* Note: Due to limitations with the API, this prevents dragging the egg when viewing an ender chest or shulker box,
* even if the egg is only dragged over slots in the player's inventory.
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryDragConsider(InventoryDragEvent event) {
InventoryType inv = event.getInventory().getType(); //this only gets the currently viewed ("top") inventory, which is not necessairly where the items are dragged in/over
if (event.getWhoClicked().getGameMode() != GameMode.CREATIVE) {
if (inv.equals(InventoryType.ENDER_CHEST) || inv.equals(InventoryType.SHULKER_BOX)) {
boolean holdEgg = Egg.isEgg(event.getOldCursor());
if (holdEgg) {
event.setCancelled(true);
console_log(String.format("Stopped %s from dragging egg while viewing shulker/ender chest",
event.getWhoClicked().getName()));
}
}
}
}
/**
* Stop players from storing the egg in an ender chest or shulker box.
* Also stops the player from putting the egg into a bundle regardless of open inventory.
* TODO refactor into multiple smaller listeners
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryMoveConsider(InventoryClickEvent event) {
InventoryType inv = event.getInventory().getType();
if (event.getWhoClicked().getGameMode() != GameMode.CREATIVE) {
if (inv.equals(InventoryType.ENDER_CHEST) || inv.equals(InventoryType.SHULKER_BOX)) {
boolean hoverEgg = Egg.isEgg(event.getCurrentItem());
boolean holdEgg = Egg.isEgg(event.getCursor());
Boolean clickedContainer = null;
if (event.getClickedInventory() != null) {
clickedContainer = event.getClickedInventory().equals(event.getInventory());
}
//if the other inventory is an ender chest or shulker box
if (hoverEgg || holdEgg) {
//clicked on the egg or holding the egg with the cursor
boolean cancel = false;
if (clickedContainer == null){
logger.info(event.getAction().toString());
} else if (clickedContainer) {
//player clicked the container
switch (event.getAction()) {
case COLLECT_TO_CURSOR:
case HOTBAR_MOVE_AND_READD:
case MOVE_TO_OTHER_INVENTORY:
case HOTBAR_SWAP:
if (hoverEgg) {
//the egg is on the current item so these are not allowed
cancel = true;
}
//if the current item is not an egg, allow this action
//(eg allow shift+clicking items out of the ender chest while cursor holding the egg)
break;
default:
cancel = true; //no interaction is allowed in this case
}
} else {
//player clicked on own inventory
//prevent any action that would move the egg into/from the ender chest (other than hotkey, which is prevented below)
switch (event.getAction()) {
case MOVE_TO_OTHER_INVENTORY:
if(hoverEgg){ //prevent only if hovering over the egg, not if holding it
cancel=true;
}
break;
case COLLECT_TO_CURSOR:
cancel = true; //cancel these actions
default:
break;
}
}
if (cancel) {
//if the item clicked was the egg
event.setCancelled(true);
console_log(String.format("Stopped %s from moving egg to shulker/ender chest",
event.getWhoClicked().getName()));
}
}
//don't allow hotkeying either
if (event.getClick().equals(ClickType.NUMBER_KEY)) {
ItemStack item = event.getWhoClicked().getInventory().getItem(event.getHotbarButton());
if (item != null) {
if (event.getClickedInventory().equals(event.getInventory())) {
//make sure the destination is the ender chest
//this allows hotkeying the egg around in the player's inventory
if (Egg.isEgg(item)) {
event.setCancelled(true);
console_log(String.format("Stopped %s from hotkeying egg to shulker/ender chest",
event.getWhoClicked().getName()));
}
}
}
}
}
//prevent using bundles on the egg in *any* inventory
if(event.getCurrentItem() != null){
if(event.getCursor()!=null){
ItemStack clicked=event.getCurrentItem();
ItemStack cursor=event.getCursor();
if ((Egg.isEgg(cursor) && clicked.getType() == Material.BUNDLE)
|| (Egg.isEgg(clicked) && cursor.getType() == Material.BUNDLE)) {
event.setCancelled(true);
console_log(String.format("Stopped %s from bundling the egg",
event.getWhoClicked().getName()));
}
}
}
}
}
/**
* Stop players from pushing the egg into a shulker using a hopper/hopper minecart
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onPushConsider(InventoryMoveItemEvent event) {
//nice try, but it won't work
if (event.getDestination().getType().equals(InventoryType.SHULKER_BOX)) {
if (Egg.isEgg(event.getItem())) {
event.setCancelled(true);
}
}
}
private void console_log(String message) {
logger.info(message);
}
}

View file

@ -0,0 +1,195 @@
package io.github.J0hnL0cke.egghunt.Controller;
import org.bukkit.Material;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.*;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
import io.github.J0hnL0cke.egghunt.Model.Egg;
import java.util.logging.Logger;
/**
* Listens to miscellaneous Bukkit events
*/
public class MiscListener implements Listener {
private Logger logger;
private Configuration config;
private Data data;
public MiscListener(Logger logger, Configuration config, Data data) {
this.logger = logger;
this.config = config;
this.data = data;
}
/**
* Save data when the server autosaves.
* Need to do this because a server crash could roll back the server data but not the plugin.
* In this case data loss is beneficial, because being in sync with server's reality is more important.
* TODO test this
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onAutosave(WorldSaveEvent event) {
//TODO: don't save data until an autosave happens
data.saveData();
}
/**
* Drop egg if a player logs off with it in their inventory.
* TODO check if item spawn and item drop events overlap, and check which can be replaced
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onLogoff(PlayerQuitEvent event) {
Player player = event.getPlayer();
// Check if the player has a dragon egg
if (player.getInventory().contains(Material.DRAGON_EGG)) {
// Set owner and remove
data.setEggOwner(player); //TODO is this necessary? player will likely already be owner
player.getInventory().remove(Material.DRAGON_EGG);
// Drop it on the floor and set its location
//TODO use drop egg method in EggRespawn
Item egg_drop = event.getPlayer().getWorld().dropItem(player.getLocation(),
new ItemStack(Material.DRAGON_EGG));
data.updateEggLocation(egg_drop);
}
}
/**
* Track the egg droping as an item.
* Note: No handler to check if the falling egg entity drops an item, so we have to check every item spawn
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onItemSpawn(ItemSpawnEvent event) {
// Check if the spawned item is the egg
Item item = event.getEntity();
if (Egg.isEgg(item)) {
data.updateEggLocation(item);
Egg.makeEggInvulnerable(event.getEntity(), config, logger);
}
}
/**
* Handle the egg being placed as a block
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlace (BlockPlaceEvent event) {
if (Egg.isEgg(event.getBlock())) {
data.updateEggLocation(event.getBlock());
data.setEggOwner(event.getPlayer());
}
}
/**
* Handle the egg being placed in an item frame
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInteract(PlayerInteractEntityEvent event) {
if (event.getRightClicked() instanceof ItemFrame) {
PlayerInventory player_inv = event.getPlayer().getInventory();
if (Egg.isEgg(player_inv.getItemInMainHand()) || Egg.isEgg(player_inv.getItemInOffHand())) {
data.updateEggLocation(event.getRightClicked());
data.setEggOwner(event.getPlayer());
}
}
}
/**
* Handle the egg teleporting
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSpread(BlockFromToEvent event) {
if (Egg.isEgg(event.getBlock())) {
data.updateEggLocation(event.getToBlock());
if (!config.getAccurateLocation()) {
//TODO disable accuracy here
console_log("The egg teleported, showing players the egg's location before teleport");
} else {
console_log("The egg teleported, showing players the egg's up-to-date location");
}
if (config.resetOwnerOnTeleport()) {
if (data.getEggOwner() != null) {
announce(String.format("The dragon egg has teleported. %s is no longer the owner.", data.getEggOwner().getName()));
data.resetEggOwner(false);
}
}
}
}
/**
* Handle the egg as a falling block entity
*/
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onFallingBlock(final EntityChangeBlockEvent event){
//check if this is dealing with a falling block, since EntityChangeBlockEvent is generic
if (event.getEntityType() == EntityType.FALLING_BLOCK) {
//if the falling block is the egg
if (Egg.isEgg((FallingBlock)event.getEntity())) {
console_log("Gravity event involving dragon egg occured");
if (event.getBlock().getType() == Material.AIR) {
//egg lands
data.updateEggLocation(event.getBlock());
} else if (event.getBlock().getType() == Material.DRAGON_EGG) {
//egg begins falling
data.updateEggLocation(event.getEntity());
}
}
}
}
//Other event handlers
/**
* Modify the player death message if they are holding the egg when they die
*/
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerDeath(PlayerDeathEvent event) {
if (!event.getKeepInventory() && event.getEntity().getInventory().contains(Material.DRAGON_EGG)) {
data.resetEggOwner(false);
//change the death message
String deathmsg = event.getDeathMessage();
if (deathmsg == null || deathmsg.isBlank()) {
announce(String.format("%s died and lost the dragon egg!", event.getEntity().getDisplayName()));
} else {
if (deathmsg.endsWith(".")) {
deathmsg = deathmsg.substring(0, deathmsg.length() - 1);
}
event.setDeathMessage(String.format("%s and lost the dragon egg!", deathmsg));
}
}
}
//Helper methods
private void announce(String msg) {
Announcement.announce(msg, logger);
}
private void console_log(String message) {
logger.info(message);
}
}

View file

@ -169,7 +169,7 @@ public class Data {
String.format("%s has claimed the dragon egg!", Bukkit.getOfflinePlayer(owner).getName()), logger);
Player p = Bukkit.getPlayer(playerUUID);
if (p != null) { //make sure player is online
Announcement.claimEggEffects(p);
Announcement.ShowEggClaimEffects(p);
}
}
}

View file

@ -0,0 +1,107 @@
package io.github.J0hnL0cke.egghunt.Model;
import java.util.logging.Logger;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
/**
* Provides methods related to the dragon egg
*/
public class Egg {
private static Material egg = Material.DRAGON_EGG;
/**
* Makes the given entity invulnerable if enabled in the config
*/
public static void makeEggInvulnerable(Entity entity, Configuration config, Logger logger) {
if (config.getEggInvincible()) {
entity.setInvulnerable(true);
logger.info("made drop invulnerable");
}
}
/**
* Spawns the dragon egg in the end world specified by the given config.
* @return The new egg block.
*/
public static Block respawnEgg(Configuration config) {
Block newEggLoc = config.getEndWorld().getEnderDragonBattle().getEndPortalLocation().add(0, 4, 0).getBlock();
newEggLoc.setType(Material.DRAGON_EGG);
return newEggLoc;
}
/**
* Spawns a new egg item at the given location, sets it to invincible if enabled in the given config.
* This should trigger the item drop event, so it should not be necessary to immediately update the data file with the returned item.
* @return the egg item that was spawned
*/
public static Item spawnEggItem(Location loc, Configuration config, Data data){
ItemStack egg=new ItemStack(Material.DRAGON_EGG);
egg.setAmount(1);
Item drop=loc.getWorld().dropItem(loc, egg);
drop.setGravity(false);
drop.setGlowing(true);
drop.setVelocity(new Vector().setX(0).setY(0).setZ(0));
if (config.getEggInvincible()) {
drop.setInvulnerable(true);
}
return drop;
}
/**
* Check if the given ItemStack is the dragon egg. Also returns false if the provided stack is null.
* @param stack ItemStack to check
* @return True if the stack material is a dragon egg, otherwise false
*/
public static boolean isEgg(ItemStack stack) {
if (stack == null) {
return false;
}
return stack.getType().equals(egg);
}
/**
* Check if the given Item is the dragon egg. Also returns false if the provided item is null.
* @param item Item to check
* @return True if the item material is a dragon egg, otherwise false
*/
public static boolean isEgg(Item item) {
if (item == null) {
return false;
}
return item.getItemStack().getType().equals(egg);
}
/**
* Check if the given Block is the dragon egg. Also returns false if the provided block is null.
* @param block Block to check
* @return True if the block material is a dragon egg, otherwise false
*/
public static boolean isEgg(Block block) {
if (block == null) {
return false;
}
return block.getType().equals(egg);
}
/**
* Check if the given FallingBlock is the dragon egg. Also returns false if the provided block is null.
* @param block FallingBlock to check
* @return True if the block material is a dragon egg, otherwise false
*/
public static boolean isEgg(FallingBlock block) {
if (block == null) {
return false;
}
return block.getBlockData().getMaterial().equals(egg);
}
}

View file

@ -4,12 +4,15 @@ import java.util.logging.Logger;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import io.github.J0hnL0cke.egghunt.Controller.CommandHandler;
import io.github.J0hnL0cke.egghunt.Controller.EggHuntListener;
import io.github.J0hnL0cke.egghunt.Controller.EggDestroyListener;
import io.github.J0hnL0cke.egghunt.Controller.MiscListener;
import io.github.J0hnL0cke.egghunt.Controller.EventScheduler;
import io.github.J0hnL0cke.egghunt.Controller.InventoryListener;
import io.github.J0hnL0cke.egghunt.Model.Configuration;
import io.github.J0hnL0cke.egghunt.Model.Data;
import io.github.J0hnL0cke.egghunt.Persistence.ConfigFileDAO;
@ -21,15 +24,13 @@ public final class egghunt extends JavaPlugin {
Data data;
CommandHandler commandHandler;
EventScheduler schedule;
EggHuntListener listener;
BukkitTask belowWorldTask;
Logger logger;
@Override
public void onEnable() {
logger = getLogger();
log("onEnable has been invoked, starting EggHunt.");
log("Enabling EggHunt...");
saveDefaultConfig();
//create model instances using dependency injection
@ -37,18 +38,24 @@ public final class egghunt extends JavaPlugin {
data = new Data(DataFileDAO.getDataDAO(this), getLogger());
//create controller instances
listener = new EggHuntListener(getLogger(), config, data);
schedule = new EventScheduler(config, data, logger);
MiscListener miscListener = new MiscListener(getLogger(), config, data);
InventoryListener inventoryListener = new InventoryListener(logger, config, data);
EggDestroyListener destroyListener = new EggDestroyListener(logger, config, data);
EventScheduler scheduler = new EventScheduler(config, data, logger);
commandHandler = new CommandHandler(data);
//register event handlers
log("registering event listeners.");
getServer().getPluginManager().registerEvents(listener, this);
log("Registering event listeners...");
PluginManager manager = getServer().getPluginManager();
manager.registerEvents(miscListener, this);
manager.registerEvents(inventoryListener, this);
manager.registerEvents(destroyListener, this);
//schedule tasks
//TODO: disable task when not in use
log("Scheduling below world task");
belowWorldTask = schedule.runTaskTimer(this, 20, 20);
log("Scheduling below world task...");
belowWorldTask = scheduler.runTaskTimer(this, 20, 20);
log("Done!");
}