1+ package io.github.pylonmc.rebar.block.base
2+
3+ import io.github.pylonmc.rebar.Rebar
4+ import io.github.pylonmc.rebar.block.BlockListener
5+ import io.github.pylonmc.rebar.block.BlockListener.logEventHandleErr
6+ import io.github.pylonmc.rebar.block.BlockStorage
7+ import io.github.pylonmc.rebar.block.RebarBlock
8+ import io.github.pylonmc.rebar.block.context.BlockCreateContext
9+ import io.github.pylonmc.rebar.event.api.MultiListener
10+ import io.github.pylonmc.rebar.event.api.annotation.MultiHandlers
11+ import io.github.pylonmc.rebar.event.api.annotation.UniversalHandler
12+ import org.bukkit.Bukkit
13+ import org.bukkit.Material
14+ import org.bukkit.block.Block
15+ import org.bukkit.event.EventHandler
16+ import org.bukkit.event.EventPriority
17+ import org.bukkit.event.block.BlockBurnEvent
18+ import org.bukkit.event.block.BlockIgniteEvent
19+ import org.bukkit.event.block.BlockSpreadEvent
20+ import org.bukkit.event.entity.EntityDamageEvent
21+ import org.jetbrains.annotations.ApiStatus
22+
23+ @Suppress(" unused" )
24+ interface RebarFire {
25+ fun onDamageEntity (event : EntityDamageEvent , priority : EventPriority ) {}
26+
27+ /* *
28+ * Called when this fire block ignites block
29+ * Spawns copies of this fire block itself after calling, if the event is not cancelled
30+ */
31+ fun onIgniteBlock (event : BlockIgniteEvent , priority : EventPriority ) {}
32+
33+ /* *
34+ * Spawns copies of this fire block itself after calling, if the event is not cancelled
35+ */
36+ fun onFireSpread (event : BlockSpreadEvent , priority : EventPriority ) {}
37+
38+ /* *
39+ * Spawns copies of this fire block itself if returns true, otherwise set the block to air.
40+ *
41+ * @see Companion.onFireEatBlock
42+ */
43+ fun onFireEatBlock (block : Block ): Boolean {
44+ return true
45+ }
46+
47+ /* *
48+ * Called when a fire is spawned
49+ * - after onIgniteBlock
50+ * - after onFireSpread
51+ * - fire eats block
52+ */
53+ fun onFireSpawn (fire : Block ) {}
54+
55+ @ApiStatus.Internal
56+ companion object : MultiListener {
57+ @UniversalHandler
58+ private fun onDamageEntity (event : EntityDamageEvent , priority : EventPriority ) {
59+ if (event.cause != EntityDamageEvent .DamageCause .FIRE ) return
60+
61+ val rebarBlock = BlockStorage .get(event.entity.location)
62+ if (rebarBlock !is RebarFire ) {
63+ return
64+ }
65+
66+ try {
67+ MultiHandlers .handleEvent(rebarBlock, " onDamageEntity" , event, priority)
68+ } catch (e: Exception ) {
69+ BlockListener .logEventHandleErr(event, e, rebarBlock)
70+ }
71+ }
72+
73+ @UniversalHandler
74+ private fun onIgniteBlock (event : BlockIgniteEvent , priority : EventPriority ) {
75+ if (event.ignitingBlock == null || event.cause != BlockIgniteEvent .IgniteCause .SPREAD ) {
76+ return
77+ }
78+
79+ val rebarBlock = BlockStorage .get(event.ignitingBlock!! )
80+ if (rebarBlock !is RebarFire ) return
81+
82+ try {
83+ MultiHandlers .handleEvent(rebarBlock, " onIgniteBlock" , event, priority)
84+
85+ if (! event.isCancelled) {
86+ trySpawnRebarFire(rebarBlock, event.block)
87+ }
88+ } catch (e: Exception ) {
89+ BlockListener .logEventHandleErr(event, e, rebarBlock)
90+ }
91+ }
92+
93+ @UniversalHandler
94+ private fun onFireSpread (event : BlockSpreadEvent , priority : EventPriority ) {
95+ if (event.block.type != Material .FIRE ) return
96+
97+ val rebarBlock = BlockStorage .get(event.source)
98+ if (rebarBlock !is RebarFire ) return
99+
100+ try {
101+ MultiHandlers .handleEvent(rebarBlock, " onFireSpread" , event, priority)
102+
103+ if (! event.isCancelled) {
104+ trySpawnRebarFire(rebarBlock, event.block)
105+ }
106+ } catch (e: Exception ) {
107+ BlockListener .logEventHandleErr(event, e, rebarBlock)
108+ }
109+ }
110+
111+ /* *
112+ * This is a hack to make fire spread work. After calling BlockBurnEvent,
113+ * the fire still has a chance to spawn a new fire at the block
114+ * without calling events again.
115+ */
116+ @EventHandler(priority = EventPriority .HIGHEST , ignoreCancelled = true )
117+ private fun onFireEatBlock (event : BlockBurnEvent ) {
118+ val rebarBlock = BlockStorage .get(event.ignitingBlock!! )
119+ if (rebarBlock !is RebarFire ) return
120+
121+ Bukkit .getScheduler().runTaskLater(Rebar , Runnable {
122+ if (event.block.type == Material .FIRE ) { // SOUL_FIRE cannot spread, just ignore it.
123+ if (rebarBlock.onFireEatBlock(event.block)) {
124+ trySpawnRebarFire(rebarBlock, event.block)
125+ } else {
126+ event.block.type = Material .AIR
127+ }
128+ }
129+ }, 1 )
130+ }
131+
132+ private fun <T > trySpawnRebarFire (fire : T , block : Block ) where T : RebarFire, T : RebarBlock {
133+ if (BlockStorage .isRebarBlock(block)) {
134+ return
135+ }
136+
137+ // place new fire
138+ BlockStorage .placeBlock(
139+ block,
140+ fire.key,
141+ BlockCreateContext .PluginGenerate (Rebar .javaPlugin, block = block, shouldSetType = false )
142+ )
143+ fire.onFireSpawn(block)
144+ }
145+ }
146+ }
0 commit comments