1
1
package com.noxcrew.interfaces
2
2
3
+ import com.destroystokyo.paper.MaterialSetTag
4
+ import com.destroystokyo.paper.MaterialTags
3
5
import com.github.benmanes.caffeine.cache.Cache
4
6
import com.github.benmanes.caffeine.cache.Caffeine
5
7
import com.noxcrew.interfaces.Constants.SCOPE
@@ -16,9 +18,11 @@ import io.papermc.paper.event.player.AsyncChatEvent
16
18
import kotlinx.coroutines.launch
17
19
import net.kyori.adventure.text.Component
18
20
import org.bukkit.Bukkit
21
+ import org.bukkit.Material
22
+ import org.bukkit.NamespacedKey
23
+ import org.bukkit.block.Block
19
24
import org.bukkit.entity.HumanEntity
20
25
import org.bukkit.entity.Player
21
- import org.bukkit.event.Cancellable
22
26
import org.bukkit.event.Event
23
27
import org.bukkit.event.EventHandler
24
28
import org.bukkit.event.EventPriority
@@ -69,6 +73,60 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
69
73
Reason .UNKNOWN ,
70
74
Reason .PLUGIN
71
75
)
76
+
77
+ /* * An incomplete set of blocks that have some interaction when clicked on. */
78
+ private val CLICKABLE_BLOCKS : MaterialSetTag =
79
+ MaterialSetTag (NamespacedKey (" interfaces" , " clickable-blocks" ))
80
+ .add(
81
+ MaterialTags .WOODEN_DOORS ,
82
+ MaterialTags .WOODEN_TRAPDOORS ,
83
+ MaterialTags .FENCE_GATES ,
84
+ MaterialSetTag .BUTTONS ,
85
+ )
86
+ // Add blocks with inventories
87
+ .add(
88
+ Material .CHEST ,
89
+ Material .ENDER_CHEST ,
90
+ Material .TRAPPED_CHEST ,
91
+ Material .BARREL ,
92
+ Material .FURNACE ,
93
+ Material .BLAST_FURNACE ,
94
+ Material .SMOKER ,
95
+ Material .CRAFTING_TABLE ,
96
+ Material .LOOM ,
97
+ Material .CARTOGRAPHY_TABLE ,
98
+ Material .ENCHANTING_TABLE ,
99
+ Material .SMITHING_TABLE ,
100
+ )
101
+ .add(Material .LEVER )
102
+ .add(Material .CAKE )
103
+ // Add copper doors & trapdoors as they do not have their own tags
104
+ .add(
105
+ Material .COPPER_DOOR ,
106
+ Material .EXPOSED_COPPER_DOOR ,
107
+ Material .WEATHERED_COPPER_DOOR ,
108
+ Material .OXIDIZED_COPPER_DOOR ,
109
+ )
110
+ .add(
111
+ Material .WAXED_COPPER_DOOR ,
112
+ Material .WAXED_EXPOSED_COPPER_DOOR ,
113
+ Material .WAXED_WEATHERED_COPPER_DOOR ,
114
+ Material .WAXED_OXIDIZED_COPPER_DOOR ,
115
+ )
116
+ .add(
117
+ Material .COPPER_TRAPDOOR ,
118
+ Material .EXPOSED_COPPER_TRAPDOOR ,
119
+ Material .WEATHERED_COPPER_TRAPDOOR ,
120
+ Material .OXIDIZED_COPPER_TRAPDOOR ,
121
+ )
122
+ .add(
123
+ Material .WAXED_COPPER_TRAPDOOR ,
124
+ Material .WAXED_EXPOSED_COPPER_TRAPDOOR ,
125
+ Material .WAXED_WEATHERED_COPPER_TRAPDOOR ,
126
+ Material .WAXED_OXIDIZED_COPPER_TRAPDOOR ,
127
+ )
128
+ // You can click signs to edit them
129
+ .add(MaterialTags .SIGNS )
72
130
}
73
131
74
132
/* * Stores data for a single chat query. */
@@ -183,7 +241,11 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
183
241
val view = convertHolderToInterfaceView(holder) ? : return
184
242
val clickedPoint = clickedPoint(view, event) ? : return
185
243
val isPlayerInventory = (event.clickedInventory ? : event.inventory).holder is Player
186
- handleClick(view, clickedPoint, event.click, event, event.hotbarButton, isPlayerInventory)
244
+
245
+ // Run base click handling
246
+ if (handleClick(view, clickedPoint, event.click, event.hotbarButton, isPlayerInventory)) {
247
+ event.isCancelled = true
248
+ }
187
249
188
250
// If the event is not cancelled we add extra prevention checks if any of the involved
189
251
// slots are not allowed to be modified!
@@ -263,6 +325,10 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
263
325
setOpenInterface(event.player.uniqueId, null )
264
326
}
265
327
328
+ /* * Returns whether [block] will trigger some interaction if clicked with [item]. */
329
+ private fun hasInteraction (block : Block , item : ItemStack ): Boolean =
330
+ CLICKABLE_BLOCKS .isTagged(block)
331
+
266
332
@EventHandler(priority = EventPriority .LOW )
267
333
public fun onInteract (event : PlayerInteractEvent ) {
268
334
if (event.action == Action .PHYSICAL ) return
@@ -271,6 +337,13 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
271
337
val player = event.player
272
338
val view = getOpenInterface(player.uniqueId) ? : return
273
339
340
+ // If we are prioritizing block interactions we assure they are not happening first
341
+ if (view.builder.prioritiseBlockInteractions) {
342
+ // This is a bit messy because Bukkit doesn't cleanly give access to the block interactions. If you are
343
+ // using this setting feel free to PR more logic into this method.
344
+ if (event.clickedBlock != null && hasInteraction(event.clickedBlock!! , event.item ? : ItemStack .empty())) return
345
+ }
346
+
274
347
val clickedPoint = view.backing.relativizePlayerInventorySlot(
275
348
if (event.hand == EquipmentSlot .HAND ) {
276
349
GridPoint .at(3 , player.inventory.heldItemSlot)
@@ -289,7 +362,14 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
289
362
return
290
363
}
291
364
292
- handleClick(view, clickedPoint, click, event, - 1 , true )
365
+ if (handleClick(view, clickedPoint, click, - 1 , true )) {
366
+ // Support modern behavior where we don't interfere with block interactions
367
+ if (view.builder.onlyCancelItemInteraction) {
368
+ event.setUseItemInHand(Event .Result .DENY )
369
+ } else {
370
+ event.isCancelled = true
371
+ }
372
+ }
293
373
}
294
374
295
375
@EventHandler(priority = EventPriority .LOW , ignoreCancelled = true )
@@ -412,25 +492,23 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
412
492
view : AbstractInterfaceView <* , * , * >,
413
493
clickedPoint : GridPoint ,
414
494
click : ClickType ,
415
- event : Cancellable ,
416
495
slot : Int ,
417
496
isPlayerInventory : Boolean
418
- ) {
497
+ ): Boolean {
419
498
// Determine the type of click, if nothing was clicked we allow it
420
499
val raw = view.pane.getRaw(clickedPoint)
421
500
422
501
// Optionally cancel clicking on other slots
423
502
if (raw == null ) {
424
503
if (view.builder.preventClickingEmptySlots && ! (view.builder.allowClickingOwnInventoryIfClickingEmptySlotsIsPrevented && isPlayerInventory)) {
425
- event.isCancelled = true
504
+ return true
426
505
}
427
- return
506
+ return false
428
507
}
429
508
430
509
// Automatically cancel if throttling or already processing
431
510
if (view.isProcessingClick || shouldThrottle(view.player)) {
432
- event.isCancelled = true
433
- return
511
+ return true
434
512
}
435
513
436
514
// Only allow one click to be processed at the same time
@@ -464,8 +542,9 @@ public class InterfacesListeners private constructor(private val plugin: Plugin)
464
542
465
543
// Update the cancellation state of the event
466
544
if (completedClickHandler.cancelled) {
467
- event.isCancelled = true
545
+ return true
468
546
}
547
+ return false
469
548
}
470
549
471
550
/* * Converts a bukkit [action] to a [ClickType]. */
0 commit comments