parent
ea6a237de8
commit
bd2132c06a
@ -18,7 +18,6 @@ import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraftforge.energy.IEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.*
|
||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
||||
import ru.dbotthepony.mc.otm.capability.*
|
||||
@ -33,11 +32,9 @@ import ru.dbotthepony.mc.otm.core.util.WriteOnce
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
|
||||
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import ru.dbotthepony.mc.otm.core.math.unaryMinus
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import java.lang.ref.WeakReference
|
||||
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
||||
|
||||
class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBlockEntity(MBlockEntities.CHEMICAL_GENERATOR, pos, state), IDroppableContainer {
|
||||
override val defaultDisplayName: Component
|
||||
@ -53,11 +50,13 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
get() = container
|
||||
val energy = GeneratorEnergyStorage(this::setChangedLight, CAPACITY, THROUGHPUT)
|
||||
|
||||
private val consumers = ArrayList<LazyOptional<out IEnergyStorage>>()
|
||||
private val consumers = BESubscribeList(this, ForgeCapabilities.ENERGY)
|
||||
|
||||
fun checkSurroundings() = consumers.update()
|
||||
|
||||
override fun setChangedLight() {
|
||||
super.setChangedLight()
|
||||
check = true
|
||||
checkFuelSlot = true
|
||||
}
|
||||
|
||||
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
@ -86,7 +85,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
tickOnceServer(this::checkSurroundings)
|
||||
tickOnceServer(consumers::update)
|
||||
}
|
||||
|
||||
override fun saveAdditional(nbt: CompoundTag) {
|
||||
@ -107,36 +106,6 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
workTicksTotal = nbt.getInt(WORK_TICKS_TOTAL_KEY)
|
||||
}
|
||||
|
||||
fun checkSurroundings() {
|
||||
if (!valid)
|
||||
return
|
||||
|
||||
val known = consumers.clone() as ArrayList<*>
|
||||
consumers.clear()
|
||||
val level = level ?: return
|
||||
|
||||
for (direction in Direction.values()) {
|
||||
// нельзя выталкивать энергию через перед
|
||||
if (direction == blockState.getValue(RotatableMatteryBlock.FACING))
|
||||
continue
|
||||
|
||||
val resolver = level.getBlockEntity(blockPos + direction)?.getEnergySided(-direction)
|
||||
|
||||
resolver?.ifPresentK {
|
||||
if (!known.contains(resolver)) {
|
||||
val ref = WeakReference(this)
|
||||
|
||||
resolver.addListener {
|
||||
if (SERVER_IS_LIVE)
|
||||
ref.get()?.checkSurroundings()
|
||||
}
|
||||
}
|
||||
|
||||
consumers.add(resolver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val itemHandler = container.handler(object : MatteryContainerHooks {
|
||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||
if (slot == SLOT_INPUT)
|
||||
@ -160,7 +129,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
super.setBlockState(p_155251_)
|
||||
|
||||
if (valid)
|
||||
tickOnceServer(this::checkSurroundings)
|
||||
tickOnceServer(consumers::update)
|
||||
}
|
||||
|
||||
var workTicks = 0
|
||||
@ -169,7 +138,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
var workTicksTotal = 0
|
||||
private set
|
||||
|
||||
private var check = true
|
||||
private var checkFuelSlot = true
|
||||
|
||||
private fun workWithPower(it: IEnergyStorage) {
|
||||
val extracted = energy.extractEnergy(THROUGHPUT, true)
|
||||
@ -187,7 +156,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
|
||||
if (workTicks == 0) {
|
||||
workTicksTotal = 0
|
||||
check = true
|
||||
checkFuelSlot = true
|
||||
}
|
||||
|
||||
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) {
|
||||
@ -197,7 +166,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
|
||||
}
|
||||
|
||||
if (workTicks == 0 && !isBlockedByRedstone && check) {
|
||||
if (workTicks == 0 && !isBlockedByRedstone && checkFuelSlot) {
|
||||
if (!container[SLOT_INPUT].isEmpty) {
|
||||
val ticks = ForgeHooks.getBurnTime(container[SLOT_INPUT], null)
|
||||
val residue = container[SLOT_INPUT].item.getCraftingRemainingItem(container[SLOT_INPUT].copy().also { it.count = 1 })
|
||||
@ -220,7 +189,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
}
|
||||
}
|
||||
|
||||
check = false
|
||||
checkFuelSlot = false
|
||||
}
|
||||
|
||||
if (energy.batteryLevel.isZero) return
|
||||
@ -233,7 +202,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl
|
||||
}
|
||||
|
||||
for (consumer in consumers) {
|
||||
consumer.ifPresent(this::workWithPower)
|
||||
workWithPower(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,53 @@
|
||||
package ru.dbotthepony.mc.otm.core.collect
|
||||
|
||||
import java.util.WeakHashMap
|
||||
|
||||
/**
|
||||
* Wrapper around [WeakHashMap] to behave like set
|
||||
*/
|
||||
class WeakHashSet<E : Any> : MutableSet<E> {
|
||||
private val backing = WeakHashMap<E, Unit>()
|
||||
|
||||
override fun add(element: E): Boolean {
|
||||
return backing.put(element, Unit) == null
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<E>): Boolean {
|
||||
return elements.count(::add) > 0
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
backing.clear()
|
||||
}
|
||||
|
||||
override fun iterator(): MutableIterator<E> {
|
||||
return backing.keys.iterator()
|
||||
}
|
||||
|
||||
override fun remove(element: E): Boolean {
|
||||
return backing.remove(element) != null
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<E>): Boolean {
|
||||
return backing.keys.removeAll(elements)
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<E>): Boolean {
|
||||
return backing.keys.retainAll(elements)
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = backing.size
|
||||
|
||||
override fun contains(element: E): Boolean {
|
||||
return backing.get(element) === Unit
|
||||
}
|
||||
|
||||
override fun containsAll(elements: Collection<E>): Boolean {
|
||||
return elements.all(::contains)
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return backing.isEmpty()
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.SectionPos
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
import ru.dbotthepony.mc.otm.onceServer
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.EnumMap
|
||||
import java.util.function.Predicate
|
||||
|
||||
open class BESubscribeList<T>(
|
||||
val block: BlockEntity,
|
||||
val capability: Capability<T>,
|
||||
) : Predicate<Direction>, Iterable<T> {
|
||||
private val knownCaps = WeakHashSet<LazyOptional<T>>()
|
||||
private val trackedCaps = EnumMap<Direction, WeakReference<LazyOptional<T>>>(Direction::class.java)
|
||||
|
||||
var valid = true
|
||||
set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
|
||||
if (value) {
|
||||
update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun invalidate() {
|
||||
valid = false
|
||||
}
|
||||
|
||||
fun revive() {
|
||||
valid = true
|
||||
}
|
||||
|
||||
// override
|
||||
protected open fun subscribe(direction: Direction, capability: LazyOptional<T>) {}
|
||||
// override
|
||||
protected open fun unsubscribe(direction: Direction, capability: LazyOptional<T>?) {}
|
||||
|
||||
override fun test(t: Direction): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun validate() {
|
||||
val iterator = trackedCaps.iterator()
|
||||
|
||||
for ((k, v) in iterator) {
|
||||
if (v.get() == null) {
|
||||
unsubscribe(k, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<T> {
|
||||
return object : Iterator<T> {
|
||||
val iterator = trackedCaps.iterator()
|
||||
var value: T? = null
|
||||
|
||||
private fun find() {
|
||||
while (iterator.hasNext() && value == null) {
|
||||
val (k, v) = iterator.next()
|
||||
value = v.get()?.orNull()
|
||||
|
||||
if (value == null) {
|
||||
iterator.remove()
|
||||
unsubscribe(k, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
find()
|
||||
return value != null
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
find()
|
||||
val value = value
|
||||
this.value = null
|
||||
return value ?: throw NoSuchElementException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun update() {
|
||||
if (!valid)
|
||||
return
|
||||
|
||||
val sorse = block.level?.chunkSource ?: return
|
||||
var waitChunkLoad = false
|
||||
|
||||
for (it in Direction.stream().filter(this)) {
|
||||
val pos = block.blockPos + it
|
||||
val getChunk = sorse.getChunkNow(SectionPos.blockToSectionCoord(pos.x), SectionPos.blockToSectionCoord(pos.z))
|
||||
|
||||
if (getChunk == null) {
|
||||
waitChunkLoad = true
|
||||
} else {
|
||||
val cap = getChunk.getBlockEntity(pos)?.getCapability(capability)
|
||||
val knownCap = trackedCaps[it]?.get()
|
||||
|
||||
if (cap != null && cap.isPresent) {
|
||||
if (knownCap !== cap) {
|
||||
if (knownCaps.add(cap)) {
|
||||
val ref = WeakReference(this)
|
||||
cap.addListener { ref.get()?.update() }
|
||||
}
|
||||
|
||||
trackedCaps[it] = WeakReference(cap)
|
||||
subscribe(it, cap)
|
||||
}
|
||||
} else {
|
||||
trackedCaps.remove(it)
|
||||
unsubscribe(it, knownCap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (waitChunkLoad) {
|
||||
onceServer(::update)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user