Improve performance of multiblock scanning by postponing blockentity lookup until it is actually needed

This commit is contained in:
DBotThePony 2025-02-25 11:56:36 +07:00
parent 304b6a65c8
commit 59200b2baa
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 13 additions and 14 deletions

View File

@ -7,11 +7,10 @@ import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.block.Rotation import net.minecraft.world.level.block.Rotation
import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.core.getBlockStateNow
import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.math.plus
fun interface BlockPredicate { fun interface BlockPredicate {
fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean
fun rotate(rotation: Rotation): BlockPredicate { fun rotate(rotation: Rotation): BlockPredicate {
return this return this
@ -42,7 +41,7 @@ fun interface BlockPredicate {
} }
data class Positioned(val offset: BlockPos, val parent: BlockPredicate) : BlockPredicate { data class Positioned(val offset: BlockPos, val parent: BlockPredicate) : BlockPredicate {
override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
return parent.test(offset + pos, access, blockState, blockEntity) return parent.test(offset + pos, access, blockState, blockEntity)
} }
@ -55,7 +54,7 @@ fun interface BlockPredicate {
constructor(vararg nodes: BlockPredicate) : this(ImmutableSet.copyOf(nodes)) constructor(vararg nodes: BlockPredicate) : this(ImmutableSet.copyOf(nodes))
constructor(nodes: Set<BlockPredicate>) : this(ImmutableSet.copyOf(nodes)) constructor(nodes: Set<BlockPredicate>) : this(ImmutableSet.copyOf(nodes))
override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
return nodes.all { it.test(pos, access, blockState, blockEntity) } return nodes.all { it.test(pos, access, blockState, blockEntity) }
} }
} }
@ -64,19 +63,19 @@ fun interface BlockPredicate {
constructor(vararg nodes: BlockPredicate) : this(ImmutableSet.copyOf(nodes)) constructor(vararg nodes: BlockPredicate) : this(ImmutableSet.copyOf(nodes))
constructor(nodes: Set<BlockPredicate>) : this(ImmutableSet.copyOf(nodes)) constructor(nodes: Set<BlockPredicate>) : this(ImmutableSet.copyOf(nodes))
override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
return nodes.any { it.test(pos, access, blockState, blockEntity) } return nodes.any { it.test(pos, access, blockState, blockEntity) }
} }
} }
object Air : BlockPredicate { object Air : BlockPredicate {
override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
return blockState.isAir return blockState.isAir
} }
} }
object NotAir : BlockPredicate { object NotAir : BlockPredicate {
override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { override fun test(pos: BlockPos, access: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
return !blockState.isAir return !blockState.isAir
} }
} }

View File

@ -116,7 +116,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
stream.writeByte(status.ordinal) stream.writeByte(status.ordinal)
} }
private fun orPredicates(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { private fun orPredicates(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
if (prototype.predicate.isNotEmpty()) { if (prototype.predicate.isNotEmpty()) {
if (lastSuccessfulPathPredicate != -1 && !prototype.predicate[lastSuccessfulPathPredicate].test(pos, levelAccessor, blockState, blockEntity)) { if (lastSuccessfulPathPredicate != -1 && !prototype.predicate[lastSuccessfulPathPredicate].test(pos, levelAccessor, blockState, blockEntity)) {
lastSuccessfulPathPredicate = -1 lastSuccessfulPathPredicate = -1
@ -131,7 +131,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
return true return true
} }
private fun orChildren(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { private fun orChildren(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
if (children.isNotEmpty()) { if (children.isNotEmpty()) {
if (lastSuccessfulPathChildren != -1 && !children[lastSuccessfulPathChildren].test0(levelAccessor, blockState, blockEntity)) { if (lastSuccessfulPathChildren != -1 && !children[lastSuccessfulPathChildren].test0(levelAccessor, blockState, blockEntity)) {
lastSuccessfulPathChildren = -1 lastSuccessfulPathChildren = -1
@ -146,7 +146,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
return true return true
} }
private fun test0(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): Boolean { private fun test0(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): Boolean {
val test = when (prototype.strategy) { val test = when (prototype.strategy) {
Strategy.OR_BOTH -> orPredicates(levelAccessor, blockState, blockEntity) && orChildren(levelAccessor, blockState, blockEntity) Strategy.OR_BOTH -> orPredicates(levelAccessor, blockState, blockEntity) && orChildren(levelAccessor, blockState, blockEntity)
@ -161,7 +161,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
if (test) { if (test) {
if (assignedBlockEntityLists.isNotEmpty()) { if (assignedBlockEntityLists.isNotEmpty()) {
val be1 = this.blockEntity val be1 = this.blockEntity
val be2 = blockEntity val be2 = blockEntity.value
if (be1 != be2) { if (be1 != be2) {
generation++ generation++
@ -222,18 +222,18 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
} }
fun test(levelAccessor: LevelAccessor): MultiblockStatus { fun test(levelAccessor: LevelAccessor): MultiblockStatus {
val blockEntity = levelAccessor.getBlockEntityNow(pos) val blockEntity = lazy(LazyThreadSafetyMode.NONE) { levelAccessor.getBlockEntityNow(pos) }
val blockState = levelAccessor.getBlockStateNowOrNull(pos) ?: return MultiblockStatus.NOT_LOADED val blockState = levelAccessor.getBlockStateNowOrNull(pos) ?: return MultiblockStatus.NOT_LOADED
return test(levelAccessor, blockState, blockEntity) return test(levelAccessor, blockState, blockEntity)
} }
fun test(levelAccessor: LevelAccessor, chunk: LevelChunk): MultiblockStatus { fun test(levelAccessor: LevelAccessor, chunk: LevelChunk): MultiblockStatus {
val blockEntity = chunk.getBlockEntity(pos) val blockEntity = lazy(LazyThreadSafetyMode.NONE) { chunk.getBlockEntity(pos) }
val blockState = chunk.getBlockState(pos) val blockState = chunk.getBlockState(pos)
return test(levelAccessor, blockState, blockEntity) return test(levelAccessor, blockState, blockEntity)
} }
fun test(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: BlockEntity?): MultiblockStatus { fun test(levelAccessor: LevelAccessor, blockState: BlockState, blockEntity: Lazy<BlockEntity?>): MultiblockStatus {
val status = test0(levelAccessor, blockState, blockEntity) val status = test0(levelAccessor, blockState, blockEntity)
val previous = this.status val previous = this.status