From 9579bc6a0cccd2b307f158195919a2257d106319 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 19 Jan 2025 20:56:32 +0700 Subject: [PATCH 1/5] LinkedHashSet instead of ObjectLinkedOpenHashSet for update performance because LinkedHashSet uses linked list, while ObjectLinkedOpenHashSet use sequential array of keys --- .../mc/otm/block/entity/cable/EnergyCableGraph.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt index 13e60b2b5..85764bd1e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt @@ -1,8 +1,5 @@ package ru.dbotthepony.mc.otm.block.entity.cable -import it.unimi.dsi.fastutil.ints.IntLists -import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.ReferenceArraySet import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet @@ -19,6 +16,7 @@ import ru.dbotthepony.mc.otm.onceServer import java.util.* import kotlin.collections.ArrayList import kotlin.collections.HashSet +import kotlin.collections.LinkedHashSet import kotlin.math.ln class EnergyCableGraph : GraphNodeList() { @@ -69,7 +67,7 @@ class EnergyCableGraph : GraphNodeList() + val segments = LinkedHashSet() private var shortCircuit = false private var lastTickTransfers = 0 private var lastTick = 0 @@ -134,7 +132,7 @@ class EnergyCableGraph : GraphNodeList() + private val nodes = LinkedHashSet() private val paths = ReferenceOpenHashSet() operator fun contains(node: EnergyCableBlockEntity.Node): Boolean { From aa41647c04323b5537bce17b83f53ce5383c2a60 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 19 Jan 2025 21:12:59 +0700 Subject: [PATCH 2/5] Speed up cable Segment splitting --- .../mc/otm/block/entity/cable/EnergyCableGraph.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt index 85764bd1e..b9fc82069 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt @@ -307,13 +307,21 @@ class EnergyCableGraph : GraphNodeList Date: Sun, 19 Jan 2025 22:51:37 +0700 Subject: [PATCH 3/5] Greatly improve cable network segment slicing and splicing --- .../block/entity/cable/EnergyCableGraph.kt | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt index b9fc82069..dfd5df626 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt @@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.block.entity.cable import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.ReferenceArraySet -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet import net.minecraft.core.BlockPos import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.SERVER_IS_LIVE @@ -133,12 +133,24 @@ class EnergyCableGraph : GraphNodeList() - private val paths = ReferenceOpenHashSet() + private var paths = ReferenceLinkedOpenHashSet() operator fun contains(node: EnergyCableBlockEntity.Node): Boolean { return node in nodes } + fun missingNodes(from: Collection): List { + val missing = ArrayList() + + this.nodes.forEach { + if (it !in from) { + missing.add(it) + } + } + + return missing + } + var throughput = Decimal.ZERO private set @@ -282,8 +294,9 @@ class EnergyCableGraph : GraphNodeList { - if (nodes.isEmpty()) { - throw IllegalStateException("Empty segment somehow?") - } else if (nodes.size == 1) { + fun split(nodes: Collection): List { + for (node in nodes) + require(node in this.nodes) { "$node does not belong to $this" } + + if (this.nodes.size == 1) { return listOf(this) } else { - lastPoweredStatus = 0 - val list = ArrayList(nodes) - val itr = list.iterator() - itr.next() val result = ArrayList() result.add(this) - for (v in itr) { - v._segment = Segment() - v.segment.nodes.add(v) + for (v in nodes) { + v.segment = Segment() v.segment.throughput = v.energyThroughput v.segment.throughputKnown = true v.segment.transferredLastTick = transferredLastTick - v.segment.paths.addAll(paths) + v.segment.lastPoweredStatus = lastPoweredStatus + v.segment.paths = paths.clone() paths.forEach { it.segments.add(v.segment) } result.add(v.segment) } - nodes.clear() - nodes.add(list[0]) - throughput = list[0].energyThroughput - throughputKnown = true - return result } } @@ -397,7 +402,7 @@ class EnergyCableGraph : GraphNodeList() + val solution = LinkedHashSet() var last = first.parent solution.add(first.node) @@ -408,10 +413,23 @@ class EnergyCableGraph : GraphNodeList() - solution.forEach { touchedSegments.addAll(it.segment.split()) } + + for (it in solution) { + if (it.segment in touchedSegments) + continue + + val diff = it.segment.missingNodes(solution) + + // segment satisfies new constraints + if (diff.isEmpty()) { + touchedSegments.add(it.segment) + } else { + touchedSegments.addAll(it.segment.split(diff)) + } + } + val path = SegmentPath(a.blockEntity.blockPos, b.blockEntity.blockPos) solution.forEach { it.segment.add(path) } - touchedSegments.forEach { it.tryCombine(touchedSegments) } return path From 3f91e554cbcc5de7c4e656a508c876efcff159fd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 19 Jan 2025 23:12:18 +0700 Subject: [PATCH 4/5] Throttle "powered" cable updates even further when it doesn't oscillate --- .../dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt index dfd5df626..b7fefc158 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt @@ -202,9 +202,9 @@ class EnergyCableGraph : GraphNodeList Date: Mon, 20 Jan 2025 08:41:53 +0700 Subject: [PATCH 5/5] Ronna and Quetta SI prefixes --- .../mc/otm/datagen/lang/English.kt | 7 ++++ .../mc/otm/datagen/lang/Russian.kt | 8 +++++ .../dbotthepony/mc/otm/core/util/SiPrefix.kt | 34 ++++++++++--------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 8755aca87..ff508b9cb 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -261,6 +261,8 @@ private fun misc(provider: MatteryLanguageProvider) { misc("suffix.exa", "%s E%s") misc("suffix.zetta", "%s Z%s") misc("suffix.yotta", "%s Y%s") + misc("suffix.ronna", "%s R%s") + misc("suffix.quetta", "%s Q%s") misc("suffix.deci", "%s d%s") misc("suffix.centi", "%s c%s") @@ -282,6 +284,8 @@ private fun misc(provider: MatteryLanguageProvider) { misc("suffix_concise.exa", "%sE") misc("suffix_concise.zetta", "%sZ") misc("suffix_concise.yotta", "%sY") + misc("suffix_concise.ronna", "%sR") + misc("suffix_concise.quetta", "%sQ") misc("suffix_concise.deci", "%sd") misc("suffix_concise.centi", "%sc") @@ -302,6 +306,9 @@ private fun misc(provider: MatteryLanguageProvider) { misc("suffix_raw.exa", "E") misc("suffix_raw.zetta", "Z") misc("suffix_raw.yotta", "Y") + misc("suffix_raw.ronna", "R") + misc("suffix_raw.quetta", "Q") + misc("suffix_raw.deci", "d") misc("suffix_raw.centi", "c") misc("suffix_raw.milli", "m") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index d45ac6c92..4a059c766 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -269,6 +269,8 @@ private fun misc(provider: MatteryLanguageProvider) { misc("suffix.exa", "%s Э%s") misc("suffix.zetta", "%s З%s") misc("suffix.yotta", "%s И%s") + misc("suffix.ronna", "%s Рн%s") + misc("suffix.quetta", "%s Кв%s") misc("suffix.deci", "%s д%s") misc("suffix.centi", "%s с%s") @@ -290,6 +292,9 @@ private fun misc(provider: MatteryLanguageProvider) { misc("suffix_concise.exa", "%sЭ") misc("suffix_concise.zetta", "%sЗ") misc("suffix_concise.yotta", "%sИ") + misc("suffix_concise.ronna", "%sРн") + misc("suffix_concise.quetta", "%sКв") + misc("suffix_concise.deci", "%sд") misc("suffix_concise.centi", "%sс") misc("suffix_concise.milli", "%sм") @@ -309,6 +314,9 @@ private fun misc(provider: MatteryLanguageProvider) { misc("suffix_raw.exa", "Э") misc("suffix_raw.zetta", "З") misc("suffix_raw.yotta", "И") + misc("suffix_raw.ronna", "Рн") + misc("suffix_raw.quetta", "Кв") + misc("suffix_raw.deci", "д") misc("suffix_raw.centi", "с") misc("suffix_raw.milli", "м") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt index 0b21620a0..7f4507279 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/SiPrefix.kt @@ -9,14 +9,14 @@ import java.math.BigInteger import kotlin.math.absoluteValue enum class SiPrefix(val power: Int, val symbol: String) { - YOCTO(-8, "y"), - ZEPTO(-7, "z"), - ATTO (-6, "a"), - FEMTO(-5, "f"), - PICO (-4, "p"), - NANO (-3, "n"), - MICRO(-2, "μ"), - MILLI(-1, "m"), + YOCTO (-8, "y"), + ZEPTO (-7, "z"), + ATTO (-6, "a"), + FEMTO (-5, "f"), + PICO (-4, "p"), + NANO (-3, "n"), + MICRO (-2, "μ"), + MILLI (-1, "m"), NONE(0, "") { override val isEmpty: Boolean @@ -26,14 +26,16 @@ enum class SiPrefix(val power: Int, val symbol: String) { get() = 0 }, - KILO (1, "k"), - MEGA (2, "M"), - GIGA (3, "G"), - TERA (4, "T"), - PETA (5, "P"), - EXA (6, "E"), - ZETTA(7, "Z"), - YOTTA(8, "Y"); + KILO (1, "k"), + MEGA (2, "M"), + GIGA (3, "G"), + TERA (4, "T"), + PETA (5, "P"), + EXA (6, "E"), + ZETTA (7, "Z"), + YOTTA (8, "Y"), + RONNA (9, "R"), + QUETTA(10, "Q"); open val isEmpty: Boolean get() = false