2023-05-25 19:20:03 +02:00
package com.craftaro.ultimatestacker.listeners ;
2023-06-30 22:28:37 +02:00
import com.craftaro.core.compatibility.CompatibleHand ;
import com.craftaro.core.hooks.ProtectionManager ;
2024-01-07 12:16:27 +01:00
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial ;
2023-06-30 22:28:37 +02:00
import com.craftaro.core.third_party.de.tr7zw.nbtapi.NBTItem ;
2023-05-25 19:20:03 +02:00
import com.craftaro.ultimatestacker.UltimateStacker ;
2023-06-30 22:27:08 +02:00
import com.craftaro.ultimatestacker.api.UltimateStackerApi ;
2023-05-30 11:21:46 +02:00
import com.craftaro.ultimatestacker.api.events.spawner.SpawnerBreakEvent ;
import com.craftaro.ultimatestacker.api.events.spawner.SpawnerPlaceEvent ;
2023-05-25 19:20:03 +02:00
import com.craftaro.ultimatestacker.api.stack.block.BlockStack ;
import com.craftaro.ultimatestacker.api.stack.block.BlockStackManager ;
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack ;
import com.craftaro.ultimatestacker.settings.Settings ;
import com.craftaro.ultimatestacker.stackable.spawner.SpawnerStackImpl ;
import com.craftaro.ultimatestacker.utils.Methods ;
2018-11-06 04:33:10 +01:00
import org.apache.commons.lang.math.NumberUtils ;
import org.bukkit.Bukkit ;
2020-08-25 01:01:11 +02:00
import org.bukkit.GameMode ;
2023-04-07 18:58:21 +02:00
import org.bukkit.Material ;
2018-11-06 04:33:10 +01:00
import org.bukkit.block.Block ;
import org.bukkit.block.CreatureSpawner ;
import org.bukkit.enchantments.Enchantment ;
import org.bukkit.entity.EntityType ;
import org.bukkit.entity.Player ;
2023-03-29 21:21:00 +02:00
import org.bukkit.event.Event ;
2018-11-06 04:33:10 +01:00
import org.bukkit.event.EventHandler ;
import org.bukkit.event.EventPriority ;
import org.bukkit.event.Listener ;
import org.bukkit.event.block.Action ;
import org.bukkit.event.block.BlockBreakEvent ;
import org.bukkit.event.block.BlockPlaceEvent ;
import org.bukkit.event.player.PlayerInteractEvent ;
import org.bukkit.inventory.ItemStack ;
import org.bukkit.inventory.meta.BlockStateMeta ;
2019-04-11 08:54:59 +02:00
import java.util.List ;
2023-06-29 11:18:18 +02:00
import java.util.Optional ;
2019-04-11 08:54:59 +02:00
2018-11-06 04:33:10 +01:00
public class BlockListeners implements Listener {
2019-08-02 15:59:10 +02:00
private final UltimateStacker plugin ;
2018-11-06 04:33:10 +01:00
2019-08-02 15:59:10 +02:00
public BlockListeners ( UltimateStacker plugin ) {
this . plugin = plugin ;
2018-11-06 04:33:10 +01:00
}
2023-03-29 21:21:00 +02:00
@EventHandler ( priority = EventPriority . HIGHEST )
2020-08-25 01:01:11 +02:00
public void onBlockInteract ( PlayerInteractEvent event ) {
2023-03-29 21:21:00 +02:00
if ( event . useInteractedBlock ( ) = = Event . Result . DENY ) return ;
2018-11-06 04:33:10 +01:00
Block block = event . getClickedBlock ( ) ;
Player player = event . getPlayer ( ) ;
2023-04-01 15:55:37 +02:00
if ( block = = null ) return ;
if ( ! ProtectionManager . canInteract ( player , block . getLocation ( ) ) | | ! ProtectionManager . canBreak ( player , block . getLocation ( ) ) ) {
if ( ! player . isOp ( ) ) {
return ;
}
}
2020-09-09 20:35:24 +02:00
CompatibleHand hand = CompatibleHand . getHand ( event ) ;
ItemStack inHand = hand . getItem ( player ) ;
2023-04-07 18:58:21 +02:00
boolean isSneaking = player . isSneaking ( ) ;
Action clickAction = event . getAction ( ) ;
int inHandAmount = inHand . getAmount ( ) ;
2018-11-06 04:33:10 +01:00
2023-04-07 18:58:21 +02:00
//Stacking blocks
if ( Settings . STACK_BLOCKS . getBoolean ( )
& & Settings . STACKABLE_BLOCKS . getStringList ( ) . contains ( block . getType ( ) . name ( ) ) //Is block stackable
2023-06-29 11:18:18 +02:00
& & ! block . getType ( ) . equals ( XMaterial . SPAWNER . parseMaterial ( ) ) //Don't stack spawners here
2024-01-07 12:22:37 +01:00
) {
2020-08-25 01:01:11 +02:00
2023-06-29 11:18:18 +02:00
Optional < XMaterial > xBlockType = XMaterial . matchXMaterial ( block . getType ( ) . name ( ) ) ;
if ( ! xBlockType . isPresent ( ) ) return ;
XMaterial blockType = xBlockType . get ( ) ;
2020-08-25 01:01:11 +02:00
2023-04-07 18:58:21 +02:00
BlockStackManager blockStackManager = plugin . getBlockStackManager ( ) ;
boolean isStacked = blockStackManager . isBlock ( block . getLocation ( ) ) ;
BlockStack stack = blockStackManager . getBlock ( block . getLocation ( ) ) ;
//Modify stack
if ( isStacked ) {
event . setCancelled ( true ) ;
//Add to stack
2024-01-07 14:52:51 +01:00
if ( clickAction = = Action . RIGHT_CLICK_BLOCK & & ! player . hasPermission ( " ultimatestacker.block.nostack " ) ) {
2023-04-07 18:58:21 +02:00
if ( inHand . getType ( ) . equals ( Material . AIR ) ) return ;
2023-06-29 11:18:18 +02:00
if ( ! blockType . equals ( XMaterial . matchXMaterial ( inHand ) ) ) return ;
2023-04-07 18:58:21 +02:00
//Add all held items to stack
if ( Settings . ALWAYS_ADD_ALL . getBoolean ( ) | | isSneaking ) {
stack . add ( inHandAmount ) ;
if ( player . getGameMode ( ) ! = GameMode . CREATIVE ) {
hand . takeItem ( player , inHandAmount ) ;
}
} else {
//Add one held item to stack
stack . add ( 1 ) ;
if ( player . getGameMode ( ) ! = GameMode . CREATIVE ) {
hand . takeItem ( player , 1 ) ;
}
2020-08-25 01:01:11 +02:00
}
2023-04-07 18:58:21 +02:00
}
//Remove from stack
if ( clickAction = = Action . LEFT_CLICK_BLOCK ) {
if ( isSneaking ) {
//Remove all items from stack
int amountToRemove = Math . min ( Settings . MAX_REMOVEABLE . getInt ( ) , stack . getAmount ( ) ) ;
2023-06-29 11:18:18 +02:00
ItemStack removed = stack . getMaterial ( ) . parseItem ( ) ;
2023-04-07 18:58:21 +02:00
removed . setAmount ( amountToRemove ) ;
stack . take ( amountToRemove ) ;
2020-08-25 01:01:11 +02:00
if ( Settings . ADD_TO_INVENTORY . getBoolean ( ) ) {
2023-04-07 18:58:21 +02:00
player . getInventory ( ) . addItem ( removed ) ;
2020-08-25 01:01:11 +02:00
} else {
2023-04-07 18:58:21 +02:00
player . getWorld ( ) . dropItemNaturally ( block . getLocation ( ) , removed ) ;
2020-08-25 01:01:11 +02:00
}
2023-04-07 18:58:21 +02:00
} else {
//Remove one item from stack
stack . take ( 1 ) ;
2023-04-05 11:57:17 +02:00
if ( Settings . ADD_TO_INVENTORY . getBoolean ( ) ) {
2023-06-29 11:18:18 +02:00
player . getInventory ( ) . addItem ( stack . getMaterial ( ) . parseItem ( ) ) ;
2023-04-05 11:57:17 +02:00
} else {
2023-06-29 11:18:18 +02:00
player . getWorld ( ) . dropItemNaturally ( block . getLocation ( ) , stack . getMaterial ( ) . parseItem ( ) ) ;
2023-04-05 11:57:17 +02:00
}
2023-04-07 18:58:21 +02:00
}
if ( stack . getAmount ( ) = = 0 ) {
//Remove stack
stack . destroy ( ) ;
return ;
2020-08-25 01:01:11 +02:00
}
}
2023-04-07 18:58:21 +02:00
//update hologram
plugin . updateHologram ( stack ) ;
2023-06-05 16:25:37 +02:00
plugin . getPluginDataManager ( ) . save ( stack ) ;
2023-04-07 18:58:21 +02:00
return ;
} else {
2024-01-07 14:52:51 +01:00
if ( isSneaking | | player . hasPermission ( " ultimatestacker.block.nostack " ) ) return ;
2023-04-07 18:58:21 +02:00
//Check if player clicked the same type as the clicked block
if ( inHand . getType ( ) . equals ( Material . AIR ) ) return ;
2023-06-29 11:18:18 +02:00
if ( ! blockType . equals ( XMaterial . matchXMaterial ( inHand ) ) ) return ;
2023-04-07 18:58:21 +02:00
if ( clickAction ! = Action . RIGHT_CLICK_BLOCK ) return ;
//Create new stack
event . setCancelled ( true ) ;
2023-04-10 17:17:44 +02:00
if ( player . getGameMode ( ) ! = GameMode . CREATIVE ) {
hand . takeItem ( player , 1 ) ;
}
2023-04-07 18:58:21 +02:00
BlockStack newStack = blockStackManager . createBlock ( block ) ;
2023-06-05 16:25:37 +02:00
plugin . getPluginDataManager ( ) . save ( newStack ) ;
2023-04-07 18:58:21 +02:00
plugin . updateHologram ( newStack ) ;
2020-08-25 01:01:11 +02:00
}
2023-04-07 18:58:21 +02:00
return ;
2020-08-25 01:01:11 +02:00
}
2023-04-07 18:58:21 +02:00
//Stacking spawners
2023-06-29 11:18:18 +02:00
if ( block . getType ( ) ! = XMaterial . SPAWNER . parseMaterial ( )
| | inHand . getType ( ) ! = XMaterial . SPAWNER . parseMaterial ( )
2024-01-07 14:52:51 +01:00
| | event . getAction ( ) = = Action . LEFT_CLICK_BLOCK ) return ;
2018-11-06 04:33:10 +01:00
2019-09-07 23:55:16 +02:00
List < String > disabledWorlds = Settings . DISABLED_WORLDS . getStringList ( ) ;
2020-08-25 01:01:11 +02:00
if ( disabledWorlds . stream ( ) . anyMatch ( worldStr - > event . getPlayer ( ) . getWorld ( ) . getName ( ) . equalsIgnoreCase ( worldStr ) ) )
return ;
2019-04-11 08:54:59 +02:00
2019-08-02 15:59:10 +02:00
if ( ! plugin . spawnersEnabled ( ) ) return ;
2018-11-06 04:33:10 +01:00
2020-09-09 20:35:24 +02:00
BlockStateMeta bsm = ( BlockStateMeta ) inHand . getItemMeta ( ) ;
2018-11-06 04:33:10 +01:00
CreatureSpawner cs = ( CreatureSpawner ) bsm . getBlockState ( ) ;
EntityType itemType = cs . getSpawnedType ( ) ;
2020-09-09 20:35:24 +02:00
int itemAmount = getSpawnerAmount ( inHand ) ;
2019-09-03 22:38:00 +02:00
int specific = plugin . getSpawnerFile ( ) . getInt ( " Spawners. " + cs . getSpawnedType ( ) . name ( ) + " .Max Stack Size " ) ;
2019-09-07 23:55:16 +02:00
int maxStackSize = specific = = - 1 ? Settings . MAX_STACK_SPAWNERS . getInt ( ) : specific ;
2018-11-06 04:33:10 +01:00
2018-11-06 06:09:40 +01:00
cs = ( CreatureSpawner ) block . getState ( ) ;
2018-11-06 04:33:10 +01:00
EntityType blockType = cs . getSpawnedType ( ) ;
event . setCancelled ( true ) ;
if ( itemType = = blockType ) {
2023-06-30 22:27:08 +02:00
SpawnerStack stack = UltimateStackerApi . getSpawnerStackManager ( ) . getSpawner ( block ) ;
2023-09-18 15:34:19 +02:00
if ( stack = = null ) return ;
2024-03-23 19:17:44 +01:00
if ( player . isSneaking ( ) ) {
//Add all to stack from hand
if ( Settings . SNEAK_TO_ADD_ALL . getBoolean ( ) ) {
//Redo this logic, if we have 10 items in hand and each item is 5 stack size, we need to take into consideration that what happens if we can only add 2 stack total in a stack? We have to remove one extra item and add one spawner with 3 stack back
int amountToAdd = Math . min ( maxStackSize - stack . getAmount ( ) , itemAmount * inHand . getAmount ( ) ) ; //Multiply by inHand.getAmount() to get the total amount of items in hand
int remaining = itemAmount * inHand . getAmount ( ) - amountToAdd ; //Calculate the remaining amount of items in hand
stack . setAmount ( stack . getAmount ( ) + amountToAdd ) ;
plugin . updateHologram ( stack ) ;
plugin . getDataManager ( ) . save ( stack ) ;
if ( remaining % itemAmount = = 0 ) { //We don't have to worry about leftovers
if ( player . getGameMode ( ) ! = GameMode . CREATIVE ) {
hand . takeItem ( player , amountToAdd / itemAmount ) ;
}
} else {
int fullStacks = amountToAdd / itemAmount ;
int overflow = remaining % itemAmount ;
//remove fullstacks-1 and add back overflow as a new item stack
if ( player . getGameMode ( ) ! = GameMode . CREATIVE ) {
if ( overflow > 0 ) {
hand . takeItem ( player , fullStacks + 1 ) ;
ItemStack overflowItem = Methods . getSpawnerItem ( blockType , overflow ) ;
if ( player . getInventory ( ) . firstEmpty ( ) = = - 1 ) {
block . getWorld ( ) . dropItemNaturally ( block . getLocation ( ) . add ( . 5 , 0 , . 5 ) , overflowItem ) ;
} else {
player . getInventory ( ) . addItem ( overflowItem ) ;
}
} else {
hand . takeItem ( player , fullStacks ) ;
}
}
}
}
return ;
}
2024-03-14 22:06:40 +01:00
if ( player . hasPermission ( " ultimatestacker.spawner.nostack " ) & & ! player . isOp ( ) ) {
2024-01-07 14:52:51 +01:00
event . setCancelled ( false ) ;
return ;
}
2018-11-06 04:33:10 +01:00
if ( event . getAction ( ) = = Action . RIGHT_CLICK_BLOCK ) {
if ( stack . getAmount ( ) = = maxStackSize ) return ;
2019-06-05 11:40:36 +02:00
ItemStack overflowItem = null ;
2018-11-06 04:33:10 +01:00
if ( ( stack . getAmount ( ) + itemAmount ) > maxStackSize ) {
2019-06-05 11:40:36 +02:00
overflowItem = Methods . getSpawnerItem ( blockType , ( stack . getAmount ( ) + itemAmount ) - maxStackSize ) ;
itemAmount = maxStackSize - stack . getAmount ( ) ;
}
SpawnerPlaceEvent placeEvent = new SpawnerPlaceEvent ( player , block , blockType , itemAmount ) ;
Bukkit . getPluginManager ( ) . callEvent ( placeEvent ) ;
if ( placeEvent . isCancelled ( ) ) {
event . setCancelled ( true ) ;
return ;
}
if ( overflowItem ! = null ) {
2018-11-06 04:33:10 +01:00
if ( player . getInventory ( ) . firstEmpty ( ) = = - 1 )
2019-10-05 17:56:30 +02:00
block . getWorld ( ) . dropItemNaturally ( block . getLocation ( ) . add ( . 5 , 0 , . 5 ) , overflowItem ) ;
2018-11-06 04:33:10 +01:00
else
2019-06-05 11:40:36 +02:00
player . getInventory ( ) . addItem ( overflowItem ) ;
2018-11-06 04:33:10 +01:00
}
stack . setAmount ( stack . getAmount ( ) + itemAmount ) ;
2019-09-03 22:38:00 +02:00
plugin . updateHologram ( stack ) ;
2023-09-18 15:34:19 +02:00
plugin . getDataManager ( ) . save ( stack ) ;
2021-05-21 22:52:33 +02:00
if ( player . getGameMode ( ) ! = GameMode . CREATIVE )
hand . takeItem ( player ) ;
2018-11-06 04:33:10 +01:00
}
}
}
2023-03-29 21:21:00 +02:00
@EventHandler ( priority = EventPriority . HIGHEST )
2020-08-25 01:01:11 +02:00
public void onBlockPlace ( BlockPlaceEvent event ) {
2023-03-29 21:21:00 +02:00
if ( event . isCancelled ( ) ) return ;
2018-11-06 04:33:10 +01:00
Block block = event . getBlock ( ) ;
2019-06-05 11:40:36 +02:00
Player player = event . getPlayer ( ) ;
2018-11-06 04:33:10 +01:00
2023-06-29 11:18:18 +02:00
if ( block . getType ( ) ! = XMaterial . SPAWNER . parseMaterial ( )
2020-08-25 01:01:11 +02:00
| | ! ( block . getState ( ) instanceof CreatureSpawner ) // Needed for a DataPack
| | ! plugin . spawnersEnabled ( ) )
return ;
2019-06-05 11:40:36 +02:00
2020-08-25 01:01:11 +02:00
CreatureSpawner cs = ( CreatureSpawner ) block . getState ( ) ;
CreatureSpawner cs2 = ( CreatureSpawner ) ( ( BlockStateMeta ) event . getItemInHand ( ) . getItemMeta ( ) ) . getBlockState ( ) ;
int amount = getSpawnerAmount ( event . getItemInHand ( ) ) ;
2019-01-15 07:53:01 +01:00
2020-08-25 01:01:11 +02:00
SpawnerPlaceEvent placeEvent = new SpawnerPlaceEvent ( player , block , cs2 . getSpawnedType ( ) , amount ) ;
Bukkit . getPluginManager ( ) . callEvent ( placeEvent ) ;
if ( placeEvent . isCancelled ( ) ) {
event . setCancelled ( true ) ;
return ;
2019-01-01 00:41:02 +01:00
}
2018-11-06 04:33:10 +01:00
2023-06-30 22:27:08 +02:00
SpawnerStack stack = UltimateStackerApi . getSpawnerStackManager ( ) . addSpawner ( new SpawnerStackImpl ( block . getLocation ( ) , amount ) ) ;
2023-09-18 15:34:19 +02:00
plugin . getSpawnerStackManager ( ) . addSpawner ( stack ) ;
2023-06-05 16:25:37 +02:00
plugin . getPluginDataManager ( ) . save ( stack ) ;
2020-08-25 01:01:11 +02:00
cs . setSpawnedType ( cs2 . getSpawnedType ( ) ) ;
cs . update ( ) ;
plugin . updateHologram ( stack ) ;
2018-11-06 04:33:10 +01:00
}
2023-03-29 21:21:00 +02:00
@EventHandler ( priority = EventPriority . HIGHEST )
2018-11-06 04:33:10 +01:00
public void onBlockBreak ( BlockBreakEvent event ) {
2023-03-29 21:21:00 +02:00
if ( event . isCancelled ( ) ) return ;
2018-11-06 04:33:10 +01:00
Block block = event . getBlock ( ) ;
2023-06-29 11:18:18 +02:00
if ( block . getType ( ) ! = XMaterial . SPAWNER . parseMaterial ( ) ) return ;
2018-11-06 04:33:10 +01:00
2019-08-02 15:59:10 +02:00
if ( ! plugin . spawnersEnabled ( ) ) return ;
2019-02-17 22:55:42 +01:00
event . setExpToDrop ( 0 ) ;
2018-11-06 04:33:10 +01:00
2018-11-06 06:09:40 +01:00
CreatureSpawner cs = ( CreatureSpawner ) block . getState ( ) ;
2018-11-06 04:33:10 +01:00
2024-03-20 12:36:33 +01:00
EntityType spawnedEntityType = cs . getSpawnedType ( ) ;
//Empty spawners return null?? It is annotated as @NotNull
if ( spawnedEntityType = = null ) return ;
2018-11-06 04:33:10 +01:00
Player player = event . getPlayer ( ) ;
2018-11-06 05:41:58 +01:00
ItemStack item = player . getInventory ( ) . getItemInHand ( ) ;
2018-11-06 04:33:10 +01:00
2023-06-30 22:27:08 +02:00
SpawnerStack stack = UltimateStackerApi . getSpawnerStackManager ( ) . getSpawner ( block ) ;
2024-03-23 19:17:44 +01:00
if ( stack = = null ) return ;
2018-11-06 04:33:10 +01:00
event . setCancelled ( true ) ;
int amt = 1 ;
2019-06-05 11:40:36 +02:00
boolean remove = false ;
2018-11-06 04:33:10 +01:00
2019-09-07 23:55:16 +02:00
if ( player . isSneaking ( ) & & Settings . SNEAK_FOR_STACK . getBoolean ( ) ) {
2018-11-06 04:33:10 +01:00
amt = stack . getAmount ( ) ;
2019-06-05 11:40:36 +02:00
remove = true ;
} else if ( stack . getAmount ( ) < = 1 ) {
remove = true ;
}
2024-03-20 12:36:33 +01:00
SpawnerBreakEvent breakEvent = new SpawnerBreakEvent ( player , block , spawnedEntityType , amt ) ;
2019-06-05 11:40:36 +02:00
Bukkit . getPluginManager ( ) . callEvent ( breakEvent ) ;
if ( breakEvent . isCancelled ( ) )
return ;
if ( remove ) {
event . setCancelled ( false ) ;
2020-08-25 01:01:11 +02:00
plugin . removeHologram ( stack ) ;
2023-06-30 22:27:08 +02:00
SpawnerStack spawnerStack = UltimateStackerApi . getSpawnerStackManager ( ) . removeSpawner ( block . getLocation ( ) ) ;
2023-06-05 16:25:37 +02:00
plugin . getPluginDataManager ( ) . delete ( spawnerStack ) ;
2018-11-06 04:33:10 +01:00
} else {
2019-06-05 11:40:36 +02:00
stack . setAmount ( stack . getAmount ( ) - 1 ) ;
2023-09-18 15:34:19 +02:00
plugin . getDataManager ( ) . save ( stack ) ;
2019-09-03 22:38:00 +02:00
plugin . updateHologram ( stack ) ;
2018-11-06 04:33:10 +01:00
}
2019-06-05 11:40:36 +02:00
2019-10-05 17:56:30 +02:00
if ( player . hasPermission ( " ultimatestacker.spawner.nosilkdrop " ) | | item . getEnchantments ( ) . containsKey ( Enchantment . SILK_TOUCH ) & & player . hasPermission ( " ultimatestacker.spawner.silktouch " ) ) {
2024-03-20 12:36:33 +01:00
ItemStack spawner = Methods . getSpawnerItem ( spawnedEntityType , amt ) ;
2019-10-05 17:56:30 +02:00
if ( player . getInventory ( ) . firstEmpty ( ) = = - 1 | | ! Settings . SPAWNERS_TO_INVENTORY . getBoolean ( ) )
block . getWorld ( ) . dropItemNaturally ( block . getLocation ( ) . add ( . 5 , 0 , . 5 ) , spawner ) ;
else
player . getInventory ( ) . addItem ( spawner ) ;
}
2018-11-06 04:33:10 +01:00
}
2018-11-06 05:53:27 +01:00
private int getSpawnerAmount ( ItemStack item ) {
2022-03-18 21:38:26 +01:00
NBTItem nbtItem = new NBTItem ( item ) ;
if ( nbtItem . hasKey ( " spawner_stack_size " ) )
return nbtItem . getInteger ( " spawner_stack_size " ) ;
2018-11-06 04:33:10 +01:00
if ( ! item . hasItemMeta ( ) | | ! item . getItemMeta ( ) . hasDisplayName ( ) ) return 1 ;
if ( item . getItemMeta ( ) . getDisplayName ( ) . contains ( " : " ) ) {
2019-06-27 20:34:33 +02:00
int amt = NumberUtils . toInt ( item . getItemMeta ( ) . getDisplayName ( ) . replace ( " \ u00A7 " , " " ) . replace ( " ; " , " " ) . split ( " : " ) [ 0 ] , 1 ) ;
2018-11-06 05:53:27 +01:00
return amt = = 0 ? 1 : amt ;
2018-11-06 04:33:10 +01:00
}
return 1 ;
}
}