Capability subscriptions embedded into MatteryBlockEntity.Side
This commit is contained in:
parent
aab9e09e30
commit
d8648d7088
@ -23,7 +23,9 @@ import net.minecraft.world.level.material.Material
|
||||
import net.minecraft.world.level.material.MaterialColor
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
||||
import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||
import ru.dbotthepony.mc.otm.core.get
|
||||
@ -97,6 +99,7 @@ abstract class MatteryBlock @JvmOverloads constructor(
|
||||
if (this is EntityBlock && level.isClientSide)
|
||||
return InteractionResult.SUCCESS
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
|
||||
}
|
||||
|
||||
@ -167,6 +170,7 @@ abstract class MatteryBlock @JvmOverloads constructor(
|
||||
neighbourPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
@Suppress("DEPRECATION")
|
||||
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
|
||||
|
||||
if (this is EntityBlock && !level.isClientSide) {
|
||||
@ -174,6 +178,9 @@ abstract class MatteryBlock @JvmOverloads constructor(
|
||||
|
||||
if (tile is IRedstoneControlled)
|
||||
tile.redstoneControl.redstoneSignal = level.getBestNeighborSignal(pos)
|
||||
|
||||
if (tile is MatteryBlockEntity && SERVER_IS_LIVE)
|
||||
tile.neighborChanged(neighbour, neighbourPos, movedByPiston)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||
@ -9,10 +10,8 @@ import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.SectionPos
|
||||
import net.minecraft.nbt.ByteTag
|
||||
import net.minecraft.core.Vec3i
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.DoubleTag
|
||||
import net.minecraft.nbt.FloatTag
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@ -20,6 +19,7 @@ import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.level.ChunkPos
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
||||
@ -41,25 +41,30 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||
import ru.dbotthepony.mc.otm.core.collect.SupplierList
|
||||
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
|
||||
import ru.dbotthepony.mc.otm.core.forValidRefs
|
||||
import ru.dbotthepony.mc.otm.core.forValidRefsBreak
|
||||
import ru.dbotthepony.mc.otm.core.get
|
||||
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
import ru.dbotthepony.mc.otm.core.math.minus
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.EnumValueCodec
|
||||
import ru.dbotthepony.mc.otm.core.util.Savetables
|
||||
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
|
||||
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
||||
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.once
|
||||
import ru.dbotthepony.mc.otm.oncePre
|
||||
import ru.dbotthepony.mc.otm.onceServer
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.Collections
|
||||
import java.util.EnumMap
|
||||
import java.util.WeakHashMap
|
||||
import java.util.function.Supplier
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
@ -155,6 +160,11 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
exposeGlobally(ForgeCapabilities.ITEM_HANDLER, value)
|
||||
}
|
||||
|
||||
@Suppress("SuspiciousCallableReferenceInLambda")
|
||||
protected fun <T> trackGlobally(capability: Capability<T>): List<LazyOptional<T>> {
|
||||
return SupplierList(_sides.values.map { it.track(capability)::get })
|
||||
}
|
||||
|
||||
enum class SideMode(val filter: FlowDirection, val automation: FlowDirection) {
|
||||
DISABLED (FlowDirection.NONE, FlowDirection.NONE),
|
||||
NONE (FlowDirection.BI_DIRECTIONAL, FlowDirection.NONE),
|
||||
@ -197,6 +207,81 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
private val caps = Reference2ObjectArrayMap<Capability<*>, Cap<*>>()
|
||||
private val modeStates = Object2ObjectArrayMap<String, ModeState>()
|
||||
private val data = Object2ObjectArrayMap<ResourceLocation, INBTSerializable<Tag>>()
|
||||
private val subscriptions = Reference2ObjectArrayMap<Capability<*>, SubRef<*>>()
|
||||
private val knownLOs = WeakHashSet<LazyOptional<*>>()
|
||||
|
||||
private inner class SubRef<T>(var value: LazyOptional<T>) : Supplier<LazyOptional<T>> {
|
||||
override fun get(): LazyOptional<T> {
|
||||
return value
|
||||
}
|
||||
|
||||
fun unset() {
|
||||
value = LazyOptional.empty()
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> track(capability: Capability<T>): Supplier<LazyOptional<T>> {
|
||||
var subref = subscriptions[capability] as Supplier<LazyOptional<T>>?
|
||||
|
||||
if (subref == null) {
|
||||
subref = SubRef(LazyOptional.empty<Any?>()) as SubRef<T>
|
||||
subscriptions[capability] = subref
|
||||
level?.once { updateTracked(capability) }
|
||||
}
|
||||
|
||||
return subref
|
||||
}
|
||||
|
||||
fun updateTracked() {
|
||||
for (key in subscriptions.keys) {
|
||||
// Concurrent Modification safety:
|
||||
// we do not add nor remove keys from map, we only update values
|
||||
updateTracked(key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTracked(capability: Capability<*>) {
|
||||
if (isRemoved) return
|
||||
val dir = blockRotation.side2Dir(side)
|
||||
|
||||
val chunk = level
|
||||
?.chunkSource
|
||||
?.getChunkNow(SectionPos.blockToSectionCoord(blockPos.x), SectionPos.blockToSectionCoord(blockPos.z))
|
||||
|
||||
if (chunk == null) {
|
||||
subscriptions[capability]!!.unset()
|
||||
level?.once { updateTracked(capability) }
|
||||
return
|
||||
}
|
||||
|
||||
val entity = chunk.getBlockEntity(blockPos + dir.normal)
|
||||
|
||||
if (entity == null) {
|
||||
subscriptions[capability]!!.unset()
|
||||
return
|
||||
}
|
||||
|
||||
val new = entity.getCapability(capability, dir.opposite)
|
||||
|
||||
if (!new.isPresent) {
|
||||
subscriptions[capability]!!.unset()
|
||||
return
|
||||
}
|
||||
|
||||
val subref = subscriptions[capability] as SubRef<Any?>
|
||||
|
||||
if (subref.value !== new) {
|
||||
if (knownLOs.add(new)) {
|
||||
val ref = WeakReference(this)
|
||||
|
||||
new.addListener {
|
||||
ref.get()?.updateTracked(capability)
|
||||
}
|
||||
}
|
||||
|
||||
subref.value = new as LazyOptional<Any?>
|
||||
}
|
||||
}
|
||||
|
||||
val isEmpty get() = caps.isEmpty() && modeStates.isEmpty()
|
||||
|
||||
@ -453,6 +538,30 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
savetables.deserializeNBT(nbt)
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
override fun setBlockState(pBlockState: BlockState) {
|
||||
val old = blockRotation
|
||||
@Suppress("DEPRECATION")
|
||||
super.setBlockState(pBlockState)
|
||||
val new = blockRotation
|
||||
|
||||
if (old != new) {
|
||||
for (side in _sides.values) {
|
||||
side.updateTracked()
|
||||
side.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
for (side in _sides.values) {
|
||||
side.revive()
|
||||
}
|
||||
}
|
||||
|
||||
fun neighborChanged(neighbour: Block, neighbourPos: BlockPos, movedByPiston: Boolean) {
|
||||
val dir = vec2Dir[vecKey(neighbourPos - blockPos)] ?: return
|
||||
_sides[blockRotation.dir2Side(dir)]!!.updateTracked()
|
||||
}
|
||||
|
||||
protected fun tickOnce(func: Runnable) {
|
||||
level?.oncePre { if (!isRemoved) func.run() }
|
||||
}
|
||||
@ -511,13 +620,31 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
synchronizer.defaultEndpoint.markUnused()
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
val old = this.level
|
||||
super.setLevel(level)
|
||||
unsubscribe()
|
||||
_subCache = null
|
||||
|
||||
if (!p_155231_.isClientSide) {
|
||||
if (!level.isClientSide) {
|
||||
subscribe()
|
||||
|
||||
if (old != null) {
|
||||
for (side in _sides.values) {
|
||||
side.updateTracked()
|
||||
side.invalidate()
|
||||
}
|
||||
|
||||
for (side in _sides.values) {
|
||||
side.revive()
|
||||
}
|
||||
} else {
|
||||
level.once {
|
||||
for (side in _sides.values) {
|
||||
side.updateTracked()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -751,6 +878,24 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
private val playerMap = WeakHashMap<ServerLevel, Long2ObjectOpenHashMap<ChunkSubscribers>>()
|
||||
private val tickingMap = WeakHashMap<ServerLevel, ArrayList<WeakReference<ChunkSubscribers>>>()
|
||||
|
||||
private val vec2Dir = Int2ObjectOpenHashMap<Direction>()
|
||||
|
||||
private fun vecKey(value: Vec3i): Int {
|
||||
if (value.x !in -1 .. 1) return -1
|
||||
if (value.y !in -1 .. 1) return -1
|
||||
if (value.z !in -1 .. 1) return -1
|
||||
val x = if (value.x < 0) 2 else value.x
|
||||
val y = if (value.y < 0) 2 else value.y
|
||||
val z = if (value.z < 0) 2 else value.z
|
||||
return x or (y shl 4) or (z shl 8)
|
||||
}
|
||||
|
||||
init {
|
||||
for (dir in Direction.values()) {
|
||||
vec2Dir[vecKey(dir.normal)] = dir
|
||||
}
|
||||
}
|
||||
|
||||
fun onLevelUnload(event: LevelEvent.Unload) {
|
||||
val level = event.level as? ServerLevel ?: return
|
||||
playerMap.remove(level)
|
||||
|
@ -85,8 +85,8 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery
|
||||
|
||||
private var sleepTicks = 4
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
sleepTicks = 4
|
||||
}
|
||||
|
||||
|
@ -133,10 +133,10 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
return matter
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,13 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.matter
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity
|
||||
@ -30,8 +23,6 @@ import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
|
||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
|
||||
import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
|
||||
class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterGraphNode, IMatterStorage, IDroppableContainer {
|
||||
var gaugeLevel by synchronizer.float()
|
||||
@ -161,10 +152,10 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
|
||||
matterNode.destroy(::MatterNetworkGraph)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
|
@ -204,10 +204,10 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
|
||||
matterNode.destroy(::MatterNetworkGraph)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.matter
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.menu.matter.MatterPanelMenu
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import java.util.HashMap
|
||||
import java.util.UUID
|
||||
@ -17,7 +15,6 @@ import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||
@ -54,10 +51,10 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
exposeGlobally(MatteryCapability.TASK, this)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
|
@ -106,10 +106,10 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
matterNode.destroy(::MatterNetworkGraph)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.ContainerHandler
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
||||
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
|
||||
@ -164,10 +163,10 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
matterNode.destroy(::MatterNetworkGraph)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
|
@ -169,10 +169,10 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
return null to IdleReason.ITEM
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel) {
|
||||
if (level is ServerLevel) {
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
}
|
||||
|
@ -8,20 +8,14 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import ru.dbotthepony.mc.otm.menu.matter.PatternStorageMenu
|
||||
import net.minecraft.MethodsReturnNonnullByDefault
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.matter.*
|
||||
@ -29,9 +23,7 @@ import ru.dbotthepony.mc.otm.core.collect.iterator
|
||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
||||
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
|
||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import java.util.ArrayList
|
||||
import java.util.stream.Stream
|
||||
|
||||
@ -90,10 +82,10 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
private val itemHandler = container.handler { slot: Int, stack: ItemStack -> stack.getCapability(MatteryCapability.PATTERN).isPresent }
|
||||
override val droppableContainer by ::container
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
MatterNetworkGraph.discoverFull(this, matterNode)
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.storage
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@ -11,9 +8,6 @@ import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import ru.dbotthepony.mc.otm.config.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
|
||||
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
@ -21,11 +15,8 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.registry.MBlocks
|
||||
import ru.dbotthepony.mc.otm.storage.*
|
||||
|
||||
class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
@ -59,10 +50,10 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
exposeGlobally(MatteryCapability.STORAGE_NODE, cell)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
StorageNetworkGraph.discoverFull(this, cell.storageNode)
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.storage
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.NonNullList
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
@ -20,12 +19,9 @@ import net.minecraft.world.item.crafting.RecipeType
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.ForgeHooks
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.config.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
@ -42,7 +38,6 @@ import ru.dbotthepony.mc.otm.container.set
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getEnum
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.menu.storage.ItemMonitorMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlocks
|
||||
import ru.dbotthepony.mc.otm.storage.*
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
@ -501,10 +496,10 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
return ItemMonitorMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel)
|
||||
if (level is ServerLevel)
|
||||
StorageNetworkGraph.discoverFull(this, cell.storageNode)
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
|
||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
@ -14,7 +13,6 @@ import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraftforge.items.IItemHandler
|
||||
@ -25,7 +23,6 @@ import ru.dbotthepony.mc.otm.block.entity.storage.AbstractStorageImportExport.Co
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.config.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
|
||||
@ -34,8 +31,6 @@ import ru.dbotthepony.mc.otm.core.math.getCapability
|
||||
import ru.dbotthepony.mc.otm.core.math.isPositive
|
||||
import ru.dbotthepony.mc.otm.core.math.isZero
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
||||
import ru.dbotthepony.mc.otm.graph.GraphNodeListener
|
||||
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
|
||||
@ -115,10 +110,10 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
||||
savetable(::filter, FILTER_KEY)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel) {
|
||||
if (level is ServerLevel) {
|
||||
StorageNetworkGraph.discoverFull(this, cell.storageNode)
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.storage
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
@ -15,28 +14,22 @@ import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraftforge.items.IItemHandler
|
||||
import ru.dbotthepony.mc.otm.*
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
||||
import ru.dbotthepony.mc.otm.block.CableBlock
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
|
||||
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
|
||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||
import ru.dbotthepony.mc.otm.config.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
import ru.dbotthepony.mc.otm.core.math.rotationTwo
|
||||
import ru.dbotthepony.mc.otm.core.math.toIntSafe
|
||||
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 ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
import ru.dbotthepony.mc.otm.graph.Graph6Node
|
||||
import ru.dbotthepony.mc.otm.graph.GraphNodeListener
|
||||
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
|
||||
@ -45,11 +38,15 @@ import ru.dbotthepony.mc.otm.menu.storage.StorageExporterMenu
|
||||
import ru.dbotthepony.mc.otm.menu.storage.StorageImporterMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.registry.MNames
|
||||
import ru.dbotthepony.mc.otm.storage.*
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageEventConsumer
|
||||
import ru.dbotthepony.mc.otm.storage.IStorageProvider
|
||||
import ru.dbotthepony.mc.otm.storage.ITEM_STORAGE
|
||||
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
|
||||
import ru.dbotthepony.mc.otm.storage.StorageStackType
|
||||
import ru.dbotthepony.mc.otm.storage.addStack
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
import java.util.stream.Stream
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
abstract class AbstractStorageImportExport<T>(
|
||||
blockType: BlockEntityType<*>,
|
||||
@ -85,42 +82,23 @@ abstract class AbstractStorageImportExport<T>(
|
||||
exposeAllSidesExcept(RelativeSide.FRONT, MatteryCapability.STORAGE_NODE, cell)
|
||||
}
|
||||
|
||||
override fun invalidateCaps() {
|
||||
super.invalidateCaps()
|
||||
target.invalidate()
|
||||
}
|
||||
|
||||
override fun reviveCaps() {
|
||||
super.reviveCaps()
|
||||
target.revive()
|
||||
}
|
||||
|
||||
override fun setRemoved() {
|
||||
super.setRemoved()
|
||||
cell.destroy(level)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel) {
|
||||
if (level is ServerLevel) {
|
||||
StorageNetworkGraph.discoverFull(this, cell.storageNode)
|
||||
tickOnceServer(this::checkSurroundings)
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract val targetCapability: Capability<T>
|
||||
|
||||
protected val target by lazy {
|
||||
object : BESubscribeList<T>(this@AbstractStorageImportExport, targetCapability) {
|
||||
override fun test(t: Direction): Boolean {
|
||||
return t == -this@AbstractStorageImportExport.blockState.getValue(BlockRotationFreedom.TWO.property).front
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkSurroundings() {
|
||||
target.update()
|
||||
front.track(targetCapability)
|
||||
}
|
||||
|
||||
abstract val filter: ItemFilter
|
||||
@ -206,7 +184,7 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState)
|
||||
|
||||
nextTick--
|
||||
|
||||
val target = target.firstOrNull()
|
||||
val target = target.get().orNull()
|
||||
|
||||
if (nextTick <= 0 && target != null && enoughEnergy) {
|
||||
val graph = cell.storageGraph ?: return
|
||||
@ -318,7 +296,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
|
||||
|
||||
nextTick--
|
||||
|
||||
val target = target.firstOrNull()
|
||||
val target = target.get().orNull()
|
||||
|
||||
if (nextTick <= 0 && target != null && enoughEnergy) {
|
||||
val graph = cell.storageGraph ?: return
|
||||
|
@ -1,20 +1,12 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.storage
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.config.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
||||
@ -25,9 +17,6 @@ import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
|
||||
import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph
|
||||
import ru.dbotthepony.mc.otm.menu.storage.StoragePowerSupplierMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.registry.MNames
|
||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
|
||||
class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_POWER_SUPPLIER, blockPos, blockState) {
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
@ -51,10 +40,10 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState
|
||||
savetables.decimal(::powerPassed, POWER_PASSED_KEY)
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
|
||||
if (p_155231_ is ServerLevel) {
|
||||
if (level is ServerLevel) {
|
||||
StorageNetworkGraph.discoverFull(this, cell.storageNode)
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,28 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.energy.IEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.block.IDroppableContainer
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.capability.energy
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.capability.energyStoredMattery
|
||||
import ru.dbotthepony.mc.otm.capability.extractEnergy
|
||||
import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery
|
||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.core.ImmutableList
|
||||
import ru.dbotthepony.mc.otm.core.getValue
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
import ru.dbotthepony.mc.otm.core.math.facingOne
|
||||
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
||||
import ru.dbotthepony.mc.otm.menu.tech.BatteryBankMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
|
||||
@ -202,28 +204,17 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
|
||||
}
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
checkSurroundings()
|
||||
}
|
||||
|
||||
private val consumers = object : BESubscribeList<IEnergyStorage>(this@BatteryBankBlockEntity, ForgeCapabilities.ENERGY) {
|
||||
override fun test(t: Direction): Boolean {
|
||||
return blockState.facingOne == t
|
||||
}
|
||||
}
|
||||
|
||||
fun checkSurroundings() = consumers.update(blockState.facingOne::equals)
|
||||
private val consumers by front.track(ForgeCapabilities.ENERGY)
|
||||
|
||||
fun tick() {
|
||||
if (redstoneControl.isBlockedByRedstone)
|
||||
return
|
||||
|
||||
for (it in consumers) {
|
||||
consumers.ifPresentK {
|
||||
val (_, maxThroughput) = energy.getDistribution(false)
|
||||
|
||||
if (maxThroughput.isZero)
|
||||
continue
|
||||
return@ifPresentK
|
||||
|
||||
val diff = it.receiveEnergy(maxThroughput, true)
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.ForgeConfigSpec
|
||||
@ -18,7 +16,6 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.WorkerState
|
||||
import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
@ -29,9 +26,6 @@ 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.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
||||
|
||||
class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.CHEMICAL_GENERATOR, pos, state), IDroppableContainer {
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
@ -66,41 +60,18 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
||||
savetable(::container, INVENTORY_KEY)
|
||||
exposeEnergyGlobally(energy)
|
||||
exposeItemsGlobally(itemHandler)
|
||||
|
||||
savetables.int(::workTicks, WORK_TICKS_KEY)
|
||||
savetables.int(::workTicksTotal, WORK_TICKS_TOTAL_KEY)
|
||||
}
|
||||
|
||||
private val consumers = BESubscribeList(this, ForgeCapabilities.ENERGY)
|
||||
|
||||
fun checkSurroundings() = consumers.update()
|
||||
private val consumers = trackGlobally(ForgeCapabilities.ENERGY)
|
||||
|
||||
override fun setChangedLight() {
|
||||
super.setChangedLight()
|
||||
checkFuelSlot = true
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
tickOnceServer(consumers::update)
|
||||
}
|
||||
|
||||
override fun saveAdditional(nbt: CompoundTag) {
|
||||
super.saveAdditional(nbt)
|
||||
|
||||
nbt[WORK_TICKS_KEY] = workTicks
|
||||
nbt[WORK_TICKS_TOTAL_KEY] = workTicksTotal
|
||||
}
|
||||
|
||||
override fun load(nbt: CompoundTag) {
|
||||
super.load(nbt)
|
||||
|
||||
workTicks = nbt.getInt(WORK_TICKS_KEY)
|
||||
workTicksTotal = nbt.getInt(WORK_TICKS_TOTAL_KEY)
|
||||
}
|
||||
|
||||
override fun setBlockState(p_155251_: BlockState) {
|
||||
super.setBlockState(p_155251_)
|
||||
tickOnceServer(consumers::update)
|
||||
}
|
||||
|
||||
var workTicks = 0
|
||||
private set
|
||||
|
||||
@ -171,7 +142,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
||||
}
|
||||
|
||||
for (consumer in consumers) {
|
||||
workWithPower(consumer)
|
||||
consumer.ifPresentK(::workWithPower)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.tech
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.IntTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
@ -9,26 +8,21 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
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.block.tech.EnergyCounterBlock
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.getDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.unaryMinus
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getByteArrayList
|
||||
import ru.dbotthepony.mc.otm.core.nbt.ifHas
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.BESubscribeList
|
||||
import ru.dbotthepony.mc.otm.menu.tech.EnergyCounterMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import java.util.*
|
||||
@ -36,6 +30,10 @@ import java.util.*
|
||||
class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
||||
var passed by synchronizer.fraction()
|
||||
|
||||
override val blockRotation: BlockRotation get() {
|
||||
return BlockRotation.of(blockState[EnergyCounterBlock.INPUT_DIRECTION])
|
||||
}
|
||||
|
||||
private val history = Array(10 * 20) { Decimal.ZERO }
|
||||
internal var historyTick = 0
|
||||
|
||||
@ -124,22 +122,8 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
private val energyInput = EnergyCounterCap(true)
|
||||
private val energyOutput = EnergyCounterCap(false)
|
||||
|
||||
private val inputCapability = object : BESubscribeList<IEnergyStorage>(this@EnergyCounterBlockEntity, ForgeCapabilities.ENERGY) {
|
||||
override fun test(t: Direction): Boolean {
|
||||
return t == blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION)
|
||||
}
|
||||
}
|
||||
|
||||
private val outputCapability = object : BESubscribeList<IEnergyStorage>(this@EnergyCounterBlockEntity, ForgeCapabilities.ENERGY) {
|
||||
override fun test(t: Direction): Boolean {
|
||||
return t == -blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setLevel(p_155231_: Level) {
|
||||
super.setLevel(p_155231_)
|
||||
tickOnceServer(this::checkSurroundings)
|
||||
}
|
||||
private val inputCapability by front.track(ForgeCapabilities.ENERGY)
|
||||
private val outputCapability by back.track(ForgeCapabilities.ENERGY)
|
||||
|
||||
private inner class EnergyCounterCap(isInput: Boolean) : IMatteryEnergyStorage {
|
||||
override val energyFlow = FlowDirection.input(isInput)
|
||||
@ -148,7 +132,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
if (redstoneControl.isBlockedByRedstone)
|
||||
return Decimal.ZERO
|
||||
|
||||
val it = inputCapability.first
|
||||
val it = inputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
val diff: Decimal
|
||||
@ -176,7 +160,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
if (redstoneControl.isBlockedByRedstone)
|
||||
return Decimal.ZERO
|
||||
|
||||
val it = outputCapability.first
|
||||
val it = outputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
val diff: Decimal
|
||||
@ -206,7 +190,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
override var batteryLevel: Decimal
|
||||
get() {
|
||||
if (energyFlow.input) {
|
||||
val it = outputCapability.first
|
||||
val it = outputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
@ -216,7 +200,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
return Decimal(it.energyStored)
|
||||
}
|
||||
} else {
|
||||
val it = inputCapability.first
|
||||
val it = inputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
@ -236,7 +220,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
override val maxBatteryLevel: Decimal
|
||||
get() {
|
||||
if (energyFlow.input) {
|
||||
val it = outputCapability.first
|
||||
val it = outputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
@ -246,7 +230,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
return Decimal(it.maxEnergyStored)
|
||||
}
|
||||
} else {
|
||||
val it = inputCapability.first
|
||||
val it = inputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
@ -263,7 +247,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
override val missingPower: Decimal
|
||||
get() {
|
||||
if (energyFlow.input) {
|
||||
val it = outputCapability.first
|
||||
val it = outputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
@ -273,7 +257,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
return Decimal((it.maxEnergyStored - it.energyStored).coerceAtLeast(0))
|
||||
}
|
||||
} else {
|
||||
val it = inputCapability.first
|
||||
val it = inputCapability.orNull()
|
||||
|
||||
if (it != null) {
|
||||
if (it is IMatteryEnergyStorage) {
|
||||
@ -288,86 +272,19 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
}
|
||||
}
|
||||
|
||||
private var resolverInput = LazyOptional.of<IMatteryEnergyStorage> { energyInput }
|
||||
private var resolverOutput = LazyOptional.of<IMatteryEnergyStorage> { energyOutput }
|
||||
init {
|
||||
front.Cap(ForgeCapabilities.ENERGY, energyInput)
|
||||
front.Cap(MatteryCapability.ENERGY, energyInput)
|
||||
|
||||
private var resolverInputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } else null
|
||||
private var resolverOutputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyOutput) } else null
|
||||
|
||||
private var valid = true
|
||||
|
||||
override fun invalidateCaps() {
|
||||
super.invalidateCaps()
|
||||
valid = false
|
||||
resolverInput.invalidate()
|
||||
resolverInputMekanism?.invalidate()
|
||||
resolverOutput.invalidate()
|
||||
resolverOutputMekanism?.invalidate()
|
||||
}
|
||||
|
||||
override fun reviveCaps() {
|
||||
super.reviveCaps()
|
||||
valid = true
|
||||
resolverInput = LazyOptional.of { energyInput }
|
||||
resolverOutput = LazyOptional.of { energyOutput }
|
||||
back.Cap(ForgeCapabilities.ENERGY, energyOutput)
|
||||
back.Cap(MatteryCapability.ENERGY, energyOutput)
|
||||
|
||||
if (isMekanismLoaded) {
|
||||
resolverInputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) }
|
||||
resolverOutputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyOutput) }
|
||||
front.Cap(MatteryCapability.MEKANISM_ENERGY, Mattery2MekanismEnergyWrapper(energyInput))
|
||||
back.Cap(MatteryCapability.MEKANISM_ENERGY, Mattery2MekanismEnergyWrapper(energyOutput))
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("deprecation", "OVERRIDE_DEPRECATION")
|
||||
override fun setBlockState(new: BlockState) {
|
||||
val old = blockState
|
||||
super.setBlockState(new)
|
||||
|
||||
if (new !== old && new.getValue(EnergyCounterBlock.INPUT_DIRECTION) != old.getValue(EnergyCounterBlock.INPUT_DIRECTION)) {
|
||||
resolverInput.invalidate()
|
||||
resolverInputMekanism?.invalidate()
|
||||
resolverOutput.invalidate()
|
||||
resolverOutputMekanism?.invalidate()
|
||||
|
||||
resolverInput = LazyOptional.of { energyInput }
|
||||
resolverOutput = LazyOptional.of { energyOutput }
|
||||
|
||||
if (isMekanismLoaded) {
|
||||
resolverInputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) }
|
||||
resolverOutputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyOutput) }
|
||||
}
|
||||
|
||||
checkSurroundings()
|
||||
}
|
||||
}
|
||||
|
||||
fun checkSurroundings() {
|
||||
inputCapability.update((blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION))::equals)
|
||||
outputCapability.update((-blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION))::equals)
|
||||
}
|
||||
|
||||
override fun <T : Any> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
if (side == null || isRemoved)
|
||||
return super.getCapability(cap, side)
|
||||
|
||||
if (valid) {
|
||||
if (side == blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION)) {
|
||||
if (cap == MatteryCapability.ENERGY || cap == ForgeCapabilities.ENERGY) {
|
||||
return resolverInput.cast()
|
||||
} else if (cap == MatteryCapability.MEKANISM_ENERGY) {
|
||||
return resolverInputMekanism!!.cast()
|
||||
}
|
||||
} else if (side == blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION).opposite) {
|
||||
if (cap == MatteryCapability.ENERGY || cap == ForgeCapabilities.ENERGY) {
|
||||
return resolverOutput.cast()
|
||||
} else if (cap == MatteryCapability.MEKANISM_ENERGY) {
|
||||
return resolverOutputMekanism!!.cast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side)
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
lastTick = history[historyTick]
|
||||
historyTick = (historyTick + 1) % history.size
|
||||
|
@ -114,28 +114,6 @@ class StorageImporterBlock : RotatableMatteryBlock(), EntityBlock {
|
||||
): VoxelShape {
|
||||
return shapes[p_60555_]!!
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighbour: Block,
|
||||
neighbourPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
|
||||
|
||||
if (!level.isClientSide) {
|
||||
val tile = level.getBlockEntity(pos)
|
||||
|
||||
if (tile is StorageImporterBlockEntity) {
|
||||
level.oncePre {
|
||||
tile.checkSurroundings()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StorageExporterBlock : RotatableMatteryBlock(), EntityBlock {
|
||||
@ -218,26 +196,4 @@ class StorageExporterBlock : RotatableMatteryBlock(), EntityBlock {
|
||||
): VoxelShape {
|
||||
return shapes[p_60555_]!!
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighbour: Block,
|
||||
neighbourPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
|
||||
|
||||
if (!level.isClientSide) {
|
||||
val tile = level.getBlockEntity(pos)
|
||||
|
||||
if (tile is StorageExporterBlockEntity) {
|
||||
level.oncePre {
|
||||
tile.checkSurroundings()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,17 +58,4 @@ class BatteryBankBlock : RotatableMatteryBlock(), EntityBlock {
|
||||
override fun faceToPlayer(context: BlockPlaceContext): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighbour: Block,
|
||||
neighbourPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
|
||||
val blockEntity = level.getBlockEntity(pos) as? BatteryBankBlockEntity ?: return
|
||||
level.oncePre { blockEntity.checkSurroundings() }
|
||||
}
|
||||
}
|
||||
|
@ -75,27 +75,6 @@ class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock {
|
||||
}
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighbour: Block,
|
||||
neighbourPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
|
||||
|
||||
if (!level.isClientSide) {
|
||||
val tile = level.getBlockEntity(pos)
|
||||
|
||||
if (tile is ChemicalGeneratorBlockEntity) {
|
||||
level.oncePre {
|
||||
tile.checkSurroundings()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val shapes = getShapeForEachState(rotationProperty) { BlockShapes.CHEMICAL_GENERATOR.rotateFromNorth(it[rotationProperty]).computeShape() }
|
||||
|
||||
@Suppress("override_deprecation")
|
||||
|
@ -63,23 +63,6 @@ class EnergyCounterBlock : MatteryBlock(), EntityBlock {
|
||||
p_49915_.add(INPUT_DIRECTION, IF_DIRECTION)
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighbour: Block,
|
||||
neighbourPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
|
||||
|
||||
if (SERVER_IS_LIVE) {
|
||||
level.once {
|
||||
(level.getBlockEntity(pos) as? EnergyCounterBlockEntity)?.checkSurroundings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val SHAPES = HashMap<BlockState, VoxelShape>()
|
||||
|
||||
init {
|
||||
|
@ -66,6 +66,14 @@ interface GetterSetter<V> : Supplier<V>, Consumer<V>, ReadWriteProperty<Any?, V>
|
||||
}
|
||||
}
|
||||
|
||||
operator fun <T> Supplier<T>.getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||
return get()
|
||||
}
|
||||
|
||||
operator fun <T> Consumer<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||
accept(value)
|
||||
}
|
||||
|
||||
fun <V> KMutableProperty0<V>.asGetterSetter(watch: ((old: V, new: V) -> Unit)? = null): GetterSetter<V> {
|
||||
return GetterSetter.of(this).let {
|
||||
if (watch != null) {
|
||||
|
@ -1,303 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.SectionPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
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.SERVER_IS_LIVE
|
||||
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import ru.dbotthepony.mc.otm.core.math.unaryMinus
|
||||
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
|
||||
|
||||
private inline val Direction.flag: Int get() = 1 shl (ordinal + 1)
|
||||
|
||||
/**
|
||||
* This class allows block entities to track [capability] per block side.
|
||||
*
|
||||
* Allowed sides are governed by [test] method, which is open for override.
|
||||
*
|
||||
* **IMPORTANT:** Once rules behind [test] are changed, you MUST call [validate] or [update] right away, or expect hard to debug bugs.
|
||||
* If rule changes can't be tracked in practical way, then flip on [alwaysValidate], although it will come with performance
|
||||
* penalty (this will cause [iterator] to invoke [validate] on each its invocation).
|
||||
*
|
||||
* Subclasses can also override [subscribe] and [unsubscribe] to more finely track changes in neighbours.
|
||||
*
|
||||
* **THIS CLASS IS COMPLETELY THREAD UNSAFE**, it is assumed you only ever invoke it on server thread,
|
||||
* or, at very least, thread where [ServerLevel] resides.
|
||||
*/
|
||||
open class BESubscribeList<T>(
|
||||
val block: BlockEntity,
|
||||
val capability: Capability<T>,
|
||||
val alwaysValidate: Boolean = false
|
||||
) : Predicate<Direction>, Iterable<T> {
|
||||
private val knownCaps = WeakHashSet<LazyOptional<T>>()
|
||||
private val trackedCaps = EnumMap<Direction, WeakReference<LazyOptional<T>>>(Direction::class.java)
|
||||
private var updateQueued = false
|
||||
private var firstKey: Direction? = null
|
||||
private var lastDirectionSet = 0
|
||||
private var isWaitingOnChunk = false
|
||||
|
||||
/**
|
||||
* First valid capability, this is faster than invoking [iterator] and getting first value from it.
|
||||
*/
|
||||
val first: T? get() {
|
||||
return firstLO.orNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* First valid capability as [LazyOptional], this is faster than invoking [iterator] and getting first value from it.
|
||||
*
|
||||
* If required, calls [update]
|
||||
*/
|
||||
val firstLO: LazyOptional<T> get() {
|
||||
if (updateQueued) {
|
||||
update()
|
||||
} else if (alwaysValidate) {
|
||||
validate()
|
||||
}
|
||||
|
||||
for (i in 0 .. 2) {
|
||||
if (firstKey == null) {
|
||||
return LazyOptional.empty()
|
||||
}
|
||||
|
||||
val get = trackedCaps[firstKey]?.get()
|
||||
|
||||
if (get == null || !get.isPresent) {
|
||||
update()
|
||||
continue
|
||||
}
|
||||
|
||||
return get
|
||||
}
|
||||
|
||||
return LazyOptional.empty()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
final override fun iterator(): Iterator<T> {
|
||||
if (updateQueued) {
|
||||
update()
|
||||
} else if (alwaysValidate) {
|
||||
validate()
|
||||
}
|
||||
|
||||
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)
|
||||
} else if (!test(k)) {
|
||||
iterator.remove()
|
||||
unsubscribe(k, null)
|
||||
updateQueued = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(direction: Direction) {
|
||||
return update(direction::equals)
|
||||
}
|
||||
|
||||
private fun calculateDirectionSet(): Int {
|
||||
var set = 0
|
||||
|
||||
for (value in VALUES)
|
||||
if (test(value))
|
||||
set = set or value.flag
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for one of these conditions to be true:
|
||||
* * If [test] was determined to be changed during last time [iterator] was invoked AND tracked capability was filtered out due to [test] returning false
|
||||
* * Performs a fast bitflag intersection test, by calling [test] on all directions and seeking difference between built set and previous set checked during last [update]
|
||||
* * Tracked capabilities are checked for validity (if references are still valid)
|
||||
*
|
||||
* Once *any* of conditions above end up true, [update] is called and nothing else down the list is checked further.
|
||||
*/
|
||||
fun validate() {
|
||||
check(valid) { "Subscription list is marked as invalid" }
|
||||
|
||||
if (updateQueued) {
|
||||
update()
|
||||
return
|
||||
}
|
||||
|
||||
val new = calculateDirectionSet()
|
||||
|
||||
if (new != lastDirectionSet) {
|
||||
val intersect = new and lastDirectionSet
|
||||
val removed = lastDirectionSet and (intersect.inv())
|
||||
val added = new and (intersect.inv())
|
||||
|
||||
for (dir in VALUES) {
|
||||
if (dir.flag and removed != 0) {
|
||||
val value1 = trackedCaps.remove(dir)
|
||||
val value = value1?.get()
|
||||
|
||||
if (value1 != null) {
|
||||
unsubscribe(dir, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (added != 0) {
|
||||
update { it.flag and added != 0 }
|
||||
}
|
||||
|
||||
lastDirectionSet = new
|
||||
return
|
||||
}
|
||||
|
||||
val iterator = trackedCaps.iterator()
|
||||
var any = 0
|
||||
|
||||
for ((k, v) in iterator) {
|
||||
if (v.get() == null) {
|
||||
unsubscribe(k, null)
|
||||
any = any or k.flag
|
||||
}
|
||||
}
|
||||
|
||||
if (any != 0) {
|
||||
update { it.flag and any != 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates subscription list, searching for new capabilities and "removing" outdated ones.
|
||||
*
|
||||
* [predicate] narrows sides-to-check list, not replaces the set generated by this class' [test]
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun update(predicate: Predicate<Direction>? = null) {
|
||||
if (!valid || block.isRemoved)
|
||||
return
|
||||
|
||||
val level = block.level as? ServerLevel ?: return // don't run on client
|
||||
val sorse = level.chunkSource
|
||||
var waitChunkLoad = false
|
||||
|
||||
var stream = Direction.stream()
|
||||
|
||||
if (predicate != null) {
|
||||
stream = stream.filter(predicate)
|
||||
} else {
|
||||
updateQueued = false
|
||||
lastDirectionSet = calculateDirectionSet()
|
||||
}
|
||||
|
||||
stream = stream.filter(this)
|
||||
firstKey = null
|
||||
|
||||
for (dir in stream) {
|
||||
val pos = block.blockPos + dir
|
||||
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, -dir)
|
||||
val knownCap = trackedCaps[dir]?.get()
|
||||
|
||||
if (cap != null && cap.isPresent) {
|
||||
if (knownCap !== cap) {
|
||||
if (knownCaps.add(cap)) {
|
||||
val ref = WeakReference(this)
|
||||
|
||||
cap.addListener {
|
||||
val self = ref.get()
|
||||
|
||||
if (self != null) {
|
||||
val current = self.trackedCaps[dir]
|
||||
|
||||
if (current?.get() === it) {
|
||||
self.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trackedCaps[dir] = WeakReference(cap)
|
||||
subscribe(dir, cap)
|
||||
}
|
||||
|
||||
if (firstKey == null) {
|
||||
firstKey = dir
|
||||
}
|
||||
} else {
|
||||
trackedCaps.remove(dir)
|
||||
unsubscribe(dir, knownCap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (waitChunkLoad && SERVER_IS_LIVE) {
|
||||
onceServer { if (isWaitingOnChunk) update() }
|
||||
isWaitingOnChunk = true
|
||||
} else if (predicate == null) {
|
||||
isWaitingOnChunk = false
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val VALUES = Direction.values()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user