Reimplement "open/close" capability state
This commit is contained in:
parent
9fb57259bd
commit
5a6a88e65b
@ -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?
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user