Capability subscriptions embedded into MatteryBlockEntity.Side

This commit is contained in:
DBotThePony 2023-02-18 09:59:09 +07:00
parent aab9e09e30
commit d8648d7088
Signed by: DBot
GPG Key ID: DCC23B5715498507
25 changed files with 262 additions and 694 deletions

View File

@ -23,7 +23,9 @@ import net.minecraft.world.level.material.Material
import net.minecraft.world.level.material.MaterialColor import net.minecraft.world.level.material.MaterialColor
import net.minecraft.world.phys.BlockHitResult import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.shapes.VoxelShape 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.IRedstoneControlled
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.core.get import ru.dbotthepony.mc.otm.core.get
@ -97,6 +99,7 @@ abstract class MatteryBlock @JvmOverloads constructor(
if (this is EntityBlock && level.isClientSide) if (this is EntityBlock && level.isClientSide)
return InteractionResult.SUCCESS return InteractionResult.SUCCESS
@Suppress("DEPRECATION")
return super.use(blockState, level, blockPos, ply, hand, blockHitResult) return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
} }
@ -167,6 +170,7 @@ abstract class MatteryBlock @JvmOverloads constructor(
neighbourPos: BlockPos, neighbourPos: BlockPos,
movedByPiston: Boolean movedByPiston: Boolean
) { ) {
@Suppress("DEPRECATION")
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston) super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
if (this is EntityBlock && !level.isClientSide) { if (this is EntityBlock && !level.isClientSide) {
@ -174,6 +178,9 @@ abstract class MatteryBlock @JvmOverloads constructor(
if (tile is IRedstoneControlled) if (tile is IRedstoneControlled)
tile.redstoneControl.redstoneSignal = level.getBestNeighborSignal(pos) tile.redstoneControl.redstoneSignal = level.getBestNeighborSignal(pos)
if (tile is MatteryBlockEntity && SERVER_IS_LIVE)
tile.neighborChanged(neighbour, neighbourPos, movedByPiston)
} }
} }

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.block.entity package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.ImmutableSet 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.Long2ObjectFunction
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap 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.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.SectionPos import net.minecraft.core.SectionPos
import net.minecraft.nbt.ByteTag import net.minecraft.core.Vec3i
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.DoubleTag
import net.minecraft.nbt.FloatTag
import net.minecraft.nbt.StringTag import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
@ -20,6 +19,7 @@ import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.ChunkPos import net.minecraft.world.level.ChunkPos
import net.minecraft.world.level.Level 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.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity 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.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper 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.forValidRefs
import ru.dbotthepony.mc.otm.core.forValidRefsBreak import ru.dbotthepony.mc.otm.core.forValidRefsBreak
import ru.dbotthepony.mc.otm.core.get import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.math.BlockRotation import ru.dbotthepony.mc.otm.core.math.BlockRotation
import ru.dbotthepony.mc.otm.core.math.RelativeSide 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.nbt.set
import ru.dbotthepony.mc.otm.core.util.EnumValueCodec import ru.dbotthepony.mc.otm.core.util.EnumValueCodec
import ru.dbotthepony.mc.otm.core.util.Savetables import ru.dbotthepony.mc.otm.core.util.Savetables
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
import ru.dbotthepony.mc.otm.network.FieldSynchronizer import ru.dbotthepony.mc.otm.network.FieldSynchronizer
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
import ru.dbotthepony.mc.otm.once
import ru.dbotthepony.mc.otm.oncePre import ru.dbotthepony.mc.otm.oncePre
import ru.dbotthepony.mc.otm.onceServer import ru.dbotthepony.mc.otm.onceServer
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.Collections import java.util.Collections
import java.util.EnumMap import java.util.EnumMap
import java.util.WeakHashMap import java.util.WeakHashMap
import java.util.function.Supplier
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0 import kotlin.reflect.KProperty0
@ -155,6 +160,11 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
exposeGlobally(ForgeCapabilities.ITEM_HANDLER, value) 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) { enum class SideMode(val filter: FlowDirection, val automation: FlowDirection) {
DISABLED (FlowDirection.NONE, FlowDirection.NONE), DISABLED (FlowDirection.NONE, FlowDirection.NONE),
NONE (FlowDirection.BI_DIRECTIONAL, 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 caps = Reference2ObjectArrayMap<Capability<*>, Cap<*>>()
private val modeStates = Object2ObjectArrayMap<String, ModeState>() private val modeStates = Object2ObjectArrayMap<String, ModeState>()
private val data = Object2ObjectArrayMap<ResourceLocation, INBTSerializable<Tag>>() 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() val isEmpty get() = caps.isEmpty() && modeStates.isEmpty()
@ -453,6 +538,30 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
savetables.deserializeNBT(nbt) 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) { protected fun tickOnce(func: Runnable) {
level?.oncePre { if (!isRemoved) func.run() } level?.oncePre { if (!isRemoved) func.run() }
} }
@ -511,13 +620,31 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
synchronizer.defaultEndpoint.markUnused() synchronizer.defaultEndpoint.markUnused()
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) val old = this.level
super.setLevel(level)
unsubscribe() unsubscribe()
_subCache = null _subCache = null
if (!p_155231_.isClientSide) { if (!level.isClientSide) {
subscribe() 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 playerMap = WeakHashMap<ServerLevel, Long2ObjectOpenHashMap<ChunkSubscribers>>()
private val tickingMap = WeakHashMap<ServerLevel, ArrayList<WeakReference<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) { fun onLevelUnload(event: LevelEvent.Unload) {
val level = event.level as? ServerLevel ?: return val level = event.level as? ServerLevel ?: return
playerMap.remove(level) playerMap.remove(level)

View File

@ -85,8 +85,8 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery
private var sleepTicks = 4 private var sleepTicks = 4
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
sleepTicks = 4 sleepTicks = 4
} }

View File

@ -133,10 +133,10 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return matter return matter
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }

View File

@ -1,20 +1,13 @@
package ru.dbotthepony.mc.otm.block.entity.matter package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos 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.server.level.ServerLevel
import net.minecraft.world.Container
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState 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.IDroppableContainer
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity 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.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities 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 { 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() var gaugeLevel by synchronizer.float()
@ -161,10 +152,10 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
matterNode.destroy(::MatterNetworkGraph) matterNode.destroy(::MatterNetworkGraph)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }

View File

@ -204,10 +204,10 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
matterNode.destroy(::MatterNetworkGraph) matterNode.destroy(::MatterNetworkGraph)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }

