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
import it.unimi.dsi.fastutil.booleans.BooleanConsumer
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
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 java.lang.ref.WeakReference
import java.util.*
import java.util.function.BooleanSupplier
import java.util.function.Consumer
import java.util.function.Predicate
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 sidedCaps = Array(RelativeSide.entries.size) {
Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>()
Reference2ObjectOpenHashMap<BlockCapability<*, *>, ControllableCapability<*>>()
}
protected val tickList = TickList()
@ -121,6 +123,68 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
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
*/
@ -132,24 +196,24 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
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]
check(!map.containsKey(capability)) { "Already has exposed $capability on $side!" }
MBlocks.ensureCapabilityIsKnown(capability)
map[capability] = value
val wrapper = ControllableCapability(value)
map[capability] = wrapper
setChanged()
level?.invalidateCapabilities(blockPos)
return wrapper
}
/**
* 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)
for (side in RelativeSide.entries)
if (predicate.test(side))
exposeSided(side, capability, value)
return ControllableCapabilitySet(RelativeSide.entries.stream().filter(predicate).map { exposeSided(it, capability, value) }.toList())
}
protected fun exposeEnergySideless(value: IMatteryEnergyStorage) {
@ -157,14 +221,22 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
exposeSideless(MatteryCapability.BLOCK_ENERGY, value)
}
protected fun exposeEnergyGlobally(value: IMatteryEnergyStorage) {
exposeGlobally(Capabilities.EnergyStorage.BLOCK, value)
exposeGlobally(MatteryCapability.BLOCK_ENERGY, value)
protected fun exposeEnergyGlobally(value: IMatteryEnergyStorage): CapabilityControl {
return ControllableCapabilitySet(
listOf(
exposeGlobally(Capabilities.EnergyStorage.BLOCK, value),
exposeGlobally(MatteryCapability.BLOCK_ENERGY, value)
)
)
}
protected fun exposeEnergySided(side: RelativeSide, value: IMatteryEnergyStorage) {
exposeSided(side, Capabilities.EnergyStorage.BLOCK, value)
exposeSided(side, MatteryCapability.BLOCK_ENERGY, value)
protected fun exposeEnergySided(side: RelativeSide, value: IMatteryEnergyStorage): CapabilityControl {
return ControllableCapabilitySet(
listOf(
exposeSided(side, Capabilities.EnergyStorage.BLOCK, value),
exposeSided(side, MatteryCapability.BLOCK_ENERGY, value)
)
)
}
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? {
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?

View File

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