Improve performance on cable addition and removal from cable network

This commit is contained in:
DBotThePony 2025-02-11 01:12:58 +07:00
parent 614ba26da6
commit e68f3a7996
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 36 additions and 15 deletions

View File

@ -111,11 +111,6 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP
_segment = value
}
fun onInvalidate() {
_segment = EnergyCableGraph.Segment(this)
updatePoweredState(false)
}
val sides get() = energySides
override fun onNeighbour(link: Link) {

View File

@ -68,7 +68,7 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
}
}
class SegmentPath(private val a: BlockPos, private val b: BlockPos) {
class SegmentPath(val a: EnergyCableBlockEntity.Node, val b: EnergyCableBlockEntity.Node) {
val segments = LinkedHashSet<Segment>()
val nodes = HashSet<EnergyCableBlockEntity.Node>()
var shortCircuit = false
@ -136,7 +136,7 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
}
private val nodes = LinkedHashSet<EnergyCableBlockEntity.Node>()
private var paths = ReferenceLinkedOpenHashSet<SegmentPath>()
var paths = ReferenceLinkedOpenHashSet<SegmentPath>()
operator fun contains(node: EnergyCableBlockEntity.Node): Boolean {
return node in nodes
@ -338,6 +338,26 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
}
}
fun split(): List<Segment> {
val result = ArrayList<Segment>()
result.add(this)
for (v in nodes) {
val segment = Segment()
v._segment = segment
segment.nodes.add(v)
segment.throughput = v.energyThroughput
segment.throughputKnown = true
segment.transferredLastTick = transferredLastTick
result.add(segment)
v.updatePoweredState(false)
}
// mark this segment as dead
this.nodes.clear()
return result
}
private fun combineInto(segment: Segment) {
nodes.forEach { it._segment = segment }
segment.nodes.addAll(nodes)
@ -385,11 +405,6 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
}
}
fun invalidatePathCache() {
pathCache.clear()
nodes.forEach { it.onInvalidate() }
}
// isn't exactly A*, but greedy algorithm, which searched for locally optimal solutions because they lead to globally optimal ones
private fun findPath(a: EnergyCableBlockEntity.Node, b: EnergyCableBlockEntity.Node, existing: Collection<SegmentPath>, threshold: Decimal): SegmentPath? {
val seenTop = existing.any { a in it }
@ -435,7 +450,7 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
}
}
val path = SegmentPath(a.blockEntity.blockPos, b.blockEntity.blockPos)
val path = SegmentPath(a, b)
solution.forEach { it.segment.add(path) }
touchedSegments.forEach { it.tryCombine(touchedSegments) }
@ -490,18 +505,29 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
return list.paths
}
fun notifyThroughputsChanged() {
pathCache.values.forEach { it.saturated = false }
}
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
if (livelyNodes.remove(node)) {
check(livelyNodesList.remove(node))
}
invalidatePathCache()
node.segment.paths.forEach {
pathCache.remove(it.a to it.b)
pathCache.remove(it.b to it.a)
}
node.segment.paths = ReferenceLinkedOpenHashSet()
node.segment.split()
}
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
check(livelyNodes.add(node))
livelyNodesList.add(node)
invalidatePathCache()
notifyThroughputsChanged()
}
fun receiveEnergy(howMuch: Decimal, simulate: Boolean, fromNode: EnergyCableBlockEntity.Node, fromSide: RelativeSide): Decimal {