Compare commits

...

2 Commits

10 changed files with 205 additions and 93 deletions

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.block.entity.blackhole
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import it.unimi.dsi.fastutil.objects.ObjectIterators
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
@ -10,6 +9,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.state.BlockState
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.kommons.collect.toList
import ru.dbotthepony.kommons.util.DelegateSetter
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
@ -23,7 +23,6 @@ import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.CombinedProfiledMatterStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.config.ServerConfig
import ru.dbotthepony.mc.otm.core.RandomSource2Generator
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.multiblock.ShapedMultiblock
@ -34,6 +33,7 @@ import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.math.times
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
import ru.dbotthepony.mc.otm.core.multiblock.shapedMultiblock
import ru.dbotthepony.mc.otm.core.util.InvalidableLazy
import ru.dbotthepony.mc.otm.menu.tech.BlackHoleGeneratorMenu
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MBlockTags
@ -44,6 +44,7 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
MBlockEntities.BLACK_HOLE_GENERATOR, blockPos, blockState) {
var multiblock: ShapedMultiblock? = null
private set
private var multiblockSyncher: Closeable? = null
var lastRange by syncher.int(-1, setter = DelegateSetter { field, value ->
@ -51,13 +52,23 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
multiblockSyncher?.close()
multiblockSyncher = null
multiblock?.close()
energyTarget.invalidate()
matterTarget.invalidate()
multiblock = null
field.accept(value)
} else if (value != field.value) {
multiblockSyncher?.close()
multiblock?.close()
multiblock = CONFIGURATIONS[value - 5].value.create(blockPos)
multiblock!!.onGenerationChanges(Runnable {
energyTarget.invalidate()
matterTarget.invalidate()
})
multiblockSyncher = syncher.add0(multiblock!!)
energyTarget.invalidate()
matterTarget.invalidate()
field.accept(value)
}
})
@ -65,17 +76,16 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
var drawBuildingGuide by syncher.boolean()
val energy = CombinedProfiledEnergyStorage(
FlowDirection.NONE,
{ multiblock?.blockEntities(EnergyHatchBlockEntity.OUTPUT_TAG)?.iterator()?.map { it.energy } ?: ObjectIterators.emptyIterator() },
{ level?.random }
)
private val energyTarget = InvalidableLazy.Impl {
multiblock?.blockEntities(EnergyHatchBlockEntity.OUTPUT_TAG)?.iterator()?.map { it.energy }?.toList() ?: listOf()
}
val matter = CombinedProfiledMatterStorage(
FlowDirection.NONE,
{ multiblock?.blockEntities(MatterHatchBlockEntity.INPUT_TAG)?.iterator()?.map { it.matter } ?: ObjectIterators.emptyIterator() },
{ level?.random }
)
private val matterTarget = InvalidableLazy.Impl {
multiblock?.blockEntities(MatterHatchBlockEntity.INPUT_TAG)?.iterator()?.map { it.matter }?.toList() ?: listOf()
}
val energy = CombinedProfiledEnergyStorage(FlowDirection.NONE, energyTarget::value, { level?.random })
val matter = CombinedProfiledMatterStorage(FlowDirection.NONE, matterTarget::value, { level?.random })
enum class Mode(val label: Component, val tooltip: Component) {
TARGET_MASS(TranslatableComponent("otm.gui.black_hole_generator.sustain.mode"), TranslatableComponent("otm.gui.black_hole_generator.sustain.desc")),
@ -159,7 +169,7 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
val multiblock = multiblock
if (multiblock != null) {
if (!multiblock.update(level, blockRotation.front)) {
if (!multiblock.update(level, blockRotation.back)) {
this.lastRange = findBlackHoleRange()
} else {
val blackHole = multiblock.blockEntities(BLACK_HOLE).firstOrNull() ?: return

View File

@ -11,6 +11,8 @@ import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.energy.IEnergyStorage
import ru.dbotthepony.kommons.collect.flatMap
import ru.dbotthepony.kommons.collect.map
import ru.dbotthepony.kommons.collect.toList
import ru.dbotthepony.kommons.util.Listenable
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage
@ -22,6 +24,7 @@ import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag
import ru.dbotthepony.mc.otm.core.multiblock.IMultiblockAccess
import ru.dbotthepony.mc.otm.core.multiblock.IMultiblockListener
import ru.dbotthepony.mc.otm.core.util.InvalidableLazy
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
class EnergyInterfaceBlockEntity(
@ -34,20 +37,22 @@ class EnergyInterfaceBlockEntity(
val energyInterfaceTarget: ProfiledEnergyStorage<*>
}
private val multiblocks = LinkedHashSet<IMultiblockAccess>()
private val multiblocks = LinkedHashMap<IMultiblockAccess, Listenable.L>()
private val targets = InvalidableLazy.Impl {
multiblocks.keys.iterator().flatMap { it.blockEntities(TARGET).iterator() }.map { it.energyInterfaceTarget }.toList()
}
val energy = CombinedProfiledEnergyStorage(
FlowDirection.input(isInput),
{ multiblocks.iterator().flatMap { it.blockEntities(TARGET).iterator() }.map { it.energyInterfaceTarget } },
{ level?.random }
)
val energy = CombinedProfiledEnergyStorage(FlowDirection.input(isInput), targets::value, { level?.random })
override fun onAddedToMultiblock(multiblock: IMultiblockAccess) {
check(multiblocks.add(multiblock)) { "$this already tracks $multiblock" }
check(!isRemoved) { "Block was removed" }
check(multiblocks.put(multiblock, multiblock.onGenerationChanges(Runnable { targets.invalidate() })) == null) { "$this already tracks $multiblock" }
targets.invalidate()
}
override fun onRemovedFromMultiblock(multiblock: IMultiblockAccess) {
check(multiblocks.remove(multiblock)) { "$this does not track $multiblock" }
check(multiblocks.remove(multiblock)?.remove() != null || isRemoved) { "$this does not track $multiblock" }
targets.invalidate()
}
val container = object : MatteryContainer(::markDirtyFast, CAPACITY) {
@ -59,6 +64,11 @@ class EnergyInterfaceBlockEntity(
val itemHandler = container.handler(if (isInput) HandlerFilter.Dischargeable else HandlerFilter.Chargeable)
private val neighbours = ArrayList<CapabilityCache<IEnergyStorage>>()
override fun setRemoved() {
super.setRemoved()
multiblocks.values.forEach { it.remove() }
}
init {
savetables.stateful(::container, BATTERY_KEY)

View File

@ -1,10 +1,8 @@
package ru.dbotthepony.mc.otm.capability
import com.google.common.collect.Streams
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
@ -35,10 +33,7 @@ import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.shuffle
import ru.dbotthepony.mc.otm.core.util.formatFluidLevel
import java.util.function.Supplier
import java.util.random.RandomGenerator
import java.util.stream.Stream
private val LOGGER = LogManager.getLogger()
@ -46,37 +41,6 @@ private val LOGGER = LogManager.getLogger()
val Player.matteryPlayer: MatteryPlayer get() = (this as IMatteryPlayer).otmPlayer
val LivingEntity.matteryPlayer: MatteryPlayer? get() = (this as? IMatteryPlayer)?.otmPlayer
fun <T> Supplier<out Iterator<T>>.iterateProviders(random: RandomSource?, value: Decimal, simulate: Boolean, walker: T.(Decimal, Boolean) -> Decimal): Decimal {
val providers = get()
val iteratorProvider: () -> Iterator<T>
if (random == null) {
iteratorProvider = providers::iterator
} else {
val providerList = ObjectArrayList(providers)
providerList.shuffle(random)
iteratorProvider = providerList::iterator
}
var leftover = value
for (provider in iteratorProvider()) {
leftover -= walker(provider, leftover, true)
if (leftover.signum() <= 0) break
}
if (simulate) return value - leftover
leftover = value
for (provider in iteratorProvider()) {
leftover -= walker(provider, leftover, false)
if (leftover.signum() <= 0) break
}
return value - leftover
}
/**
* Does a checked energy receive, calls [IMatteryEnergyStorage.receiveEnergyChecked] if possible
*/

View File

@ -2,33 +2,37 @@ package ru.dbotthepony.mc.otm.capability.energy
import net.minecraft.util.RandomSource
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.iterateProviders
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.reduce
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.CapabilityListIterator
import java.util.function.Supplier
import java.util.random.RandomGenerator
open class CombinedEnergyStorage(
final override val energyFlow: FlowDirection,
val provider: Supplier<out Iterator<IMatteryEnergyStorage>>,
val random: Supplier<RandomSource?> = Supplier { null }
provider: Supplier<out List<IMatteryEnergyStorage>>,
random: Supplier<RandomSource?> = Supplier { null }
) : IMatteryEnergyStorage {
val iterator = CapabilityListIterator(provider, random)
val provider get() = iterator.provider
val random get() = iterator.random
final override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return provider.iterateProviders(random.get(), howMuch, simulate, IMatteryEnergyStorage::extractEnergy)
return iterator.iterate(howMuch, simulate, IMatteryEnergyStorage::extractEnergy)
}
final override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return provider.iterateProviders(random.get(), howMuch, simulate, IMatteryEnergyStorage::receiveEnergy)
return iterator.iterate(howMuch, simulate, IMatteryEnergyStorage::receiveEnergy)
}
/*
final override fun extractEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
return provider.iterateProviders(random.get(), howMuch, simulate, IMatteryEnergyStorage::extractEnergyChecked)
return iterator.iterate(howMuch, simulate, IMatteryEnergyStorage::extractEnergyChecked)
}
final override fun receiveEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
return provider.iterateProviders(random.get(), howMuch, simulate, IMatteryEnergyStorage::receiveEnergyChecked)
return iterator.iterate(howMuch, simulate, IMatteryEnergyStorage::receiveEnergyChecked)
}
*/

View File

@ -14,15 +14,15 @@ import java.util.random.RandomGenerator
class CombinedProfiledEnergyStorage(
energyFlow: FlowDirection,
provider: Supplier<out Iterator<ProfiledEnergyStorage<*>>>,
provider: Supplier<out List<ProfiledEnergyStorage<*>>>,
random: Supplier<RandomSource?> = Supplier { null }
) : CombinedEnergyStorage(energyFlow, provider, random), IProfiledMatteryEnergyStorage, IProfiledStorage.Combined, ITickable {
override val received = CombinedDecimalHistoryChart(Supplier { this.provider.get().map { (it as ProfiledEnergyStorage<*>).received } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val transferred = CombinedDecimalHistoryChart(Supplier { this.provider.get().map { (it as ProfiledEnergyStorage<*>).transferred } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val received = CombinedDecimalHistoryChart(Supplier { this.provider.get().iterator().map { (it as ProfiledEnergyStorage<*>).received } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val transferred = CombinedDecimalHistoryChart(Supplier { this.provider.get().iterator().map { (it as ProfiledEnergyStorage<*>).transferred } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val receivedThisTick: Decimal
get() = provider.get().map { (it as ProfiledEnergyStorage<*>).receivedThisTick }.reduce(Decimal.ZERO, Decimal::plus)
get() = provider.get().iterator().map { (it as ProfiledEnergyStorage<*>).receivedThisTick }.reduce(Decimal.ZERO, Decimal::plus)
override val transferredThisTick: Decimal
get() = provider.get().map { (it as ProfiledEnergyStorage<*>).transferredThisTick }.reduce(Decimal.ZERO, Decimal::plus)
get() = provider.get().iterator().map { (it as ProfiledEnergyStorage<*>).transferredThisTick }.reduce(Decimal.ZERO, Decimal::plus)
override fun tick() {
received.tick()

View File

@ -2,32 +2,36 @@ package ru.dbotthepony.mc.otm.capability.matter
import net.minecraft.util.RandomSource
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.iterateProviders
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.reduce
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.CapabilityListIterator
import java.util.function.Supplier
import java.util.random.RandomGenerator
open class CombinedMatterStorage(
final override val matterFlow: FlowDirection,
val provider: Supplier<out Iterator<IMatterStorage>>,
val random: Supplier<RandomSource?> = Supplier { null }
provider: Supplier<out List<IMatterStorage>>,
random: Supplier<RandomSource?> = Supplier { null }
) : IMatterStorage {
val iterator = CapabilityListIterator(provider, random)
val provider get() = iterator.provider
val random get() = iterator.random
final override var storedMatter: Decimal
get() = provider.get().map { it.storedMatter }.reduce(Decimal.ZERO, Decimal::plus)
get() = provider.get().iterator().map { it.storedMatter }.reduce(Decimal.ZERO, Decimal::plus)
set(value) {
throw UnsupportedOperationException()
}
final override val maxStoredMatter: Decimal
get() = provider.get().map { it.maxStoredMatter }.reduce(Decimal.ZERO, Decimal::plus)
get() = provider.get().iterator().map { it.maxStoredMatter }.reduce(Decimal.ZERO, Decimal::plus)
final override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal {
return provider.iterateProviders(random.get(), howMuch, simulate, IMatterStorage::receiveMatter)
return iterator.iterate(howMuch, simulate, IMatterStorage::receiveMatter)
}
final override fun extractMatter(howMuch: Decimal, simulate: Boolean): Decimal {
return provider.iterateProviders(random.get(), howMuch, simulate, IMatterStorage::extractMatter)
return iterator.iterate(howMuch, simulate, IMatterStorage::extractMatter)
}
final override val canSetMatterLevel: Boolean

View File

@ -14,15 +14,15 @@ import java.util.random.RandomGenerator
class CombinedProfiledMatterStorage(
matterFlow: FlowDirection,
provider: Supplier<out Iterator<ProfiledMatterStorage<*>>>,
provider: Supplier<out List<ProfiledMatterStorage<*>>>,
random: Supplier<RandomSource?> = Supplier { null }
) : CombinedMatterStorage(matterFlow, provider, random), IProfiledMatterStorage, IProfiledStorage.Combined, ITickable {
override val received = CombinedDecimalHistoryChart(Supplier { this.provider.get().map { (it as ProfiledMatterStorage<*>).received } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val transferred = CombinedDecimalHistoryChart(Supplier { this.provider.get().map { (it as ProfiledMatterStorage<*>).transferred } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val received = CombinedDecimalHistoryChart(Supplier { this.provider.get().iterator().map { (it as ProfiledMatterStorage<*>).received } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val transferred = CombinedDecimalHistoryChart(Supplier { this.provider.get().iterator().map { (it as ProfiledMatterStorage<*>).transferred } }, ticks = AbstractProfiledStorage.HISTORY_SIZE)
override val receivedThisTick: Decimal
get() = provider.get().map { (it as ProfiledMatterStorage<*>).receivedThisTick }.reduce(Decimal.ZERO, Decimal::plus)
get() = provider.get().iterator().map { (it as ProfiledMatterStorage<*>).receivedThisTick }.reduce(Decimal.ZERO, Decimal::plus)
override val transferredThisTick: Decimal
get() = provider.get().map { (it as ProfiledMatterStorage<*>).transferredThisTick }.reduce(Decimal.ZERO, Decimal::plus)
get() = provider.get().iterator().map { (it as ProfiledMatterStorage<*>).transferredThisTick }.reduce(Decimal.ZERO, Decimal::plus)
override fun tick() {
received.tick()

View File

@ -3,13 +3,10 @@ package ru.dbotthepony.mc.otm.core.multiblock
import it.unimi.dsi.fastutil.objects.Reference2IntMap
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
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.state.BlockState
import net.minecraft.world.phys.AABB
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
import java.util.*
import ru.dbotthepony.kommons.util.Listenable
interface IMultiblockAccess {
/**
@ -19,6 +16,19 @@ interface IMultiblockAccess {
val currentDirection: Direction?
val currentNodes: Map<BlockPos, IMultiblockNode>
/**
* Arbitrary number representing counter which increases when *something* has changed regarding multiblock configuraiton,
* probably something not even visible in public interface
*
* Useful for caching data structures which derive from current state of multiblock
*/
val generation: Int
/**
* [listener] will be executed whenever [generation] changes
*/
fun onGenerationChanges(listener: Runnable): Listenable.L
val boundingBox: AABB?
/**

View File

@ -2,8 +2,6 @@ package ru.dbotthepony.mc.otm.core.multiblock
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import it.unimi.dsi.fastutil.ints.IntArrayList
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
import it.unimi.dsi.fastutil.objects.Reference2IntMap
import it.unimi.dsi.fastutil.objects.Reference2IntMaps
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap
@ -16,8 +14,7 @@ import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.AABB
import ru.dbotthepony.mc.otm.core.AABB
import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.kommons.util.Listenable
import ru.dbotthepony.mc.otm.core.collect.collect
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.getBlockEntityNow
@ -30,7 +27,6 @@ import ru.dbotthepony.mc.otm.network.syncher.ISynchable
import java.io.Closeable
import java.util.LinkedList
import java.util.concurrent.CopyOnWriteArrayList
import java.util.function.BooleanSupplier
import kotlin.collections.ArrayDeque
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
@ -49,6 +45,25 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
private val east = Config(Direction.EAST, pos, factory.east)
private val configurations = ImmutableList.of(north, south, west, east)
override var generation: Int = 0
private set
private val changeListeners = CopyOnWriteArrayList<ChangeListener>()
private inner class ChangeListener(val runnable: Runnable) : Listenable.L {
init {
changeListeners.add(this)
}
override fun remove() {
changeListeners.remove(this)
}
}
override fun onGenerationChanges(listener: Runnable): Listenable.L {
return ChangeListener(listener)
}
override val hasRemotes: Boolean
get() = remotes.isNotEmpty()
@ -147,6 +162,8 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
val be2 = blockEntity
if (be1 != be2) {
generation++
if (be1 != null) {
if (be1 is IMultiblockListener)
referencedListeners.dereference(be1)
@ -170,6 +187,8 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
val old = this.blockState
if (state != old) {
generation++
if (old != null) {
assignedBlockStateLists.forEach {
it[old] = it.getInt(old) - 1
@ -216,6 +235,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
}
private fun clearFull() {
generation++
val blockEntity = blockEntity
if (blockEntity != null) {
@ -251,6 +271,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
}
fun clear() {
generation++
val blockEntity = blockEntity
if (blockEntity != null) {
@ -269,6 +290,14 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
private val referencedListeners = MultiblockListenerSet(this)
override var generation: Int
get() = this@ShapedMultiblock.generation
private set(value) { this@ShapedMultiblock.generation = value }
override fun onGenerationChanges(listener: Runnable): Listenable.L {
return this@ShapedMultiblock.onGenerationChanges(listener)
}
val index = when (currentDirection) {
Direction.NORTH -> 0
Direction.SOUTH -> 1
@ -349,6 +378,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
}
fun clear() {
generation++
referencedListeners.clear()
tag2BlockEntity.values.forEach { it.clear() }
tag2BlockState.values.forEach { it.clear() }
@ -366,7 +396,12 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
}
override var isValid: Boolean = false
private set
private set(value) {
if (value != field) {
field = value
generation++
}
}
private var iterator = this.parts.values.iterator()
private var validParts = 0
@ -565,6 +600,12 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
}
private var activeConfig: Config = north
set(value) {
if (field !== value) {
field = value
generation++
}
}
override val currentDirection: Direction?
get() = if (isValid) activeConfig.currentDirection else null
@ -606,6 +647,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
fun update(levelAccessor: LevelAccessor): Boolean {
isUpdating = true
val thisGeneration = generation
try {
val configurations = LinkedList<Config>()
@ -627,6 +669,11 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
activeConfig = config
isValid = true
remotes.forEach { it.listener.run() }
if (thisGeneration != generation) {
changeListeners.forEach { it.runnable.run() }
}
return true
} else {
config.clear()
@ -634,6 +681,10 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
}
}
if (thisGeneration != generation) {
changeListeners.forEach { it.runnable.run() }
}
return false
} finally {
isUpdating = false
@ -642,6 +693,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
fun update(levelAccessor: LevelAccessor, direction: Direction): Boolean {
isUpdating = true
val thisGeneration = generation
try {
var changes = false
@ -673,6 +725,10 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
remotes.forEach { it.listener.run() }
}
if (thisGeneration != generation) {
changeListeners.forEach { it.runnable.run() }
}
return isValid
} finally {
isUpdating = false
@ -680,6 +736,7 @@ class ShapedMultiblock(pos: BlockPos, factory: ShapedMultiblockFactory) : IMulti
}
override fun close() {
changeListeners.clear()
remotes.forEach { it.close() }
configurations.forEach { it.clear() }
isValid = false

View File

@ -0,0 +1,53 @@
package ru.dbotthepony.mc.otm.core.util
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.util.RandomSource
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.shuffle
import java.util.function.Supplier
class CapabilityListIterator<T>(
val provider: Supplier<out List<T>>,
val random: Supplier<RandomSource?>,
) {
private var shuffleCache = IntArray(0)
private fun doIterate(values: List<T>, value: Decimal, simulate: Boolean, walker: T.(Decimal, Boolean) -> Decimal, indexProvider: () -> IntIterator): Decimal {
var leftover = value
for (index in indexProvider()) {
val provider = values[index]
leftover -= walker(provider, leftover, true)
if (leftover.signum() <= 0) break
}
if (simulate) return value - leftover
leftover = value
for (index in indexProvider()) {
val provider = values[index]
leftover -= walker(provider, leftover, false)
if (leftover.signum() <= 0) break
}
return value - leftover
}
fun iterate(value: Decimal, simulate: Boolean, walker: T.(Decimal, Boolean) -> Decimal): Decimal {
val providers = provider.get()
if (providers.isEmpty()) return Decimal.ZERO
val random = random.get()
if (random == null || providers.size == 1) {
return doIterate(providers, value, simulate, walker, providers.indices::iterator)
} else {
if (shuffleCache.size != providers.size) {
shuffleCache = IntArray(providers.size) { it }
}
shuffleCache.shuffle(random)
return doIterate(providers, value, simulate, walker, shuffleCache::iterator)
}
}
}