Handle recursive lively nodes removal gracefully
This commit is contained in:
parent
03dfef00c4
commit
e85bc72ef2
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity.cable
|
package ru.dbotthepony.mc.otm.block.entity.cable
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntRBTreeSet
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet
|
||||||
@ -20,7 +21,6 @@ import ru.dbotthepony.mc.otm.graph.GraphNodeList
|
|||||||
import ru.dbotthepony.mc.otm.onceServer
|
import ru.dbotthepony.mc.otm.onceServer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
import kotlin.ConcurrentModificationException
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.HashSet
|
import kotlin.collections.HashSet
|
||||||
import kotlin.collections.LinkedHashSet
|
import kotlin.collections.LinkedHashSet
|
||||||
@ -85,9 +85,6 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
ContainsStatus.ABOUT_TO_BE_REMOVED, ContainsStatus.ABOUT_TO_BE_ADDED -> { } // do nothing
|
ContainsStatus.ABOUT_TO_BE_REMOVED, ContainsStatus.ABOUT_TO_BE_ADDED -> { } // do nothing
|
||||||
ContainsStatus.DOES_NOT_BELONG -> throw IllegalArgumentException("$node does not belong to $this")
|
ContainsStatus.DOES_NOT_BELONG -> throw IllegalArgumentException("$node does not belong to $this")
|
||||||
ContainsStatus.CONTAINS -> {
|
ContainsStatus.CONTAINS -> {
|
||||||
if (isIteratingNodes)
|
|
||||||
throw ConcurrentModificationException("Bug trap: currently iterating energy receivers!")
|
|
||||||
|
|
||||||
for (dir in RelativeSide.entries) {
|
for (dir in RelativeSide.entries) {
|
||||||
val pair = node to dir
|
val pair = node to dir
|
||||||
|
|
||||||
@ -594,9 +591,6 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
||||||
if (isIteratingNodes)
|
|
||||||
throw ConcurrentModificationException("Bug trap: currently iterating energy receivers!")
|
|
||||||
|
|
||||||
for (dir in RelativeSide.entries) {
|
for (dir in RelativeSide.entries) {
|
||||||
val pair = node to dir
|
val pair = node to dir
|
||||||
|
|
||||||
@ -625,9 +619,6 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
|
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
|
||||||
if (isIteratingNodes)
|
|
||||||
throw ConcurrentModificationException("Bug trap: currently iterating energy receivers!")
|
|
||||||
|
|
||||||
for (dir in RelativeSide.entries) {
|
for (dir in RelativeSide.entries) {
|
||||||
val pair = node to dir
|
val pair = node to dir
|
||||||
check(livelyNodes.add(pair))
|
check(livelyNodes.add(pair))
|
||||||
@ -637,19 +628,25 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
notifyThroughputsChanged()
|
notifyThroughputsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isIteratingNodes = false
|
private val indicesToRemove = IntRBTreeSet()
|
||||||
|
private var recursionLevel = 0
|
||||||
|
|
||||||
fun receiveEnergy(howMuch: Decimal, simulate: Boolean, fromNode: EnergyCableBlockEntity.Node, fromSide: RelativeSide): Decimal {
|
fun receiveEnergy(howMuch: Decimal, simulate: Boolean, fromNode: EnergyCableBlockEntity.Node, fromSide: RelativeSide): Decimal {
|
||||||
livelyNodesList.shuffle(fromNode.blockEntity.level!!.otmRandom)
|
val thisLevel = ++recursionLevel
|
||||||
|
val isMaster = thisLevel == 1
|
||||||
|
|
||||||
|
if (isMaster)
|
||||||
|
livelyNodesList.shuffle(fromNode.blockEntity.level!!.otmRandom)
|
||||||
|
|
||||||
|
var i = -1
|
||||||
val itr = livelyNodesList.iterator()
|
val itr = livelyNodesList.iterator()
|
||||||
var received = Decimal.ZERO
|
var received = Decimal.ZERO
|
||||||
var residue = howMuch.coerceAtMost(fromNode.energyThroughput)
|
var residue = howMuch.coerceAtMost(fromNode.energyThroughput)
|
||||||
val snapshot = Reference2ObjectOpenHashMap<Segment, Decimal>()
|
val snapshot = Reference2ObjectOpenHashMap<Segment, Decimal>()
|
||||||
|
|
||||||
isIteratingNodes = true
|
|
||||||
|
|
||||||
for (pair in itr) {
|
for (pair in itr) {
|
||||||
|
i++
|
||||||
|
|
||||||
// recursion prevention
|
// recursion prevention
|
||||||
if (!fromNode.currentlyTransferringTo.add(pair))
|
if (!fromNode.currentlyTransferringTo.add(pair))
|
||||||
continue
|
continue
|
||||||
@ -659,8 +656,12 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
val side = node.sides[relSide]!!
|
val side = node.sides[relSide]!!
|
||||||
|
|
||||||
if (!side.isEnabled) {
|
if (!side.isEnabled) {
|
||||||
itr.remove()
|
if (isMaster)
|
||||||
check(livelyNodes.remove(pair)) { "Lively nodes Set does not contain $pair" }
|
itr.remove()
|
||||||
|
else
|
||||||
|
indicesToRemove.add(i)
|
||||||
|
|
||||||
|
livelyNodes.remove(pair)
|
||||||
continue
|
continue
|
||||||
} else if (fromNode === node && side.side === fromSide) {
|
} else if (fromNode === node && side.side === fromSide) {
|
||||||
continue
|
continue
|
||||||
@ -669,8 +670,12 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
val it = side.neighbour.get()
|
val it = side.neighbour.get()
|
||||||
|
|
||||||
if (it == null || it is EnergyCableBlockEntity.CableSide) {
|
if (it == null || it is EnergyCableBlockEntity.CableSide) {
|
||||||
itr.remove()
|
if (isMaster)
|
||||||
check(livelyNodes.remove(pair)) { "Lively nodes Set does not contain $pair" }
|
itr.remove()
|
||||||
|
else
|
||||||
|
indicesToRemove.add(i)
|
||||||
|
|
||||||
|
livelyNodes.remove(pair)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -751,7 +756,17 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isIteratingNodes = false
|
recursionLevel--
|
||||||
|
|
||||||
|
if (isMaster && indicesToRemove.isNotEmpty()) {
|
||||||
|
val indices = indicesToRemove.iterator(indicesToRemove.lastInt())
|
||||||
|
|
||||||
|
while (indices.hasPrevious()) {
|
||||||
|
livelyNodesList.removeAt(indices.previousInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
indicesToRemove.clear()
|
||||||
|
}
|
||||||
|
|
||||||
return received
|
return received
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user