Force directional multiblock and multiblock performance improvements
This commit is contained in:
parent
dafa54112e
commit
2a8cabe577
@ -9,14 +9,17 @@ import it.unimi.dsi.fastutil.objects.ObjectArraySet
|
|||||||
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
|
import net.minecraft.core.SectionPos
|
||||||
import net.minecraft.core.Vec3i
|
import net.minecraft.core.Vec3i
|
||||||
import net.minecraft.tags.TagKey
|
import net.minecraft.tags.TagKey
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
import net.minecraft.world.level.LevelAccessor
|
import net.minecraft.world.level.LevelAccessor
|
||||||
import net.minecraft.world.level.block.Block
|
import net.minecraft.world.level.block.Block
|
||||||
|
import net.minecraft.world.level.block.Blocks
|
||||||
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 net.minecraft.world.level.chunk.ChunkStatus
|
||||||
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
|
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
|
||||||
import ru.dbotthepony.mc.otm.core.collect.collect
|
import ru.dbotthepony.mc.otm.core.collect.collect
|
||||||
import ru.dbotthepony.mc.otm.core.collect.map
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
@ -119,9 +122,9 @@ class MultiblockBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
abstract class BlockPredicates<T : BlockPredicates<T>> {
|
abstract class Part<T : Part<T>> {
|
||||||
val predicates = ObjectArraySet<BlockPredicate>()
|
val predicates = ObjectArraySet<BlockPredicate>()
|
||||||
val children = ObjectArraySet<BlockPredicates<*>>()
|
val children = ObjectArraySet<Part<*>>()
|
||||||
|
|
||||||
val blockStateTags = ObjectArraySet<Any>()
|
val blockStateTags = ObjectArraySet<Any>()
|
||||||
val blockTags = ObjectArraySet<Any>()
|
val blockTags = ObjectArraySet<Any>()
|
||||||
@ -153,12 +156,20 @@ class MultiblockBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun block(block: Block): T {
|
fun block(block: Block): T {
|
||||||
predicates.add { pos, access -> access.getBlockState(pos).`is`(block) }
|
predicates.add { pos, access ->
|
||||||
|
// use getChunk directly because we don't want to chunkload
|
||||||
|
(access.getChunk(SectionPos.blockToSectionCoord(pos.x), SectionPos.blockToSectionCoord(pos.z), ChunkStatus.FULL, false)?.getBlockState(pos) ?: Blocks.AIR.defaultBlockState()).`is`(block)
|
||||||
|
}
|
||||||
|
|
||||||
return this as T
|
return this as T
|
||||||
}
|
}
|
||||||
|
|
||||||
fun block(block: TagKey<Block>): T {
|
fun block(block: TagKey<Block>): T {
|
||||||
predicates.add { pos, access -> access.getBlockState(pos).`is`(block) }
|
predicates.add { pos, access ->
|
||||||
|
// use getChunk directly because we don't want to chunkload
|
||||||
|
(access.getChunk(SectionPos.blockToSectionCoord(pos.x), SectionPos.blockToSectionCoord(pos.z), ChunkStatus.FULL, false)?.getBlockState(pos) ?: Blocks.AIR.defaultBlockState()).`is`(block)
|
||||||
|
}
|
||||||
|
|
||||||
return this as T
|
return this as T
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +179,11 @@ class MultiblockBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun block(state: BlockState): T {
|
fun block(state: BlockState): T {
|
||||||
predicates.add { pos, access -> access.getBlockState(pos) == state }
|
predicates.add { pos, access ->
|
||||||
|
// use getChunk directly because we don't want to chunkload
|
||||||
|
access.getChunk(SectionPos.blockToSectionCoord(pos.x), SectionPos.blockToSectionCoord(pos.z), ChunkStatus.FULL, false)?.getBlockState(pos) == state
|
||||||
|
}
|
||||||
|
|
||||||
return this as T
|
return this as T
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +216,7 @@ class MultiblockBuilder {
|
|||||||
abstract val strategy: Strategy
|
abstract val strategy: Strategy
|
||||||
}
|
}
|
||||||
|
|
||||||
class And<P : BlockPredicates<P>>(val parent: P) : BlockPredicates<And<P>>() {
|
class And<P : Part<P>>(val parent: P) : Part<And<P>>() {
|
||||||
init {
|
init {
|
||||||
parent.children.add(this)
|
parent.children.add(this)
|
||||||
}
|
}
|
||||||
@ -212,7 +227,7 @@ class MultiblockBuilder {
|
|||||||
get() = Strategy.AND
|
get() = Strategy.AND
|
||||||
}
|
}
|
||||||
|
|
||||||
class Or<P : BlockPredicates<P>>(val parent: P) : BlockPredicates<Or<P>>() {
|
class Or<P : Part<P>>(val parent: P) : Part<Or<P>>() {
|
||||||
init {
|
init {
|
||||||
parent.children.add(this)
|
parent.children.add(this)
|
||||||
}
|
}
|
||||||
@ -226,7 +241,7 @@ class MultiblockBuilder {
|
|||||||
/**
|
/**
|
||||||
* Behaves as if being [Or] node
|
* Behaves as if being [Or] node
|
||||||
*/
|
*/
|
||||||
inner class Node(val pos: BlockPos) : BlockPredicates<Node>() {
|
inner class Node(val pos: BlockPos) : Part<Node>() {
|
||||||
init {
|
init {
|
||||||
check(nodes.put(pos, this) == null) { "Trying to create new node at $pos while already having one" }
|
check(nodes.put(pos, this) == null) { "Trying to create new node at $pos while already having one" }
|
||||||
}
|
}
|
||||||
@ -433,8 +448,8 @@ class Multiblock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class Config(val pos: BlockPos, parts: Collection<MultiblockFactory.Part>) {
|
private inner class Config(val direction: Direction, val pos: BlockPos, parts: Collection<MultiblockFactory.Part>) {
|
||||||
private inner class Part(val pos: BlockPos, val prototype: MultiblockFactory.Part) {
|
private inner class Part(val pos: BlockPos, val prototype: MultiblockFactory.Part) : Comparable<Part> {
|
||||||
private var blockEntity: BlockEntity? = null
|
private var blockEntity: BlockEntity? = null
|
||||||
private var blockState: BlockState? = null
|
private var blockState: BlockState? = null
|
||||||
private val assignedBlockEntityLists = ArrayList<BEList<*>>(prototype.blockEntityTags.size)
|
private val assignedBlockEntityLists = ArrayList<BEList<*>>(prototype.blockEntityTags.size)
|
||||||
@ -442,6 +457,12 @@ class Multiblock(
|
|||||||
private val assignedBlockLists = ArrayList<Object2IntOpenHashMap<Block>>()
|
private val assignedBlockLists = ArrayList<Object2IntOpenHashMap<Block>>()
|
||||||
private val children: ImmutableList<Part> = prototype.children.stream().map { Part(pos, it) }.collect(ImmutableList.toImmutableList())
|
private val children: ImmutableList<Part> = prototype.children.stream().map { Part(pos, it) }.collect(ImmutableList.toImmutableList())
|
||||||
|
|
||||||
|
override fun compareTo(other: Part): Int {
|
||||||
|
val cmp = SectionPos.blockToSectionCoord(pos.x).compareTo(SectionPos.blockToSectionCoord(other.pos.x))
|
||||||
|
if (cmp != 0) return cmp
|
||||||
|
return SectionPos.blockToSectionCoord(pos.z).compareTo(SectionPos.blockToSectionCoord(other.pos.z))
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
prototype.blockEntityTags.forEach {
|
prototype.blockEntityTags.forEach {
|
||||||
assignedBlockEntityLists.add(tag2BlockEntity.computeIfAbsent(it, Object2ObjectFunction { _ -> BEList(it as MultiblockBuilder.EntityTag<BlockEntity>).also { blockEntityLists.add(it) } }))
|
assignedBlockEntityLists.add(tag2BlockEntity.computeIfAbsent(it, Object2ObjectFunction { _ -> BEList(it as MultiblockBuilder.EntityTag<BlockEntity>).also { blockEntityLists.add(it) } }))
|
||||||
@ -596,7 +617,10 @@ class Multiblock(
|
|||||||
private val blockStateLists = ArrayList<Reference2IntOpenHashMap<BlockState>>()
|
private val blockStateLists = ArrayList<Reference2IntOpenHashMap<BlockState>>()
|
||||||
private val blockLists = ArrayList<Object2IntOpenHashMap<Block>>()
|
private val blockLists = ArrayList<Object2IntOpenHashMap<Block>>()
|
||||||
|
|
||||||
private val parts: ImmutableSet<Part> = parts.stream().map { Part(it.pos + pos, it) }.collect(ImmutableSet.toImmutableSet())
|
private val parts: ImmutableList<Part> = parts.stream()
|
||||||
|
.map { Part(it.pos + pos, it) }
|
||||||
|
.sorted() // group/localize parts by in-world chunks to maximize getChunk() cache hit rate
|
||||||
|
.collect(ImmutableList.toImmutableList())
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
blockEntityLists.forEach { it.clear() }
|
blockEntityLists.forEach { it.clear() }
|
||||||
@ -634,13 +658,16 @@ class Multiblock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val north = Config(pos, north).also { configurations.add(it) }
|
private val north = Config(Direction.NORTH, pos, north).also { configurations.add(it) }
|
||||||
private val south = Config(pos, south).also { configurations.add(it) }
|
private val south = Config(Direction.SOUTH, pos, south).also { configurations.add(it) }
|
||||||
private val west = Config(pos, west).also { configurations.add(it) }
|
private val west = Config(Direction.WEST, pos, west).also { configurations.add(it) }
|
||||||
private val east = Config(pos, east).also { configurations.add(it) }
|
private val east = Config(Direction.EAST, pos, east).also { configurations.add(it) }
|
||||||
|
|
||||||
private var activeConfig: Config? = null
|
private var activeConfig: Config? = null
|
||||||
|
|
||||||
|
val currentDirection: Direction?
|
||||||
|
get() = activeConfig?.direction
|
||||||
|
|
||||||
fun <T : BlockEntity> blockEntities(tag: MultiblockBuilder.EntityTag<T>): Set<T> {
|
fun <T : BlockEntity> blockEntities(tag: MultiblockBuilder.EntityTag<T>): Set<T> {
|
||||||
if (!isValid) return emptySet()
|
if (!isValid) return emptySet()
|
||||||
return activeConfig?.blockEntities(tag) ?: setOf()
|
return activeConfig?.blockEntities(tag) ?: setOf()
|
||||||
@ -678,4 +705,26 @@ class Multiblock(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun update(levelAccessor: LevelAccessor, direction: Direction): Boolean {
|
||||||
|
if (activeConfig?.direction != direction) {
|
||||||
|
activeConfig?.clear()
|
||||||
|
activeConfig = null
|
||||||
|
}
|
||||||
|
|
||||||
|
val config = when (direction) {
|
||||||
|
Direction.NORTH -> north
|
||||||
|
Direction.SOUTH -> south
|
||||||
|
Direction.WEST -> west
|
||||||
|
Direction.EAST -> east
|
||||||
|
else -> throw IllegalArgumentException(direction.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid = config.update(levelAccessor)
|
||||||
|
|
||||||
|
if (isValid)
|
||||||
|
activeConfig = config
|
||||||
|
|
||||||
|
return isValid
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user