Skip to content

Commit 71cc5ff

Browse files
committed
improved unformed, improve simple multiblock
1 parent 451094f commit 71cc5ff

File tree

3 files changed

+54
-31
lines changed

3 files changed

+54
-31
lines changed

pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/MultiblockCache.kt

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,15 @@ internal object MultiblockCache : Listener {
6666
override fun run() {
6767
for (multiblockPosition in dirtyMultiblocks) {
6868
// For a multiblock to be formed, it must be fully loaded
69+
val multiblock = BlockStorage.getAs<PylonMultiblock>(multiblockPosition)
6970
if (multiblockPosition !in fullyLoadedMultiblocks) {
70-
formedMultiblocks.remove(multiblockPosition)
71+
if (formedMultiblocks.remove(multiblockPosition) && multiblock != null) {
72+
multiblock.onMultiblockUnformed(true)
73+
PylonMultiblockUnformEvent(multiblockPosition.block, multiblock as PylonBlock).callEvent()
74+
}
7175
continue
7276
}
7377

74-
val multiblock = BlockStorage.getAs<PylonMultiblock>(multiblockPosition)
7578
if (multiblock != null && multiblock.checkFormed()) {
7679
if (formedMultiblocks.add(multiblockPosition)) {
7780
multiblock.onMultiblockFormed()
@@ -82,7 +85,7 @@ internal object MultiblockCache : Listener {
8285
}
8386
} else {
8487
if (formedMultiblocks.remove(multiblockPosition) && multiblock != null) {
85-
multiblock.onMultiblockUnformed()
88+
multiblock.onMultiblockUnformed(false)
8689
PylonMultiblockUnformEvent(multiblockPosition.block, multiblock as PylonBlock).callEvent()
8790
}
8891
}
@@ -99,13 +102,17 @@ internal object MultiblockCache : Listener {
99102
= dirtyMultiblocks.add(multiblock.block.position)
100103

101104
private fun refreshFullyLoaded(multiblock: PylonMultiblock) {
105+
val multiblockPosition = multiblock.block.position
102106
if (multiblock.chunksOccupied.all { it.isLoaded }) {
103-
fullyLoadedMultiblocks.add(multiblock.block.position)
107+
fullyLoadedMultiblocks.add(multiblockPosition)
104108
markDirty(multiblock)
105109
} else {
106-
formedMultiblocks.remove(multiblock.block.position)
107-
fullyLoadedMultiblocks.remove(multiblock.block.position)
108-
dirtyMultiblocks.remove(multiblock.block.position)
110+
if (formedMultiblocks.remove(multiblockPosition)) {
111+
multiblock.onMultiblockUnformed(true)
112+
PylonMultiblockUnformEvent(multiblock.block, multiblock as PylonBlock).callEvent()
113+
}
114+
fullyLoadedMultiblocks.remove(multiblockPosition)
115+
dirtyMultiblocks.remove(multiblockPosition)
109116
}
110117
}
111118

@@ -127,8 +134,8 @@ internal object MultiblockCache : Listener {
127134
}
128135
}
129136

130-
fullyLoadedMultiblocks.remove(multiblockPosition)
131137
formedMultiblocks.remove(multiblockPosition)
138+
fullyLoadedMultiblocks.remove(multiblockPosition)
132139
dirtyMultiblocks.remove(multiblockPosition)
133140
}
134141

@@ -162,19 +169,23 @@ internal object MultiblockCache : Listener {
162169

163170
@EventHandler
164171
private fun handle(event: PylonChunkBlocksUnloadEvent) {
165-
// Mark existing multiblocks with components as not formed and not fully loaded
166-
for (multiblockPosition in loadedMultiblocksWithComponentsInChunk(event.chunk.position)) {
167-
formedMultiblocks.remove(multiblockPosition)
168-
fullyLoadedMultiblocks.remove(multiblockPosition)
169-
dirtyMultiblocks.remove(multiblockPosition)
170-
}
171-
172172
// Remove multiblocks that were just unloaded
173173
for (pylonBlock in event.pylonBlocks) {
174174
if (pylonBlock is PylonMultiblock) {
175175
onMultiblockRemoved(pylonBlock)
176176
}
177177
}
178+
179+
// Mark existing multiblocks with components as not formed and not fully loaded
180+
for (multiblockPosition in loadedMultiblocksWithComponentsInChunk(event.chunk.position)) {
181+
val multiblock = BlockStorage.getAs<PylonMultiblock>(multiblockPosition)
182+
if (formedMultiblocks.remove(multiblockPosition) && multiblock != null) {
183+
multiblock.onMultiblockUnformed(true)
184+
PylonMultiblockUnformEvent(multiblockPosition.block, multiblock as PylonBlock).callEvent()
185+
}
186+
fullyLoadedMultiblocks.remove(multiblockPosition)
187+
dirtyMultiblocks.remove(multiblockPosition)
188+
}
178189
}
179190

180191
@EventHandler

pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonMultiblock.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import io.github.pylonmc.pylon.core.block.MultiblockCache
44
import io.github.pylonmc.pylon.core.util.position.ChunkPosition
55
import org.bukkit.block.Block
66
import org.jetbrains.annotations.ApiStatus
7-
import org.jetbrains.annotations.MustBeInvokedByOverriders
87

98

109
/**
@@ -70,7 +69,12 @@ interface PylonMultiblock {
7069

7170
/**
7271
* Called when the multiblock is unformed (i.e., was formed before, but now is not).
73-
* This includes when a part of the multiblock is unloaded, and the multiblock becomes unformed because of it.
72+
* This includes when a part of the multiblock is unloaded and the multiblock becomes unformed because of it,
73+
* or when part of the multiblock is broken/changed, and it becomes unformed because of it.
74+
*
75+
* This is **not** called when the multiblock itself is unloaded, use [PylonUnloadBlock] for that.
76+
*
77+
* [partUnloaded] is true if the multiblock became unformed because part of it was unloaded, false otherwise.
7478
*/
75-
fun onMultiblockUnformed() {}
79+
fun onMultiblockUnformed(partUnloaded: Boolean) {}
7680
}

pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonSimpleMultiblock.kt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import io.github.pylonmc.pylon.core.datatypes.PylonSerializers
99
import io.github.pylonmc.pylon.core.entity.EntityStorage
1010
import io.github.pylonmc.pylon.core.entity.PylonEntity
1111
import io.github.pylonmc.pylon.core.entity.base.PylonInteractEntity
12-
import io.github.pylonmc.pylon.core.entity.display.BlockDisplayBuilder
1312
import io.github.pylonmc.pylon.core.entity.display.ItemDisplayBuilder
1413
import io.github.pylonmc.pylon.core.entity.display.transform.TransformBuilder
1514
import io.github.pylonmc.pylon.core.event.PylonBlockDeserializeEvent
@@ -28,7 +27,6 @@ import org.bukkit.Material
2827
import org.bukkit.NamespacedKey
2928
import org.bukkit.block.Block
3029
import org.bukkit.block.BlockFace
31-
import org.bukkit.entity.BlockDisplay
3230
import org.bukkit.entity.ItemDisplay
3331
import org.bukkit.event.EventHandler
3432
import org.bukkit.event.Listener
@@ -37,6 +35,7 @@ import org.bukkit.inventory.ItemStack
3735
import org.bukkit.persistence.PersistentDataContainer
3836
import org.bukkit.util.Vector
3937
import org.jetbrains.annotations.ApiStatus
38+
import org.jetbrains.annotations.MustBeInvokedByOverriders
4039
import org.joml.Vector3i
4140
import java.util.IdentityHashMap
4241
import java.util.UUID
@@ -219,8 +218,10 @@ interface PylonSimpleMultiblock : PylonMultiblock, PylonEntityHolderBlock, Pylon
219218
val rotatedComponents = if (facing == null) components else rotateComponentsToFace(components, facing)
220219
for ((offset, component) in rotatedComponents) {
221220
val key = "multiblock_ghost_block_${offset.x}_${offset.y}_${offset.z}"
222-
val ghostBlock = component.spawnGhostBlock((block.position + offset).block)
223-
heldEntities[key] = ghostBlock
221+
if (!isHeldEntityPresent(key)) {
222+
val ghostBlock = component.spawnGhostBlock((block.position + offset).block)
223+
heldEntities[key] = ghostBlock
224+
}
224225
}
225226
updateGhostBlockColors()
226227
}
@@ -274,20 +275,27 @@ interface PylonSimpleMultiblock : PylonMultiblock, PylonEntityHolderBlock, Pylon
274275
}
275276
}
276277

277-
// Remove ghosts if fully formed
278-
if (formed) {
279-
val toRemove = heldEntities.keys.filter { it.startsWith("multiblock_ghost_block_") }
280-
for (key in toRemove) {
281-
EntityStorage.get(heldEntities[key]!!)!!.entity.remove()
282-
heldEntities.remove(key)
283-
}
284-
}
285-
286278
updateGhostBlockColors()
287279

288280
return formed
289281
}
290282

283+
@MustBeInvokedByOverriders
284+
override fun onMultiblockFormed() {
285+
val toRemove = heldEntities.keys.filter { it.startsWith("multiblock_ghost_block_") }
286+
for (key in toRemove) {
287+
EntityStorage.get(heldEntities[key]!!)!!.entity.remove()
288+
heldEntities.remove(key)
289+
}
290+
}
291+
292+
@MustBeInvokedByOverriders
293+
override fun onMultiblockUnformed(partUnloaded: Boolean) {
294+
if (!partUnloaded) {
295+
spawnGhostBlocks()
296+
}
297+
}
298+
291299
override fun isPartOfMultiblock(otherBlock: Block): Boolean = validStructures().any {
292300
it.contains((otherBlock.position - block.position).vector3i)
293301
}

0 commit comments

Comments
 (0)