diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt index 0343c2d7d..20a66630e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt @@ -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, Any>() private val sidedCaps = Array(RelativeSide.entries.size) { - Reference2ObjectOpenHashMap, Any>() + Reference2ObjectOpenHashMap, 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(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 { + 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 exposeSided(side: RelativeSide, capability: BlockCapability, value: T) { + protected fun exposeSided(side: RelativeSide, capability: BlockCapability, 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 exposeGlobally(capability: BlockCapability, value: T, predicate: Predicate = Predicate { true }) { + protected fun exposeGlobally(capability: BlockCapability, value: T, predicate: Predicate = 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 getCapability(cap: BlockCapability, 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? diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt index 225478bd8..679f4e89b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt @@ -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 + } + } } }