View File

@ -1,13 +1,11 @@
package ru.dbotthepony.mc.otm.block.entity.matter package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.menu.matter.MatterPanelMenu import ru.dbotthepony.mc.otm.menu.matter.MatterPanelMenu
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import java.util.HashMap import java.util.HashMap
import java.util.UUID import java.util.UUID
@ -17,7 +15,6 @@ import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
@ -54,10 +51,10 @@ class MatterPanelBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
exposeGlobally(MatteryCapability.TASK, this) exposeGlobally(MatteryCapability.TASK, this)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }

View File

@ -106,10 +106,10 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
matterNode.destroy(::MatterNetworkGraph) matterNode.destroy(::MatterNetworkGraph)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }

View File

@ -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.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.container.MatteryContainer 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.container.HandlerFilter
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
@ -164,10 +163,10 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.destroy(::MatterNetworkGraph) matterNode.destroy(::MatterNetworkGraph)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }

View File

@ -169,10 +169,10 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return null to IdleReason.ITEM return null to IdleReason.ITEM
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) { if (level is ServerLevel) {
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }
} }

View File

@ -8,20 +8,14 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock 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.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import ru.dbotthepony.mc.otm.menu.matter.PatternStorageMenu import ru.dbotthepony.mc.otm.menu.matter.PatternStorageMenu
import net.minecraft.MethodsReturnNonnullByDefault import net.minecraft.MethodsReturnNonnullByDefault
import net.minecraft.core.Direction
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.Container
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block 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.IDroppableContainer
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.* 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.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph 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.registry.MBlockEntities
import ru.dbotthepony.mc.otm.core.nbt.set
import java.util.ArrayList import java.util.ArrayList
import java.util.stream.Stream 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 } private val itemHandler = container.handler { slot: Int, stack: ItemStack -> stack.getCapability(MatteryCapability.PATTERN).isPresent }
override val droppableContainer by ::container override val droppableContainer by ::container
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode) MatterNetworkGraph.discoverFull(this, matterNode)
} }

