Reimplement "open/close" capability state

This commit is contained in:
DBotThePony 2024-08-30 19:01:07 +07:00
parent 9fb57259bd
commit 5a6a88e65b
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 110 additions and 29 deletions

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity package ru.dbotthepony.mc.otm.block.entity
import it.unimi.dsi.fastutil.booleans.BooleanConsumer
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
@ -57,6 +58,7 @@ import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.sometimeServer import ru.dbotthepony.mc.otm.sometimeServer
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
import java.util.function.BooleanSupplier
import java.util.function.Consumer import java.util.function.Consumer
import java.util.function.Predicate import java.util.function.Predicate
import java.util.function.Supplier import java.util.function.Supplier
@ -71,7 +73,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
private val sidelessCaps = Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>() private val sidelessCaps = Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>()
private val sidedCaps = Array(RelativeSide.entries.size) { private val sidedCaps = Array(RelativeSide.entries.size) {
Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>() Reference2ObjectOpenHashMap<BlockCapability<*, *>, ControllableCapability<*>>()
} }
protected val tickList = TickList() protected val tickList = TickList()
@ -121,6 +123,68 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
tickList.tick() tickList.tick()
} }
interface CapabilityControl : BooleanSupplier, BooleanConsumer {
var isEnabled: Boolean
fun doDispatchInvalidation()
fun dontDispatchInvalidation()
override fun getAsBoolean(): Boolean {
return isEnabled
}
override fun accept(t: Boolean) {
isEnabled = t
}
}
private inner class ControllableCapability<T : Any>(val capability: T) : CapabilityControl {
override var isEnabled: Boolean = true
set(value) {
if (value != field) {
field = value
if (dispatchInvalidation) level?.invalidateCapabilities(blockPos)
}
}
private var dispatchInvalidation = true
override fun doDispatchInvalidation() {
dispatchInvalidation = true
}
override fun dontDispatchInvalidation() {
dispatchInvalidation = false
}
fun getOrNull(): T? {
return if (isEnabled) capability else null
}
}
private inner class ControllableCapabilitySet(val capabilities: List<CapabilityControl>) : CapabilityControl {
override var isEnabled: Boolean
get() = capabilities.all { it.isEnabled }
set(value) {
capabilities.forEach { it.dontDispatchInvalidation() }
try {
capabilities.forEach { it.isEnabled = value }
} finally {
capabilities.forEach { it.doDispatchInvalidation() }
level?.invalidateCapabilities(blockPos)
}
}
override fun doDispatchInvalidation() {
capabilities.forEach { it.doDispatchInvalidation() }
}
override fun dontDispatchInvalidation() {
capabilities.forEach { it.dontDispatchInvalidation() }
}
}
/** /**
* exposes capability when no side is specified * exposes capability when no side is specified
*/ */
@ -132,24 +196,24 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
level?.invalidateCapabilities(blockPos) level?.invalidateCapabilities(blockPos)
} }
protected fun <T : Any> exposeSided(side: RelativeSide, capability: BlockCapability<T, *>, value: T) { protected fun <T : Any> exposeSided(side: RelativeSide, capability: BlockCapability<T, *>, value: T): CapabilityControl {
val map = sidedCaps[side.ordinal] val map = sidedCaps[side.ordinal]
check(!map.containsKey(capability)) { "Already has exposed $capability on $side!" } check(!map.containsKey(capability)) { "Already has exposed $capability on $side!" }
MBlocks.ensureCapabilityIsKnown(capability) MBlocks.ensureCapabilityIsKnown(capability)
map[capability] = value val wrapper = ControllableCapability(value)
map[capability] = wrapper
setChanged() setChanged()
level?.invalidateCapabilities(blockPos) level?.invalidateCapabilities(blockPos)
return wrapper
} }
/** /**
* Exposes capability unconditionally, on all sides and sideless * Exposes capability unconditionally, on all sides and sideless
*/ */
protected fun <T : Any> exposeGlobally(capability: BlockCapability<T, *>, value: T, predicate: Predicate<RelativeSide> = Predicate { true }) { protected fun <T : Any> exposeGlobally(capability: BlockCapability<T, *>, value: T, predicate: Predicate<RelativeSide> = Predicate { true }): CapabilityControl {
exposeSideless(capability, value) exposeSideless(capability, value)
for (side in RelativeSide.entries) return ControllableCapabilitySet(RelativeSide.entries.stream().filter(predicate).map { exposeSided(it, capability, value) }.toList())
if (predicate.test(side))
exposeSided(side, capability, value)
} }
protected fun exposeEnergySideless(value: IMatteryEnergyStorage) { protected fun exposeEnergySideless(value: IMatteryEnergyStorage) {
@ -157,14 +221,22 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
exposeSideless(MatteryCapability.BLOCK_ENERGY, value) exposeSideless(MatteryCapability.BLOCK_ENERGY, value)
} }
protected fun exposeEnergyGlobally(value: IMatteryEnergyStorage) { protected fun exposeEnergyGlobally(value: IMatteryEnergyStorage): CapabilityControl {
exposeGlobally(Capabilities.EnergyStorage.BLOCK, value) return ControllableCapabilitySet(
exposeGlobally(MatteryCapability.BLOCK_ENERGY, value) listOf(
exposeGlobally(Capabilities.EnergyStorage.BLOCK, value),
exposeGlobally(MatteryCapability.BLOCK_ENERGY, value)
)
)
} }
protected fun exposeEnergySided(side: RelativeSide, value: IMatteryEnergyStorage) { protected fun exposeEnergySided(side: RelativeSide, value: IMatteryEnergyStorage): CapabilityControl {
exposeSided(side, Capabilities.EnergyStorage.BLOCK, value) return ControllableCapabilitySet(
exposeSided(side, MatteryCapability.BLOCK_ENERGY, value) listOf(
exposeSided(side, Capabilities.EnergyStorage.BLOCK, value),
exposeSided(side, MatteryCapability.BLOCK_ENERGY, value)
)
)
} }
protected fun waitForServerLevel(lambda: () -> Unit) { protected fun waitForServerLevel(lambda: () -> Unit) {
@ -177,7 +249,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
fun <T : Any> getCapability(cap: BlockCapability<T, *>, side: Direction?): T? { fun <T : Any> getCapability(cap: BlockCapability<T, *>, side: Direction?): T? {
if (side != null) { if (side != null) {
return sidedCaps[blockRotation.dir2Side(side).ordinal][cap] as T? return sidedCaps[blockRotation.dir2Side(side).ordinal][cap]?.getOrNull() as T?
} }
return sidelessCaps[cap] as T? return sidelessCaps[cap] as T?

View File

@ -147,10 +147,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
inner class Piece(val side: RelativeSide) : IFluidHandler, ITickable { inner class Piece(val side: RelativeSide) : IFluidHandler, ITickable {
private val ticker = tickList.Ticker(this) private val ticker = tickList.Ticker(this)
private val neighbour = CapabilityCache(side, Capabilities.FluidHandler.BLOCK) private val neighbour = CapabilityCache(side, Capabilities.FluidHandler.BLOCK)
private val control = exposeSided(side, Capabilities.FluidHandler.BLOCK, this)
init {
exposeSided(side, Capabilities.FluidHandler.BLOCK, this)
}
private fun updateTickerState() { private fun updateTickerState() {
ticker.isEnabled = ticker.isEnabled =
@ -174,7 +171,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
access.accept(value) access.accept(value)
markDirtyFast() markDirtyFast()
updateTickerState() updateTickerState()
level?.invalidateCapabilities(blockPos) control.isEnabled = value != FlowDirection.NONE
} }
}) })
@ -273,6 +270,12 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
return FluidStack.EMPTY return FluidStack.EMPTY
} }
} }
init {
if (flow == FlowDirection.NONE) {
control.isEnabled = false
}
}
} }
} }
@ -350,10 +353,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
inner class Piece(val side: RelativeSide, val possibleModes: FlowDirection) : IMatteryEnergyStorage, ITickable { inner class Piece(val side: RelativeSide, val possibleModes: FlowDirection) : IMatteryEnergyStorage, ITickable {
private val neighbour = CapabilityCache(side, Capabilities.EnergyStorage.BLOCK) private val neighbour = CapabilityCache(side, Capabilities.EnergyStorage.BLOCK)
private val control = exposeEnergySided(side, this)
init {
exposeEnergySided(side, this)
}
override var batteryLevel: Decimal by energy::batteryLevel override var batteryLevel: Decimal by energy::batteryLevel
override val maxBatteryLevel: Decimal by energy::maxBatteryLevel override val maxBatteryLevel: Decimal by energy::maxBatteryLevel
@ -453,9 +453,15 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
access.accept(value) access.accept(value)
markDirtyFast() markDirtyFast()
updateTickerState() updateTickerState()
level?.invalidateCapabilities(blockPos) control.isEnabled = value != FlowDirection.NONE
} }
}).delegate }).delegate
init {
if (energyFlow == FlowDirection.NONE) {
control.isEnabled = false
}
}
} }
} }
@ -566,10 +572,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
private val neighbour = CapabilityCache(side, Capabilities.ItemHandler.BLOCK) private val neighbour = CapabilityCache(side, Capabilities.ItemHandler.BLOCK)
private val ticker = tickList.Ticker(this) private val ticker = tickList.Ticker(this)
private val control = exposeSided(side, Capabilities.ItemHandler.BLOCK, this)
init {
exposeSided(side, Capabilities.ItemHandler.BLOCK, this)
}
private var innerSlotPull = 0 private var innerSlotPull = 0
private var outerSlotPull = 0 private var outerSlotPull = 0
@ -601,7 +604,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
ItemHandlerMode.BATTERY -> battery!! ItemHandlerMode.BATTERY -> battery!!
} }
level?.invalidateCapabilities(blockPos) control.isEnabled = value != ItemHandlerMode.DISABLED
} }
}).delegate }).delegate
@ -705,6 +708,12 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
override fun isItemValid(slot: Int, stack: ItemStack): Boolean { override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
return currentHandler.isItemValid(slot, stack) return currentHandler.isItemValid(slot, stack)
} }
init {
if (mode == ItemHandlerMode.DISABLED) {
control.isEnabled = false
}
}
} }
} }