Merge remote-tracking branch 'origin/1.21' into 1.21
This commit is contained in:
commit
c5c5b04c3f
@ -58,7 +58,7 @@ private fun decoratives(provider: MatteryLanguageProvider) {
|
|||||||
add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description1", FEELING_SAFE_NOW)
|
add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description1", FEELING_SAFE_NOW)
|
||||||
add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description2", "Данный вариант выкрашен в $name")
|
add(MBlocks.TRITANIUM_TRAPDOOR[color]!!, "description2", "Данный вариант выкрашен в $name")
|
||||||
|
|
||||||
add(MBlocks.GRILL[color]!!, "$nameAdj мангал-дипломат")
|
add(MBlocks.GRILL[color]!!, "$name мангал-дипломат")
|
||||||
}
|
}
|
||||||
|
|
||||||
add(MRegistry.TRITANIUM_PRESSURE_PLATE.block, "Тритановая нажимная пластина")
|
add(MRegistry.TRITANIUM_PRESSURE_PLATE.block, "Тритановая нажимная пластина")
|
||||||
|
@ -9,6 +9,8 @@ import net.minecraft.world.item.ItemStack
|
|||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.item.crafting.Ingredient
|
import net.minecraft.world.item.crafting.Ingredient
|
||||||
import net.neoforged.neoforge.common.Tags
|
import net.neoforged.neoforge.common.Tags
|
||||||
|
import net.neoforged.neoforge.common.conditions.NotCondition
|
||||||
|
import net.neoforged.neoforge.common.conditions.TagEmptyCondition
|
||||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.config.CablesConfig
|
import ru.dbotthepony.mc.otm.config.CablesConfig
|
||||||
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
||||||
@ -530,6 +532,7 @@ fun addCraftingTableRecipes(consumer: RecipeOutput) {
|
|||||||
.build(consumer)
|
.build(consumer)
|
||||||
|
|
||||||
val ironRod = ItemTags.create(ResourceLocation("c", "rods/iron"))
|
val ironRod = ItemTags.create(ResourceLocation("c", "rods/iron"))
|
||||||
|
var condConsumer = consumer.withConditions(NotCondition(TagEmptyCondition(ironRod)))
|
||||||
|
|
||||||
for ((color, item) in MItems.GRILL) {
|
for ((color, item) in MItems.GRILL) {
|
||||||
MatteryRecipe(item, category = RecipeCategory.DECORATIONS)
|
MatteryRecipe(item, category = RecipeCategory.DECORATIONS)
|
||||||
@ -542,13 +545,13 @@ fun addCraftingTableRecipes(consumer: RecipeOutput) {
|
|||||||
.rowB(color?.tag)
|
.rowB(color?.tag)
|
||||||
.row(ironRod, ironRod, ironRod)
|
.row(ironRod, ironRod, ironRod)
|
||||||
.rowAC(MItemTags.TRITANIUM_INGOTS, MItemTags.TRITANIUM_INGOTS)
|
.rowAC(MItemTags.TRITANIUM_INGOTS, MItemTags.TRITANIUM_INGOTS)
|
||||||
.build(consumer, "grill_alt_a/${color?.name?.lowercase() ?: "default"}")
|
.build(condConsumer, "grill_alt_a/${color?.name?.lowercase() ?: "default"}")
|
||||||
|
|
||||||
MatteryRecipe(item, category = RecipeCategory.DECORATIONS)
|
MatteryRecipe(item, category = RecipeCategory.DECORATIONS)
|
||||||
.rowB(color?.tag)
|
.rowB(color?.tag)
|
||||||
.row(ironRod, ironRod, ironRod)
|
.row(ironRod, ironRod, ironRod)
|
||||||
.rowB(MItemTags.TRITANIUM_PLATES)
|
.rowB(MItemTags.TRITANIUM_PLATES)
|
||||||
.build(consumer, "grill_alt_b/${color?.name?.lowercase() ?: "default"}")
|
.build(condConsumer, "grill_alt_b/${color?.name?.lowercase() ?: "default"}")
|
||||||
|
|
||||||
MatteryRecipe(item, category = RecipeCategory.DECORATIONS)
|
MatteryRecipe(item, category = RecipeCategory.DECORATIONS)
|
||||||
.rowB(color?.tag)
|
.rowB(color?.tag)
|
||||||
|
@ -111,11 +111,6 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP
|
|||||||
_segment = value
|
_segment = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onInvalidate() {
|
|
||||||
_segment = EnergyCableGraph.Segment(this)
|
|
||||||
updatePoweredState(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
val sides get() = energySides
|
val sides get() = energySides
|
||||||
|
|
||||||
override fun onNeighbour(link: Link) {
|
override fun onNeighbour(link: Link) {
|
||||||
|
@ -8,6 +8,11 @@ import org.apache.logging.log4j.LogManager
|
|||||||
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
||||||
import ru.dbotthepony.mc.otm.UNIVERSE_TICKS
|
import ru.dbotthepony.mc.otm.UNIVERSE_TICKS
|
||||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||||
|
import ru.dbotthepony.mc.otm.config.CablesConfig
|
||||||
|
import ru.dbotthepony.mc.otm.core.addAll
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.max
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.reduce
|
||||||
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.shuffle
|
import ru.dbotthepony.mc.otm.core.shuffle
|
||||||
@ -66,8 +71,9 @@ 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 segments = LinkedHashSet<Segment>()
|
||||||
|
val nodes = HashSet<EnergyCableBlockEntity.Node>()
|
||||||
var shortCircuit = false
|
var shortCircuit = false
|
||||||
private var lastTickTransfers = 0
|
private var lastTickTransfers = 0
|
||||||
private var lastTick = 0
|
private var lastTick = 0
|
||||||
@ -80,7 +86,7 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
}
|
}
|
||||||
|
|
||||||
operator fun contains(node: EnergyCableBlockEntity.Node): Boolean {
|
operator fun contains(node: EnergyCableBlockEntity.Node): Boolean {
|
||||||
return segments.any { node in it }
|
return node in nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@ -133,7 +139,7 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val nodes = LinkedHashSet<EnergyCableBlockEntity.Node>()
|
private val nodes = LinkedHashSet<EnergyCableBlockEntity.Node>()
|
||||||
private var paths = ReferenceLinkedOpenHashSet<SegmentPath>()
|
var paths = ReferenceLinkedOpenHashSet<SegmentPath>()
|
||||||
|
|
||||||
operator fun contains(node: EnergyCableBlockEntity.Node): Boolean {
|
operator fun contains(node: EnergyCableBlockEntity.Node): Boolean {
|
||||||
return node in nodes
|
return node in nodes
|
||||||
@ -165,6 +171,11 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
private set
|
private set
|
||||||
|
|
||||||
val availableThroughput: Decimal get() {
|
val availableThroughput: Decimal get() {
|
||||||
|
if (lastTick != UNIVERSE_TICKS) {
|
||||||
|
transferredLastTick = Decimal.ZERO
|
||||||
|
lastTick = UNIVERSE_TICKS
|
||||||
|
}
|
||||||
|
|
||||||
checkThroughput()
|
checkThroughput()
|
||||||
return throughput - transferredLastTick
|
return throughput - transferredLastTick
|
||||||
}
|
}
|
||||||
@ -283,11 +294,13 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
fun remove(node: EnergyCableBlockEntity.Node) {
|
fun remove(node: EnergyCableBlockEntity.Node) {
|
||||||
check(nodes.remove(node)) { "Tried to remove node $node from segment $this, but that node does not belong to this segment" }
|
check(nodes.remove(node)) { "Tried to remove node $node from segment $this, but that node does not belong to this segment" }
|
||||||
|
|
||||||
|
paths.forEach { it.nodes.remove(node) }
|
||||||
throughputKnown = false
|
throughputKnown = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(node: EnergyCableBlockEntity.Node) {
|
fun add(node: EnergyCableBlockEntity.Node) {
|
||||||
check(nodes.add(node)) { "Tried to add node $node to segment $this, but we already have that node added" }
|
check(nodes.add(node)) { "Tried to add node $node to segment $this, but we already have that node added" }
|
||||||
|
paths.forEach { it.nodes.add(node) }
|
||||||
|
|
||||||
if (throughputKnown)
|
if (throughputKnown)
|
||||||
throughput = maxOf(throughput, node.energyThroughput)
|
throughput = maxOf(throughput, node.energyThroughput)
|
||||||
@ -296,12 +309,14 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
fun add(path: SegmentPath) {
|
fun add(path: SegmentPath) {
|
||||||
if (paths.add(path)) {
|
if (paths.add(path)) {
|
||||||
check(path.segments.add(this)) { "Path set and Segment disagree whenever $this is absent from $path" }
|
check(path.segments.add(this)) { "Path set and Segment disagree whenever $this is absent from $path" }
|
||||||
|
path.nodes.addAll(nodes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(path: SegmentPath) {
|
fun remove(path: SegmentPath) {
|
||||||
check(paths.remove(path)) { "Path $path should already contain $this" }
|
check(paths.remove(path)) { "Path $path should already contain $this" }
|
||||||
check(path.segments.remove(this)) { "Path set and Segment disagree whenever $this is present in $path" }
|
check(path.segments.remove(this)) { "Path set and Segment disagree whenever $this is present in $path" }
|
||||||
|
path.nodes.removeAll(nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// breaks "instant snapshots" of segments atm
|
// breaks "instant snapshots" of segments atm
|
||||||
@ -331,6 +346,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) {
|
private fun combineInto(segment: Segment) {
|
||||||
nodes.forEach { it._segment = segment }
|
nodes.forEach { it._segment = segment }
|
||||||
segment.nodes.addAll(nodes)
|
segment.nodes.addAll(nodes)
|
||||||
@ -378,11 +413,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
|
// 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? {
|
private fun findPath(a: EnergyCableBlockEntity.Node, b: EnergyCableBlockEntity.Node, existing: Collection<SegmentPath>, threshold: Decimal): SegmentPath? {
|
||||||
val seenTop = existing.any { a in it }
|
val seenTop = existing.any { a in it }
|
||||||
@ -428,7 +458,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) }
|
solution.forEach { it.segment.add(path) }
|
||||||
touchedSegments.forEach { it.tryCombine(touchedSegments) }
|
touchedSegments.forEach { it.tryCombine(touchedSegments) }
|
||||||
|
|
||||||
@ -446,23 +476,34 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var lastTickSearches = 0
|
||||||
|
private var searchedOnTick = 0
|
||||||
|
|
||||||
private fun getPath(a: EnergyCableBlockEntity.Node, b: EnergyCableBlockEntity.Node, energyToTransfer: Decimal, sort: Boolean): List<SegmentPath> {
|
private fun getPath(a: EnergyCableBlockEntity.Node, b: EnergyCableBlockEntity.Node, energyToTransfer: Decimal, sort: Boolean): List<SegmentPath> {
|
||||||
if (!a.canTraverse || !b.canTraverse)
|
if (!a.canTraverse || !b.canTraverse)
|
||||||
return listOf()
|
return listOf()
|
||||||
|
|
||||||
|
if (searchedOnTick != UNIVERSE_TICKS) {
|
||||||
|
searchedOnTick = UNIVERSE_TICKS
|
||||||
|
lastTickSearches = 0
|
||||||
|
}
|
||||||
|
|
||||||
val list = pathCache.computeIfAbsent(a to b) { CacheEntry() }
|
val list = pathCache.computeIfAbsent(a to b) { CacheEntry() }
|
||||||
|
|
||||||
if (!list.saturated) {
|
val maxSearches = CablesConfig.SEARCHES_PER_TICK
|
||||||
var maxThroughput = list.paths.maxOfOrNull { it.availableThroughput } ?: Decimal.ZERO
|
|
||||||
|
|
||||||
while (maxThroughput < energyToTransfer && !list.saturated) {
|
if (!list.saturated && lastTickSearches <= maxSearches) {
|
||||||
|
var maxThroughput = list.paths.iterator().map { it.availableThroughput }.reduce(Decimal.ZERO, Decimal::plus)
|
||||||
|
|
||||||
|
while (maxThroughput < energyToTransfer && !list.saturated && ++lastTickSearches <= maxSearches) {
|
||||||
|
// TODO: Heuristics here is wrong
|
||||||
val find = findPath(a, b, list.paths, maxThroughput)
|
val find = findPath(a, b, list.paths, maxThroughput)
|
||||||
|
|
||||||
if (find == null || find in list.paths) {
|
if (find == null || find in list.paths) {
|
||||||
list.saturated = true
|
list.saturated = true
|
||||||
} else {
|
} else {
|
||||||
list.paths.add(find)
|
list.paths.add(find)
|
||||||
maxThroughput = maxOf(maxThroughput, find.availableThroughput)
|
maxThroughput += find.availableThroughput
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,18 +514,29 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
return list.paths
|
return list.paths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun notifyThroughputsChanged() {
|
||||||
|
pathCache.values.forEach { it.saturated = false }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
||||||
if (livelyNodes.remove(node)) {
|
if (livelyNodes.remove(node)) {
|
||||||
check(livelyNodesList.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) {
|
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
|
||||||
check(livelyNodes.add(node))
|
check(livelyNodes.add(node))
|
||||||
livelyNodesList.add(node)
|
livelyNodesList.add(node)
|
||||||
invalidatePathCache()
|
|
||||||
|
notifyThroughputsChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun receiveEnergy(howMuch: Decimal, simulate: Boolean, fromNode: EnergyCableBlockEntity.Node, fromSide: RelativeSide): Decimal {
|
fun receiveEnergy(howMuch: Decimal, simulate: Boolean, fromNode: EnergyCableBlockEntity.Node, fromSide: RelativeSide): Decimal {
|
||||||
|
@ -27,4 +27,10 @@ object CablesConfig : AbstractConfig("cables") {
|
|||||||
init {
|
init {
|
||||||
E.SUPERCONDUCTOR
|
E.SUPERCONDUCTOR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val SEARCHES_PER_TICK: Int by builder
|
||||||
|
.comment("How many paths are allowed to be searched for during single tick *per* cable network")
|
||||||
|
.comment("Too low value will make huge cable networks woozy when their cabling changes (e.g. cable added or removed, or valve switched)")
|
||||||
|
.comment("Too high value will create lag spikes depending on complexity of cable network at hand when cabling changes")
|
||||||
|
.defineInRange("SEARCHER_PER_TICK", 40, 1)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user