View File

@ -1,9 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity.storage package ru.dbotthepony.mc.otm.block.entity.storage
import net.minecraft.core.BlockPos 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.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player 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.item.ItemStack
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState 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.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
import ru.dbotthepony.mc.otm.capability.MatteryCapability 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.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu 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.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.storage.* import ru.dbotthepony.mc.otm.storage.*
class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : 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) exposeGlobally(MatteryCapability.STORAGE_NODE, cell)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
StorageNetworkGraph.discoverFull(this, cell.storageNode) StorageNetworkGraph.discoverFull(this, cell.storageNode)
} }

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.storage
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.NonNullList import net.minecraft.core.NonNullList
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf 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.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.ForgeHooks import net.minecraftforge.common.ForgeHooks
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.NetworkEvent
import org.apache.logging.log4j.LogManager 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.core.TranslatableComponent
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability 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.getEnum
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.menu.storage.ItemMonitorMenu import ru.dbotthepony.mc.otm.menu.storage.ItemMonitorMenu
import ru.dbotthepony.mc.otm.registry.MBlocks
import ru.dbotthepony.mc.otm.storage.* import ru.dbotthepony.mc.otm.storage.*
import java.math.BigInteger import java.math.BigInteger
import java.util.* import java.util.*
@ -501,10 +496,10 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
return ItemMonitorMenu(containerID, inventory, this) return ItemMonitorMenu(containerID, inventory, this)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) if (level is ServerLevel)
StorageNetworkGraph.discoverFull(this, cell.storageNode) StorageNetworkGraph.discoverFull(this, cell.storageNode)
} }

View File

