Skip to content

Commit 33ed6f4

Browse files
authored
Merge pull request #744 from pylonmc/human/small-things
Small Bug Fixes & Features
2 parents 2920c9b + edd6f73 commit 33ed6f4

15 files changed

Lines changed: 192 additions & 42 deletions

File tree

rebar/src/main/kotlin/io/github/pylonmc/rebar/Rebar.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ object Rebar : JavaPlugin(), RebarAddon {
224224
RebarTool.register(this, pm)
225225
RebarWeapon.register(this, pm)
226226
VanillaCookingFuel.register(this, pm)
227+
RebarPickupable.register(this, pm)
228+
RebarDroppable.register(this, pm)
227229

228230
// Rebar Entities
229231
EntityListener.register(this, pm)

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/BlockStorage.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import kotlin.random.Random
6666
object BlockStorage : Listener {
6767

6868
val rebarBlocksKey = rebarKey("blocks")
69+
val rebarBlocksType = RebarSerializers.LIST.listTypeFrom(RebarSerializers.TAG_CONTAINER)
6970

7071
// Access to blocks, blocksByChunk, blocksById fields must be synchronized
7172
// to prevent them briefly going out of sync
@@ -510,8 +511,7 @@ object BlockStorage : Listener {
510511
}
511512

512513
private fun load(world: World, chunk: Chunk): List<RebarBlock> {
513-
val type = RebarSerializers.LIST.listTypeFrom(RebarSerializers.TAG_CONTAINER)
514-
val chunkBlocks = chunk.persistentDataContainer.get(rebarBlocksKey, type)?.mapNotNull { element ->
514+
val chunkBlocks = chunk.persistentDataContainer.get(rebarBlocksKey, rebarBlocksType)?.mapNotNull { element ->
515515
RebarBlock.deserialize(world, element)
516516
}?.toMutableList() ?: mutableListOf()
517517

@@ -522,9 +522,7 @@ object BlockStorage : Listener {
522522
val serializedBlocks = chunkBlocks.mapNotNull {
523523
RebarBlock.serialize(it, chunk.persistentDataContainer.adapterContext)
524524
}
525-
526-
val type = RebarSerializers.LIST.listTypeFrom(RebarSerializers.TAG_CONTAINER)
527-
chunk.persistentDataContainer.set(rebarBlocksKey, type, serializedBlocks)
525+
chunk.persistentDataContainer.set(rebarBlocksKey, rebarBlocksType, serializedBlocks)
528526
}
529527

530528
@EventHandler

rebar/src/main/kotlin/io/github/pylonmc/rebar/content/fluid/FluidIntersectionDisplay.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.pylonmc.rebar.content.fluid
22

3+
import io.github.pylonmc.rebar.block.BlockStorage
34
import io.github.pylonmc.rebar.datatypes.RebarSerializers
45
import io.github.pylonmc.rebar.entity.EntityStorage
56
import io.github.pylonmc.rebar.entity.RebarEntity
@@ -11,7 +12,12 @@ import io.github.pylonmc.rebar.fluid.FluidManager
1112
import io.github.pylonmc.rebar.fluid.FluidPointType
1213
import io.github.pylonmc.rebar.fluid.VirtualFluidPoint
1314
import io.github.pylonmc.rebar.item.builder.ItemStackBuilder
15+
import io.github.pylonmc.rebar.util.IMMEDIATE_FACES
1416
import io.github.pylonmc.rebar.util.rebarKey
17+
import io.papermc.paper.datacomponent.DataComponentTypes
18+
import io.papermc.paper.datacomponent.item.CustomModelData
19+
import jdk.internal.org.jline.keymap.KeyMap.display
20+
import org.bukkit.NamespacedKey
1521
import org.bukkit.block.Block
1622
import org.bukkit.entity.ItemDisplay
1723
import org.bukkit.event.EventPriority
@@ -63,13 +69,42 @@ class FluidIntersectionDisplay : RebarEntity<ItemDisplay>, RebarDeathEntity, Flu
6369
pdc.set(CONNECTED_PIPE_DISPLAYS_KEY, RebarSerializers.TAG_CONTAINER, connectedPdc)
6470
}
6571

72+
@Suppress("UnstableApiUsage")
73+
fun updateItemDisplay() {
74+
if (connectedPipeDisplays.isEmpty()) return
75+
76+
val marker = BlockStorage.getAs(FluidIntersectionMarker::class.java, entity.location.block) ?: return
77+
val modelData = CustomModelData.customModelData()
78+
modelData.addString("fluid_point_display:${FluidPointType.INTERSECTION.name.lowercase()}")
79+
modelData.addString("fluid_point_display:${marker.pipe.key}")
80+
81+
val from = this.entity.location
82+
for (face in IMMEDIATE_FACES) {
83+
var hasFace = false
84+
for (displayId in this.connectedPipeDisplays) {
85+
val display = EntityStorage.getAs(FluidPipeDisplay::class.java, displayId) ?: continue
86+
val towards = display.entity.location.subtract(from).toVector().normalize()
87+
if (face.direction == towards) {
88+
hasFace = true
89+
break
90+
}
91+
}
92+
modelData.addString("${face.name.lowercase()}=$hasFace")
93+
}
94+
this.entity.setItemStack(this.entity.itemStack.apply {
95+
setData(DataComponentTypes.CUSTOM_MODEL_DATA, modelData)
96+
})
97+
}
98+
6699
override fun connectPipeDisplay(uuid: UUID) {
67100
this.connectedPipeDisplays.add(uuid)
101+
updateItemDisplay()
68102
}
69103

70104
override fun disconnectPipeDisplay(uuid: UUID) {
71105
check(uuid in this.connectedPipeDisplays) { "$uuid is not connected" }
72106
this.connectedPipeDisplays.remove(uuid)
107+
updateItemDisplay()
73108
}
74109

75110
override fun onDeath(event: RebarEntityDeathEvent, priority: EventPriority) {

rebar/src/main/kotlin/io/github/pylonmc/rebar/content/fluid/FluidPipeDisplay.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ class FluidPipeDisplay : RebarEntity<ItemDisplay> {
138138
.buildForItemDisplay()
139139
)
140140
.itemStack(ItemStackBuilder.of(pipe.material)
141-
.addCustomModelDataString("fluid_pipe_display:${pipe.key.key}")
141+
.addCustomModelDataString("fluid_pipe_display:${pipe.key}")
142142
.addCustomModelDataString("fluid_pipe_length:${pipeAmount}")
143143
)
144144
.build(centerLocation)

rebar/src/main/kotlin/io/github/pylonmc/rebar/entity/EntityStorage.kt

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import io.github.pylonmc.rebar.util.isFromAddon
1414
import kotlinx.coroutines.Job
1515
import kotlinx.coroutines.delay
1616
import kotlinx.coroutines.launch
17+
import org.bukkit.Bukkit
1718
import org.bukkit.NamespacedKey
1819
import org.bukkit.entity.Entity
1920
import org.bukkit.event.EventHandler
@@ -37,6 +38,7 @@ object EntityStorage : Listener {
3738
private val entitiesByKey: MutableMap<NamespacedKey, MutableSet<RebarEntity<*>>> = ConcurrentHashMap()
3839
private val entityAutosaveTasks: MutableMap<UUID, Job> = ConcurrentHashMap()
3940
private val whenEntityLoadsTasks: MutableMap<UUID, MutableSet<Consumer<RebarEntity<*>>>> = ConcurrentHashMap()
41+
private val whenVanillaEntityLoadsTasks: MutableMap<UUID, MutableSet<Consumer<Entity>>> = ConcurrentHashMap()
4042

4143
// Access to entities, entitiesById fields must be synchronized to prevent them
4244
// briefly going out of sync
@@ -130,7 +132,6 @@ object EntityStorage : Listener {
130132
consumer.accept(it)
131133
}
132134
}
133-
134135
}
135136

136137
/**
@@ -161,6 +162,52 @@ object EntityStorage : Listener {
161162
inline fun <reified T> whenEntityLoads(uuid: UUID, crossinline consumer: (T) -> Unit)
162163
= whenEntityLoads(uuid, T::class.java) { t -> consumer(t) }
163164

165+
/**
166+
* Schedules a task to run when the vanilla entity with id [uuid] is loaded, or runs the task immediately
167+
* if the entity is already loaded.
168+
*
169+
* Useful for when you don't know whether a block or one of its associated entity will be loaded first.
170+
*/
171+
@JvmStatic
172+
fun whenVanillaEntityLoads(uuid: UUID, consumer: Consumer<Entity>) {
173+
val entity = Bukkit.getEntity(uuid)
174+
if (entity != null) {
175+
consumer.accept(entity)
176+
} else {
177+
whenVanillaEntityLoadsTasks.getOrPut(uuid) { mutableSetOf() }.add {
178+
consumer.accept(it)
179+
}
180+
}
181+
}
182+
183+
/**
184+
* Schedules a task to run when the vanilla entity with id [uuid] is loaded, or runs the task immediately
185+
* if the entity is already loaded.
186+
*
187+
* Useful for when you don't know whether a block or one of its associated entity will be loaded first.
188+
*/
189+
@JvmStatic
190+
fun <T> whenVanillaEntityLoads(uuid: UUID, clazz: Class<T>, consumer: Consumer<T>) {
191+
val entity = Bukkit.getEntity(uuid)
192+
if (entity != null && clazz.isInstance(entity)) {
193+
consumer.accept(clazz.cast(entity))
194+
} else {
195+
whenVanillaEntityLoadsTasks.getOrPut(uuid) { mutableSetOf() }.add {
196+
consumer.accept(if (clazz.isInstance(it)) clazz.cast(it) else throw IllegalStateException("Entity $uuid was not of expected type ${clazz.simpleName}"))
197+
}
198+
}
199+
}
200+
201+
/**
202+
* Schedules a task to run when the vanilla entity with id [uuid] is loaded, or runs the task immediately
203+
* if the entity is already loaded
204+
*
205+
* Useful for when you don't know whether a block or one of its associated entity will be loaded first.
206+
*/
207+
@JvmStatic
208+
inline fun <reified T> whenVanillaEntityLoads(uuid: UUID, crossinline consumer: (T) -> Unit)
209+
= whenVanillaEntityLoads(uuid, T::class.java) { t -> consumer(t) }
210+
164211
/**
165212
* Returns false if the entity is not a [RebarEntity] or does not exist.
166213
*/
@@ -203,10 +250,21 @@ object EntityStorage : Listener {
203250
@EventHandler
204251
private fun onEntityLoad(event: EntitiesLoadEvent) {
205252
for (entity in event.entities) {
253+
val vanillaTasks = whenVanillaEntityLoadsTasks.remove(entity.uniqueId)
254+
if (vanillaTasks != null) {
255+
for (task in vanillaTasks) {
256+
try {
257+
task.accept(entity)
258+
} catch (t: Throwable) {
259+
t.printStackTrace()
260+
}
261+
}
262+
}
263+
206264
val rebarEntity = RebarEntity.deserialize(entity) ?: continue
207265
add(rebarEntity)
208266

209-
val tasks = whenEntityLoadsTasks[rebarEntity.uuid]
267+
val tasks = whenEntityLoadsTasks.remove(rebarEntity.uuid)
210268
if (tasks != null) {
211269
for (task in tasks) {
212270
try {
@@ -215,7 +273,6 @@ object EntityStorage : Listener {
215273
t.printStackTrace()
216274
}
217275
}
218-
whenEntityLoadsTasks.remove(rebarEntity.uuid)
219276
}
220277

221278
RebarEntityLoadEvent(rebarEntity).callEvent()

rebar/src/main/kotlin/io/github/pylonmc/rebar/guide/button/BackButton.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package io.github.pylonmc.rebar.guide.button
22

33
import io.github.pylonmc.rebar.content.guide.RebarGuide
44
import io.github.pylonmc.rebar.item.builder.ItemStackBuilder
5+
import io.github.pylonmc.rebar.item.research.Research.Companion.guideHints
56
import io.github.pylonmc.rebar.util.rebarKey
67
import io.papermc.paper.datacomponent.DataComponentTypes
78
import net.kyori.adventure.text.Component
@@ -20,7 +21,11 @@ class BackButton : AbstractItem() {
2021
override fun getItemProvider(player: Player) =
2122
ItemStackBuilder.gui(Material.ENCHANTED_BOOK, rebarKey("guide_back"))
2223
.set(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, false)
23-
.name(Component.translatable("rebar.guide.button.back.name"))
24+
.name(Component.translatable("rebar.guide.button.back.name")).apply {
25+
if (player.guideHints) {
26+
lore(Component.translatable("rebar.guide.button.back.hints"))
27+
}
28+
}
2429

2530
override fun handleClick(clickType: ClickType, player: Player, click: Click) {
2631
val history = RebarGuide.history.getOrPut(player.uniqueId) { mutableListOf() }

rebar/src/main/kotlin/io/github/pylonmc/rebar/guide/button/PageButton.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ open class PageButton(val stack: ItemStack, val page: GuidePage) : GuideButton()
2828

2929
constructor(material: Material, page: GuidePage) : this(ItemStack(material), page)
3030

31-
override fun getItemProvider(viewer: Player): ItemProvider = ItemStackBuilder.gui(stack, "${rebarKey("guide_page")}:${page.key}")
31+
override fun getItemProvider(viewer: Player): ItemProvider = ItemStackBuilder.gui(stack.clone(), "${rebarKey("guide_page")}:${page.key}")
3232
.name(Component.translatable("${page.key.namespace}.guide.page.${page.key.key}"))
3333
.clearLore()
3434
.lore(Component.translatable("${page.key.namespace}.guide.button.${page.key.key}.lore", ""))

rebar/src/main/kotlin/io/github/pylonmc/rebar/guide/pages/base/SearchPage.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ abstract class SearchPage(key: NamespacedKey) : SimpleStaticGuidePage(key) {
5252
val upperGui = Gui.builder()
5353
.setStructure("# S #")
5454
.addIngredient('S', searchSpecifiersStack)
55-
.addIngredient('#', GuiItems.background(search))
55+
.addIngredient('#', GuiItems.background())
5656
.build()
5757
loadCurrentPage(player, lowerGui)
5858

rebar/src/main/kotlin/io/github/pylonmc/rebar/item/RebarItemListener.kt

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,21 @@ package io.github.pylonmc.rebar.item
33
import com.destroystokyo.paper.event.player.PlayerReadyArrowEvent
44
import io.github.pylonmc.rebar.Rebar
55
import io.github.pylonmc.rebar.block.BlockStorage
6-
import io.github.pylonmc.rebar.entity.EntityListener.logEventHandleErr
76
import io.github.pylonmc.rebar.item.base.*
87
import io.github.pylonmc.rebar.item.research.Research.Companion.canUse
98
import io.github.pylonmc.rebar.util.findRebarItemInInventory
10-
import io.papermc.paper.event.player.PlayerPickItemEvent
9+
import io.papermc.paper.event.player.PlayerPickBlockEvent
1110
import org.bukkit.GameMode
12-
import org.bukkit.attribute.Attribute
1311
import org.bukkit.entity.Player
1412
import org.bukkit.event.Event
1513
import org.bukkit.event.EventHandler
1614
import org.bukkit.event.EventPriority
1715
import org.bukkit.event.Listener
1816
import org.bukkit.event.block.BlockBreakEvent
1917
import org.bukkit.event.block.BlockDamageEvent
20-
import org.bukkit.event.block.BlockDispenseEvent
2118
import org.bukkit.event.entity.EntityDamageByEntityEvent
2219
import org.bukkit.event.entity.EntityDeathEvent
23-
import org.bukkit.event.entity.EntityShootBowEvent
24-
import org.bukkit.event.inventory.BrewingStandFuelEvent
25-
import org.bukkit.event.inventory.FurnaceBurnEvent
2620
import org.bukkit.event.player.*
27-
import kotlin.math.ceil
2821

2922
internal object RebarItemListener : Listener {
3023
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
@@ -167,20 +160,18 @@ internal object RebarItemListener : Listener {
167160
}
168161
}
169162

170-
@EventHandler
171-
private fun handle(event: PlayerPickItemEvent) {
172-
val reachDistance = event.player.getAttribute(Attribute.BLOCK_INTERACTION_RANGE)?.value ?: 4.5
173-
val block = event.player.getTargetBlockExact(ceil(reachDistance).toInt()) ?: return
174-
val rebarBlock = BlockStorage.get(block) ?: return
163+
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
164+
private fun handle(event: PlayerPickBlockEvent) {
165+
val rebarBlock = BlockStorage.get(event.block) ?: return
175166
val blockItem = rebarBlock.getPickItem() ?: return
176-
val blockRebarItem = RebarItem.fromStack(blockItem) ?: return
167+
val blockSchema = RebarItemSchema.fromStack(blockItem) ?: return
177168

178169
val sourceSlot = event.sourceSlot
179170
if (sourceSlot != -1) {
180171
val sourceItem = event.player.inventory.getItem(event.sourceSlot)
181172
if (sourceItem != null) {
182-
val sourceRebarItem = RebarItem.fromStack(sourceItem)
183-
if (sourceRebarItem != null) {
173+
val sourceSchema = RebarItemSchema.fromStack(sourceItem)
174+
if (sourceSchema == blockSchema) {
184175
// The source item is already of the correct Rebar type, so we shouldn't interfere with the event
185176
return
186177
}
@@ -189,7 +180,7 @@ internal object RebarItemListener : Listener {
189180

190181
// If we reach this point, the source item is not of the correct type
191182
// So we're going to search the inventory for a block of the correct type
192-
val existingSlot = findRebarItemInInventory(event.player.inventory, blockRebarItem)
183+
val existingSlot = findRebarItemInInventory(event.player.inventory, blockSchema)
193184
if (existingSlot != null) {
194185
// If we find one, we'll set the source to that slot
195186
event.sourceSlot = existingSlot
@@ -209,7 +200,7 @@ internal object RebarItemListener : Listener {
209200
}
210201
}
211202

212-
val newSourceSlot = findRebarItemInInventory(event.player.inventory, blockRebarItem)
203+
val newSourceSlot = findRebarItemInInventory(event.player.inventory, blockSchema)
213204
if (newSourceSlot == null) {
214205
// should never happen but you never know
215206
event.isCancelled = true
@@ -218,14 +209,6 @@ internal object RebarItemListener : Listener {
218209

219210
event.sourceSlot = newSourceSlot
220211
event.targetSlot = event.player.inventory.heldItemSlot
221-
222-
// don't question this idk wtf is going on - seems we have to manually do the swap in the hotbar
223-
if (sourceSlot <= 8) {
224-
val source = event.player.inventory.getItem(event.sourceSlot)
225-
val target = event.player.inventory.getItem(event.targetSlot)
226-
event.player.inventory.setItem(event.sourceSlot, target)
227-
event.player.inventory.setItem(event.targetSlot, source)
228-
}
229212
}
230213

231214
@JvmSynthetic
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.github.pylonmc.rebar.item.base
2+
3+
import io.github.pylonmc.rebar.event.api.MultiListener
4+
import io.github.pylonmc.rebar.event.api.annotation.MultiHandlers
5+
import io.github.pylonmc.rebar.event.api.annotation.UniversalHandler
6+
import io.github.pylonmc.rebar.item.RebarItem
7+
import io.github.pylonmc.rebar.item.RebarItemListener
8+
import org.bukkit.event.EventPriority
9+
import org.bukkit.event.player.PlayerDropItemEvent
10+
import org.jetbrains.annotations.ApiStatus
11+
12+
interface RebarDroppable {
13+
fun onDropped(event: PlayerDropItemEvent, priority: EventPriority)
14+
15+
@ApiStatus.Internal
16+
companion object : MultiListener {
17+
@UniversalHandler
18+
private fun onDrop(event: PlayerDropItemEvent, priority: EventPriority) {
19+
val rebarItem = RebarItem.fromStack(event.itemDrop.itemStack, RebarDroppable::class.java)
20+
val droppable = rebarItem as? RebarItem ?: return
21+
22+
try {
23+
MultiHandlers.handleEvent(droppable, "onDropped", event, priority)
24+
} catch (e: Exception) {
25+
RebarItemListener.logEventHandleErr(event, e, rebarItem)
26+
}
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)