@ -4,7 +4,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory 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.Level
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.IItemHandler 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.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig 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.container.ItemFilter
import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom 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.isPositive
import ru.dbotthepony.mc.otm.core.math.isZero import ru.dbotthepony.mc.otm.core.math.isZero
import ru.dbotthepony.mc.otm.core.math.plus 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.Graph6Node
import ru.dbotthepony.mc.otm.graph.GraphNodeListener import ru.dbotthepony.mc.otm.graph.GraphNodeListener
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode
@ -115,10 +110,10 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
savetable(::filter, FILTER_KEY) savetable(::filter, FILTER_KEY)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) { if (level is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode) StorageNetworkGraph.discoverFull(this, cell.storageNode)
} }

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.storage
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory 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.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.IItemHandler 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.CableBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity 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.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
import ru.dbotthepony.mc.otm.config.MachinesConfig 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.container.ItemFilter
import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RelativeSide 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.toIntSafe
import ru.dbotthepony.mc.otm.core.math.unaryMinus import ru.dbotthepony.mc.otm.core.orNull
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.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.GraphNodeListener import ru.dbotthepony.mc.otm.graph.GraphNodeListener
import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode 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.menu.storage.StorageImporterMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MNames 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.math.BigInteger
import java.util.* import java.util.*
import java.util.stream.Stream import java.util.stream.Stream
import kotlin.collections.HashSet
abstract class AbstractStorageImportExport<T>( abstract class AbstractStorageImportExport<T>(
blockType: BlockEntityType<*>, blockType: BlockEntityType<*>,
@ -85,42 +82,23 @@ abstract class AbstractStorageImportExport<T>(
exposeAllSidesExcept(RelativeSide.FRONT, MatteryCapability.STORAGE_NODE, cell) exposeAllSidesExcept(RelativeSide.FRONT, MatteryCapability.STORAGE_NODE, cell)
} }
override fun invalidateCaps() {
super.invalidateCaps()
target.invalidate()
}
override fun reviveCaps() {
super.reviveCaps()
target.revive()
}
override fun setRemoved() { override fun setRemoved() {
super.setRemoved() super.setRemoved()
cell.destroy(level) cell.destroy(level)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) { if (level is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode) StorageNetworkGraph.discoverFull(this, cell.storageNode)
tickOnceServer(this::checkSurroundings)
} }
} }
protected abstract val targetCapability: Capability<T> protected abstract val targetCapability: Capability<T>
protected val target by lazy { protected val target by lazy {
object : BESubscribeList<T>(this@AbstractStorageImportExport, targetCapability) { front.track(targetCapability)
override fun test(t: Direction): Boolean {
return t == -this@AbstractStorageImportExport.blockState.getValue(BlockRotationFreedom.TWO.property).front
}
}
}
fun checkSurroundings() {
target.update()
} }
abstract val filter: ItemFilter abstract val filter: ItemFilter
@ -206,7 +184,7 @@ class StorageImporterBlockEntity(blockPos: BlockPos, blockState: BlockState)
nextTick-- nextTick--
val target = target.firstOrNull() val target = target.get().orNull()
if (nextTick <= 0 && target != null && enoughEnergy) { if (nextTick <= 0 && target != null && enoughEnergy) {
val graph = cell.storageGraph ?: return val graph = cell.storageGraph ?: return
@ -318,7 +296,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
nextTick-- nextTick--
val target = target.firstOrNull() val target = target.get().orNull()
if (nextTick <= 0 && target != null && enoughEnergy) { if (nextTick <= 0 && target != null && enoughEnergy) {
val graph = cell.storageGraph ?: return val graph = cell.storageGraph ?: return

View File

@ -1,20 +1,12 @@
package ru.dbotthepony.mc.otm.block.entity.storage package ru.dbotthepony.mc.otm.block.entity.storage
import net.minecraft.core.BlockPos 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.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState 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.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage 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.graph.storage.StorageNetworkGraph
import ru.dbotthepony.mc.otm.menu.storage.StoragePowerSupplierMenu import ru.dbotthepony.mc.otm.menu.storage.StoragePowerSupplierMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities 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) { class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_POWER_SUPPLIER, blockPos, blockState) {
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { 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) savetables.decimal(::powerPassed, POWER_PASSED_KEY)
} }
override fun setLevel(p_155231_: Level) { override fun setLevel(level: Level) {
super.setLevel(p_155231_) super.setLevel(level)
if (p_155231_ is ServerLevel) { if (level is ServerLevel) {
StorageNetworkGraph.discoverFull(this, cell.storageNode) StorageNetworkGraph.discoverFull(this, cell.storageNode)
} }
} }

View File

@ -1,26 +1,28 @@
package ru.dbotthepony.mc.otm.block.entity.tech package ru.dbotthepony.mc.otm.block.entity.tech
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.energy.IEnergyStorage
import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.block.IDroppableContainer
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity 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.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.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.Decimal
import ru.dbotthepony.mc.otm.core.math.RelativeSide 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.menu.tech.BatteryBankMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities 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) { private val consumers by front.track(ForgeCapabilities.ENERGY)
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)
fun tick() { fun tick() {
if (redstoneControl.isBlockedByRedstone) if (redstoneControl.isBlockedByRedstone)
return return
for (it in consumers) { consumers.ifPresentK {
val (_, maxThroughput) = energy.getDistribution(false) val (_, maxThroughput) = energy.getDistribution(false)
if (maxThroughput.isZero) if (maxThroughput.isZero)
continue return@ifPresentK
val diff = it.receiveEnergy(maxThroughput, true) val diff = it.receiveEnergy(maxThroughput, true)

View File

@ -1,12 +1,10 @@
package ru.dbotthepony.mc.otm.block.entity.tech package ru.dbotthepony.mc.otm.block.entity.tech
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack 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.Block
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.ForgeConfigSpec 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.block.entity.WorkerState
import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage 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.MatteryContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.core.* 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.Decimal
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
import ru.dbotthepony.mc.otm.core.math.defineDecimal 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 { class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.CHEMICAL_GENERATOR, pos, state), IDroppableContainer {
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { 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) savetable(::container, INVENTORY_KEY)
exposeEnergyGlobally(energy) exposeEnergyGlobally(energy)
exposeItemsGlobally(itemHandler) exposeItemsGlobally(itemHandler)
savetables.int(::workTicks, WORK_TICKS_KEY)
savetables.int(::workTicksTotal, WORK_TICKS_TOTAL_KEY)
} }
private val consumers = BESubscribeList(this, ForgeCapabilities.ENERGY) private val consumers = trackGlobally(ForgeCapabilities.ENERGY)
fun checkSurroundings() = consumers.update()
override fun setChangedLight() { override fun setChangedLight() {
super.setChangedLight() super.setChangedLight()
checkFuelSlot = true 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 var workTicks = 0
private set private set
@ -171,7 +142,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
} }
for (consumer in consumers) { for (consumer in consumers) {
workWithPower(consumer) consumer.ifPresentK(::workWithPower)
} }
} }

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity.tech package ru.dbotthepony.mc.otm.block.entity.tech
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.IntTag import net.minecraft.nbt.IntTag
import net.minecraft.nbt.ListTag 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.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities 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.tech.EnergyCounterBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
import ru.dbotthepony.mc.otm.core.* 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.Decimal
import ru.dbotthepony.mc.otm.core.math.getDecimal 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.getByteArrayList
import ru.dbotthepony.mc.otm.core.nbt.ifHas import ru.dbotthepony.mc.otm.core.nbt.ifHas
import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.core.nbt.set 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.menu.tech.EnergyCounterMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.* 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_) { class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
var passed by synchronizer.fraction() 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 } private val history = Array(10 * 20) { Decimal.ZERO }
internal var historyTick = 0 internal var historyTick = 0
@ -124,22 +122,8 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
private val energyInput = EnergyCounterCap(true) private val energyInput = EnergyCounterCap(true)
private val energyOutput = EnergyCounterCap(false) private val energyOutput = EnergyCounterCap(false)
private val inputCapability = object : BESubscribeList<IEnergyStorage>(this@EnergyCounterBlockEntity, ForgeCapabilities.ENERGY) { private val inputCapability by front.track(ForgeCapabilities.ENERGY)
override fun test(t: Direction): Boolean { private val outputCapability by back.track(ForgeCapabilities.ENERGY)
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 inner class EnergyCounterCap(isInput: Boolean) : IMatteryEnergyStorage { private inner class EnergyCounterCap(isInput: Boolean) : IMatteryEnergyStorage {
override val energyFlow = FlowDirection.input(isInput) override val energyFlow = FlowDirection.input(isInput)
@ -148,7 +132,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
if (redstoneControl.isBlockedByRedstone) if (redstoneControl.isBlockedByRedstone)
return Decimal.ZERO return Decimal.ZERO
val it = inputCapability.first val it = inputCapability.orNull()
if (it != null) { if (it != null) {
val diff: Decimal val diff: Decimal
@ -176,7 +160,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
if (redstoneControl.isBlockedByRedstone) if (redstoneControl.isBlockedByRedstone)
return Decimal.ZERO return Decimal.ZERO
val it = outputCapability.first val it = outputCapability.orNull()
if (it != null) { if (it != null) {
val diff: Decimal val diff: Decimal
@ -206,7 +190,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override var batteryLevel: Decimal override var batteryLevel: Decimal
get() { get() {
if (energyFlow.input) { if (energyFlow.input) {
val it = outputCapability.first val it = outputCapability.orNull()
if (it != null) { if (it != null) {
if (it is IMatteryEnergyStorage) { if (it is IMatteryEnergyStorage) {
@ -216,7 +200,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
return Decimal(it.energyStored) return Decimal(it.energyStored)
} }
} else { } else {
val it = inputCapability.first val it = inputCapability.orNull()
if (it != null) { if (it != null) {
if (it is IMatteryEnergyStorage) { if (it is IMatteryEnergyStorage) {
@ -236,7 +220,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override val maxBatteryLevel: Decimal override val maxBatteryLevel: Decimal
get() { get() {
if (energyFlow.input) { if (energyFlow.input) {
val it = outputCapability.first val it = outputCapability.orNull()
if (it != null) { if (it != null) {
if (it is IMatteryEnergyStorage) { if (it is IMatteryEnergyStorage) {
@ -246,7 +230,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
return Decimal(it.maxEnergyStored) return Decimal(it.maxEnergyStored)
} }
} else { } else {
val it = inputCapability.first val it = inputCapability.orNull()
if (it != null) { if (it != null) {
if (it is IMatteryEnergyStorage) { if (it is IMatteryEnergyStorage) {
@ -263,7 +247,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override val missingPower: Decimal override val missingPower: Decimal
get() { get() {
if (energyFlow.input) { if (energyFlow.input) {
val it = outputCapability.first val it = outputCapability.orNull()
if (it != null) { if (it != null) {
if (it is IMatteryEnergyStorage) { 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)) return Decimal((it.maxEnergyStored - it.energyStored).coerceAtLeast(0))
} }
} else { } else {
val it = inputCapability.first val it = inputCapability.orNull()
if (it != null) { if (it != null) {
if (it is IMatteryEnergyStorage) { if (it is IMatteryEnergyStorage) {
@ -288,86 +272,19 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
} }
} }
private var resolverInput = LazyOptional.of<IMatteryEnergyStorage> { energyInput } init {
private var resolverOutput = LazyOptional.of<IMatteryEnergyStorage> { energyOutput } front.Cap(ForgeCapabilities.ENERGY, energyInput)
front.Cap(MatteryCapability.ENERGY, energyInput)
private var resolverInputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } else null back.Cap(ForgeCapabilities.ENERGY, energyOutput)
private var resolverOutputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyOutput) } else null back.Cap(MatteryCapability.ENERGY, energyOutput)
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 }
if (isMekanismLoaded) { if (isMekanismLoaded) {
resolverInputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } front.Cap(MatteryCapability.MEKANISM_ENERGY, Mattery2MekanismEnergyWrapper(energyInput))
resolverOutputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyOutput) } 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() { fun tick() {
lastTick = history[historyTick] lastTick = history[historyTick]
historyTick = (historyTick + 1) % history.size historyTick = (historyTick + 1) % history.size

View File

@ -114,28 +114,6 @@ class StorageImporterBlock : RotatableMatteryBlock(), EntityBlock {
): VoxelShape { ): VoxelShape {
return shapes[p_60555_]!! 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 { class StorageExporterBlock : RotatableMatteryBlock(), EntityBlock {
@ -218,26 +196,4 @@ class StorageExporterBlock : RotatableMatteryBlock(), EntityBlock {
): VoxelShape { ): VoxelShape {
return shapes[p_60555_]!! 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()
}
}
}
}
} }

View File

@ -58,17 +58,4 @@ class BatteryBankBlock : RotatableMatteryBlock(), EntityBlock {
override fun faceToPlayer(context: BlockPlaceContext): Boolean { override fun faceToPlayer(context: BlockPlaceContext): Boolean {
return false 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() }
}
} }

View File

@ -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() } private val shapes = getShapeForEachState(rotationProperty) { BlockShapes.CHEMICAL_GENERATOR.rotateFromNorth(it[rotationProperty]).computeShape() }
@Suppress("override_deprecation") @Suppress("override_deprecation")

View File

@ -63,23 +63,6 @@ class EnergyCounterBlock : MatteryBlock(), EntityBlock {
p_49915_.add(INPUT_DIRECTION, IF_DIRECTION) 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>() private val SHAPES = HashMap<BlockState, VoxelShape>()
init { init {

View File

@ -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> { fun <V> KMutableProperty0<V>.asGetterSetter(watch: ((old: V, new: V) -> Unit)? = null): GetterSetter<V> {
return GetterSetter.of(this).let { return GetterSetter.of(this).let {
if (watch != null) { if (watch != null) {

View File

@ -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()
}
}