Energy cable tiers, fix some Client -> Server logic leaks in singleplayer
This commit is contained in:
parent
023081eaaa
commit
1c0cdb8b5b
@ -50,6 +50,7 @@ fun addLootTables(lootTables: LootTables) {
|
|||||||
lootTables.dropsSelf(MBlocks.METAL_BEAM) { condition(ExplosionCondition.survivesExplosion()) }
|
lootTables.dropsSelf(MBlocks.METAL_BEAM) { condition(ExplosionCondition.survivesExplosion()) }
|
||||||
lootTables.dropsSelf(MBlocks.TRITANIUM_INGOT_BLOCK) { condition(ExplosionCondition.survivesExplosion()) }
|
lootTables.dropsSelf(MBlocks.TRITANIUM_INGOT_BLOCK) { condition(ExplosionCondition.survivesExplosion()) }
|
||||||
lootTables.dropsSelf(MBlocks.TRITANIUM_BARS) { condition(ExplosionCondition.survivesExplosion()) }
|
lootTables.dropsSelf(MBlocks.TRITANIUM_BARS) { condition(ExplosionCondition.survivesExplosion()) }
|
||||||
|
lootTables.dropsSelf(MBlocks.ENERGY_CABLES.values) { condition(ExplosionCondition.survivesExplosion()) }
|
||||||
|
|
||||||
lootTables.dropsSelf(MBlocks.INFINITE_WATER_SOURCE) { condition(ExplosionCondition.survivesExplosion()) }
|
lootTables.dropsSelf(MBlocks.INFINITE_WATER_SOURCE) { condition(ExplosionCondition.survivesExplosion()) }
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ fun addTags(tagsProvider: TagsProvider) {
|
|||||||
tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_DOOR.values, Tiers.IRON)
|
tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_DOOR.values, Tiers.IRON)
|
||||||
tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_TRAPDOOR.values, Tiers.IRON)
|
tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_TRAPDOOR.values, Tiers.IRON)
|
||||||
tagsProvider.requiresPickaxe(MBlocks.PAINTER, Tiers.STONE)
|
tagsProvider.requiresPickaxe(MBlocks.PAINTER, Tiers.STONE)
|
||||||
|
tagsProvider.requiresPickaxe(MBlocks.ENERGY_CABLES.values, Tiers.STONE)
|
||||||
|
|
||||||
tagsProvider.requiresPickaxe(listOf(
|
tagsProvider.requiresPickaxe(listOf(
|
||||||
MBlocks.ANDROID_STATION,
|
MBlocks.ANDROID_STATION,
|
||||||
|
@ -39,6 +39,7 @@ import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer
|
|||||||
import ru.dbotthepony.mc.otm.compat.adastra.AdAstraCompatKt;
|
import ru.dbotthepony.mc.otm.compat.adastra.AdAstraCompatKt;
|
||||||
import ru.dbotthepony.mc.otm.compat.curios.CuriosCompatKt;
|
import ru.dbotthepony.mc.otm.compat.curios.CuriosCompatKt;
|
||||||
import ru.dbotthepony.mc.otm.config.AndroidConfig;
|
import ru.dbotthepony.mc.otm.config.AndroidConfig;
|
||||||
|
import ru.dbotthepony.mc.otm.config.CablesConfig;
|
||||||
import ru.dbotthepony.mc.otm.config.ClientConfig;
|
import ru.dbotthepony.mc.otm.config.ClientConfig;
|
||||||
import ru.dbotthepony.mc.otm.config.ExopackConfig;
|
import ru.dbotthepony.mc.otm.config.ExopackConfig;
|
||||||
import ru.dbotthepony.mc.otm.config.ItemsConfig;
|
import ru.dbotthepony.mc.otm.config.ItemsConfig;
|
||||||
@ -142,6 +143,7 @@ public final class OverdriveThatMatters {
|
|||||||
|
|
||||||
ClientConfig.INSTANCE.register();
|
ClientConfig.INSTANCE.register();
|
||||||
ServerConfig.INSTANCE.register();
|
ServerConfig.INSTANCE.register();
|
||||||
|
CablesConfig.INSTANCE.register();
|
||||||
ServerCompatConfig.INSTANCE.register();
|
ServerCompatConfig.INSTANCE.register();
|
||||||
AndroidConfig.INSTANCE.register();
|
AndroidConfig.INSTANCE.register();
|
||||||
ExopackConfig.INSTANCE.register();
|
ExopackConfig.INSTANCE.register();
|
||||||
|
@ -40,6 +40,9 @@ private val serverCounter = AtomicInteger()
|
|||||||
private var _server: MinecraftServer? = null
|
private var _server: MinecraftServer? = null
|
||||||
val isClient: Boolean by lazy { FMLLoader.getDist() == Dist.CLIENT }
|
val isClient: Boolean by lazy { FMLLoader.getDist() == Dist.CLIENT }
|
||||||
|
|
||||||
|
val UNIVERSE_TICKS get() = postServerTick.ticks
|
||||||
|
val Level.ticksPassed get() = postWorldTick.computeIfAbsent(this) { TickList() }.ticks
|
||||||
|
|
||||||
fun <V> lazyPerServer(fn: (MinecraftServer) -> V): Lazy<V> {
|
fun <V> lazyPerServer(fn: (MinecraftServer) -> V): Lazy<V> {
|
||||||
return AtomicallyInvalidatedLazy(serverCounter) {
|
return AtomicallyInvalidatedLazy(serverCounter) {
|
||||||
if (!SERVER_IS_LIVE)
|
if (!SERVER_IS_LIVE)
|
||||||
|
@ -129,8 +129,8 @@ class StorageCableBlock : CableBlock(Properties.of().mapColor(MapColor.METAL).re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EnergyCableBlock : CableBlock(Properties.of().mapColor(MapColor.METAL).requiresCorrectToolForDrops().sound(SoundType.METAL).strength(1.0f, 6.0f)), EntityBlock {
|
class EnergyCableBlock(val factory: (blockPos: BlockPos, blockState: BlockState) -> BlockEntity) : CableBlock(Properties.of().mapColor(MapColor.METAL).requiresCorrectToolForDrops().sound(SoundType.METAL).strength(1.0f, 6.0f)), EntityBlock {
|
||||||
private val shapes = generateShapes(0.125)
|
private val shapes = generateShapes(0.185)
|
||||||
|
|
||||||
@Suppress("OVERRIDE_DEPRECATION")
|
@Suppress("OVERRIDE_DEPRECATION")
|
||||||
override fun getShape(blockState: BlockState, accessor: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
override fun getShape(blockState: BlockState, accessor: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||||
@ -138,6 +138,6 @@ class EnergyCableBlock : CableBlock(Properties.of().mapColor(MapColor.METAL).req
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
|
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
|
||||||
return EnergyCableBlockEntity(blockPos, blockState)
|
return factory(blockPos, blockState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ import java.util.function.Consumer
|
|||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
@ -109,6 +110,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
|||||||
protected val tickList = TickList()
|
protected val tickList = TickList()
|
||||||
protected val blockStateChangesCounter = IntCounter()
|
protected val blockStateChangesCounter = IntCounter()
|
||||||
protected val dirtyListeners = ISubscriptable.Impl<Unit>()
|
protected val dirtyListeners = ISubscriptable.Impl<Unit>()
|
||||||
|
private val waitForServerLevel = ArrayList<() -> Unit>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared savetables, written both to level storage and to item tag
|
* Shared savetables, written both to level storage and to item tag
|
||||||
@ -166,6 +168,14 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun waitForServerLevel(lambda: () -> Unit) {
|
||||||
|
if (level is ServerLevel) {
|
||||||
|
lambda.invoke()
|
||||||
|
} else if (level == null) {
|
||||||
|
waitForServerLevel.add(lambda)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface SideListener<T> : Supplier<LazyOptional<T>>, ISubscriptable<LazyOptional<T>>
|
interface SideListener<T> : Supplier<LazyOptional<T>>, ISubscriptable<LazyOptional<T>>
|
||||||
|
|
||||||
inner class Side(val side: RelativeSide) {
|
inner class Side(val side: RelativeSide) {
|
||||||
@ -191,7 +201,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
|||||||
|
|
||||||
override fun addListener(listener: Consumer<LazyOptional<T>>): ISubscriptable.L {
|
override fun addListener(listener: Consumer<LazyOptional<T>>): ISubscriptable.L {
|
||||||
val l = listeners.addListener(listener)
|
val l = listeners.addListener(listener)
|
||||||
listener.accept(value)
|
if (level is ServerLevel) listener.accept(value)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,6 +531,10 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
waitForServerLevel.forEach { it.invoke() }
|
||||||
|
} else {
|
||||||
|
waitForServerLevel.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
tickList.once {
|
waitForServerLevel {
|
||||||
redstoneControl.addListener {
|
redstoneControl.addListener {
|
||||||
updateTickerState()
|
updateTickerState()
|
||||||
}
|
}
|
||||||
@ -388,7 +388,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
|
|||||||
updateTickerState()
|
updateTickerState()
|
||||||
}
|
}
|
||||||
|
|
||||||
tickList.once {
|
waitForServerLevel {
|
||||||
redstoneControl.addListener {
|
redstoneControl.addListener {
|
||||||
updateTickerState()
|
updateTickerState()
|
||||||
}
|
}
|
||||||
@ -670,7 +670,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
|
|||||||
savetables.bool(::automatePush, "itemhandler_${side}_automatePush")
|
savetables.bool(::automatePush, "itemhandler_${side}_automatePush")
|
||||||
savetables.enum(::mode, "itemhandler_${side}_mode", ItemHandlerMode::valueOf)
|
savetables.enum(::mode, "itemhandler_${side}_mode", ItemHandlerMode::valueOf)
|
||||||
|
|
||||||
tickList.once {
|
waitForServerLevel {
|
||||||
redstoneControl.addListener {
|
redstoneControl.addListener {
|
||||||
updateTickerState()
|
updateTickerState()
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ package ru.dbotthepony.mc.otm.block.entity.cable
|
|||||||
|
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
|
import net.minecraft.server.level.ServerLevel
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
import net.minecraft.world.level.block.Block
|
import net.minecraft.world.level.block.Block
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||||
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
||||||
@ -12,13 +14,12 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
|||||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
import ru.dbotthepony.mc.otm.config.CablesConfig
|
||||||
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
||||||
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.graph.GraphNode
|
import ru.dbotthepony.mc.otm.graph.GraphNode
|
||||||
import ru.dbotthepony.mc.otm.onceServer
|
import ru.dbotthepony.mc.otm.onceServer
|
||||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
|
|
||||||
@ -27,7 +28,7 @@ import java.util.EnumMap
|
|||||||
|
|
||||||
// this allows simpler implementation and faster code, while also reducing possibility of duplication exploits
|
// this allows simpler implementation and faster code, while also reducing possibility of duplication exploits
|
||||||
|
|
||||||
class EnergyCableBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.ENERGY_CABLE, blockPos, blockState) {
|
abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(type, blockPos, blockState) {
|
||||||
inner class CableSide(val side: RelativeSide) : IMatteryEnergyStorage {
|
inner class CableSide(val side: RelativeSide) : IMatteryEnergyStorage {
|
||||||
var isEnabled = true
|
var isEnabled = true
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -47,19 +48,17 @@ class EnergyCableBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
val neighbour = sides[side]!!.trackEnergy()
|
val neighbour = sides[side]!!.trackEnergy()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
waitForServerLevel {
|
||||||
neighbour.addListener {
|
neighbour.addListener {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
if (it.isPresent) {
|
if (it.isPresent) {
|
||||||
if (it.resolve().get() !is CableSide) {
|
if (it.resolve().get() !is CableSide) {
|
||||||
node.graph.livelyNodes.add(node)
|
node.graph.livelyNodes.add(node)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onceServer {
|
onceServer {
|
||||||
updateBlockState(blockRotation.side2Dir(side), true)
|
updateBlockState(blockRotation.side2Dir(side), it.isPresent || node.neighboursView[GraphNode.link(blockRotation.side2Dir(side))] != null)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onceServer {
|
|
||||||
updateBlockState(blockRotation.side2Dir(side), false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +70,7 @@ class EnergyCableBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||||
return node.graph.receiveEnergy(howMuch, simulate)
|
return node.graph.receiveEnergy(howMuch, simulate, node, side)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var batteryLevel: Decimal
|
override var batteryLevel: Decimal
|
||||||
@ -103,6 +102,11 @@ class EnergyCableBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
updateBlockState(link.direction, false)
|
updateBlockState(link.direction, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val blockEntity get() = this@EnergyCableBlockEntity
|
||||||
|
val canTraverse get() = energyThroughput > Decimal.ZERO
|
||||||
|
val energyThroughput get() = this@EnergyCableBlockEntity.energyThroughput
|
||||||
|
val position: BlockPos get() = this@EnergyCableBlockEntity.blockPos
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBlockState(side: Direction, status: Boolean) {
|
private fun updateBlockState(side: Direction, status: Boolean) {
|
||||||
@ -112,7 +116,10 @@ class EnergyCableBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS)
|
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val blockRotation: BlockRotation
|
// whenever this changes, graph#invalidatePathCache() MUST be called
|
||||||
|
abstract val energyThroughput: Decimal
|
||||||
|
|
||||||
|
final override val blockRotation: BlockRotation
|
||||||
get() = BlockRotation.NORTH
|
get() = BlockRotation.NORTH
|
||||||
|
|
||||||
private val energySidesInternal = EnumMap<RelativeSide, CableSide>(RelativeSide::class.java)
|
private val energySidesInternal = EnumMap<RelativeSide, CableSide>(RelativeSide::class.java)
|
||||||
@ -134,3 +141,8 @@ class EnergyCableBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
|
|||||||
exposeGlobally(MatteryCapability.ENERGY_CABLE_NODE, node)
|
exposeGlobally(MatteryCapability.ENERGY_CABLE_NODE, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SimpleEnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState, val config: CablesConfig.E) : EnergyCableBlockEntity(type, blockPos, blockState) {
|
||||||
|
override val energyThroughput: Decimal
|
||||||
|
get() = config.throughput
|
||||||
|
}
|
||||||
|
@ -1,23 +1,92 @@
|
|||||||
package ru.dbotthepony.mc.otm.block.entity.cable
|
package ru.dbotthepony.mc.otm.block.entity.cable
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectAVLTreeSet
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||||
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.graph.GraphNodeList
|
import ru.dbotthepony.mc.otm.graph.GraphNodeList
|
||||||
|
import kotlin.math.ln
|
||||||
|
|
||||||
class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableGraph>() {
|
class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableGraph>() {
|
||||||
val livelyNodes = ObjectOpenHashSet<EnergyCableBlockEntity.Node>()
|
val livelyNodes = ObjectOpenHashSet<EnergyCableBlockEntity.Node>()
|
||||||
|
|
||||||
|
private val pathCache = Object2ObjectOpenHashMap<Pair<EnergyCableBlockEntity.Node, EnergyCableBlockEntity.Node>, Decimal?>()
|
||||||
|
|
||||||
|
private class SearchNode(val node: EnergyCableBlockEntity.Node, target: EnergyCableBlockEntity.Node, var parent: SearchNode? = null) : Comparable<SearchNode> {
|
||||||
|
var heuristics: Double = node.position.distSqr(target.position) * 0.0001 - ln(node.energyThroughput.coerceAtMost(Decimal.LONG_MAX_VALUE).toDouble())
|
||||||
|
|
||||||
|
override fun compareTo(other: SearchNode): Int {
|
||||||
|
return heuristics.compareTo(other.heuristics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invalidatePathCache() {
|
||||||
|
pathCache.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPath(a: EnergyCableBlockEntity.Node, b: EnergyCableBlockEntity.Node): Decimal? {
|
||||||
|
if (!a.canTraverse || !b.canTraverse)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val key = a to b
|
||||||
|
|
||||||
|
if (key in pathCache)
|
||||||
|
return pathCache[key]
|
||||||
|
|
||||||
|
// no free paths available, try to find extra one
|
||||||
|
// while this use A* algorithm, this is done purely for biasing search towards end point (to speed up search),
|
||||||
|
// on small cable networks simple flooding will do just fine, if we consider overloaded cables as closed flood gates
|
||||||
|
val openNodes = ArrayList<SearchNode>()
|
||||||
|
val seenNodes = ObjectOpenHashSet<EnergyCableBlockEntity.Node>()
|
||||||
|
|
||||||
|
openNodes.add(SearchNode(a, b))
|
||||||
|
|
||||||
|
while (openNodes.isNotEmpty()) {
|
||||||
|
val first = openNodes.min()
|
||||||
|
openNodes.remove(first)
|
||||||
|
|
||||||
|
if (first.node === b) {
|
||||||
|
// solution found
|
||||||
|
val solution = ArrayList<EnergyCableBlockEntity.Node>()
|
||||||
|
|
||||||
|
var last = first.parent
|
||||||
|
solution.add(first.node)
|
||||||
|
|
||||||
|
while (last != null) {
|
||||||
|
solution.add(last.node)
|
||||||
|
last = last.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
val calc = solution.minOf { it.energyThroughput }
|
||||||
|
pathCache[key] = calc
|
||||||
|
return calc
|
||||||
|
} else {
|
||||||
|
for (neighbour in first.node.neighboursView.values) {
|
||||||
|
if (!seenNodes.add(neighbour) || !neighbour.canTraverse) continue
|
||||||
|
openNodes.add(SearchNode(neighbour, b, first))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// solution does not exist
|
||||||
|
pathCache[key] = null
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
||||||
livelyNodes.remove(node)
|
livelyNodes.remove(node)
|
||||||
|
invalidatePathCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
|
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
|
||||||
livelyNodes.add(node)
|
livelyNodes.add(node)
|
||||||
|
invalidatePathCache()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
fun receiveEnergy(howMuch: Decimal, simulate: Boolean, fromNode: EnergyCableBlockEntity.Node, fromSide: RelativeSide): Decimal {
|
||||||
val itr = livelyNodes.iterator()
|
val itr = livelyNodes.iterator()
|
||||||
var received = Decimal.ZERO
|
var received = Decimal.ZERO
|
||||||
var residue = howMuch
|
var residue = howMuch
|
||||||
@ -27,19 +96,24 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
|
|||||||
|
|
||||||
for (side in node.sides.values) {
|
for (side in node.sides.values) {
|
||||||
if (side.isEnabled) {
|
if (side.isEnabled) {
|
||||||
|
if (fromNode === node && side.side === fromSide)
|
||||||
|
continue
|
||||||
|
|
||||||
side.neighbour.get().ifPresentK {
|
side.neighbour.get().ifPresentK {
|
||||||
if (it !is EnergyCableBlockEntity.CableSide) {
|
if (it !is EnergyCableBlockEntity.CableSide) {
|
||||||
|
val limit = getPath(fromNode, node)
|
||||||
hit = true
|
hit = true
|
||||||
|
|
||||||
val thisReceived = it.receiveEnergy(residue, simulate)
|
if (limit != null) {
|
||||||
|
val thisReceived = it.receiveEnergy(residue.coerceAtMost(limit), simulate)
|
||||||
received += thisReceived
|
received += thisReceived
|
||||||
residue -= thisReceived
|
residue -= thisReceived
|
||||||
|
|
||||||
if (!residue.isPositive) return received
|
if (!residue.isPositive) return received
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!hit) {
|
if (!hit) {
|
||||||
itr.remove()
|
itr.remove()
|
||||||
|
28
src/main/kotlin/ru/dbotthepony/mc/otm/config/CablesConfig.kt
Normal file
28
src/main/kotlin/ru/dbotthepony/mc/otm/config/CablesConfig.kt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.config
|
||||||
|
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.defineDecimal
|
||||||
|
|
||||||
|
object CablesConfig : AbstractConfig("cables") {
|
||||||
|
enum class E(throughput: Decimal) {
|
||||||
|
CRUDE(Decimal(160)),
|
||||||
|
REGULAR(Decimal(1024)),
|
||||||
|
ADVANCED(Decimal(8192)),
|
||||||
|
SUPERCONDUCTOR(Decimal.POSITIVE_INFINITY);
|
||||||
|
|
||||||
|
init {
|
||||||
|
builder.push(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var throughput by builder
|
||||||
|
.defineDecimal("THROUGHPUT", throughput, Decimal.ZERO)
|
||||||
|
|
||||||
|
init {
|
||||||
|
builder.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
E.SUPERCONDUCTOR
|
||||||
|
}
|
||||||
|
}
|
@ -262,14 +262,14 @@ sealed class Decimal : Number(), Comparable<Decimal> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun compareTo(other: Decimal): Int {
|
override fun compareTo(other: Decimal): Int {
|
||||||
return if (other is Regular)
|
return if (other === Zero)
|
||||||
|
signum()
|
||||||
|
else if (other is Regular)
|
||||||
mag.compareTo(other.mag)
|
mag.compareTo(other.mag)
|
||||||
else if (other === PositiveInfinity)
|
else if (other === PositiveInfinity)
|
||||||
-1
|
-1
|
||||||
else if (other === NegativeInfinity)
|
else if (other === NegativeInfinity)
|
||||||
1
|
1
|
||||||
else if (other === Zero)
|
|
||||||
signum()
|
|
||||||
else
|
else
|
||||||
throw RuntimeException("unreachable code")
|
throw RuntimeException("unreachable code")
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ import ru.dbotthepony.mc.otm.core.math.plus
|
|||||||
import ru.dbotthepony.mc.otm.core.orNull
|
import ru.dbotthepony.mc.otm.core.orNull
|
||||||
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
|
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
|
||||||
import ru.dbotthepony.mc.otm.core.util.ITickable
|
import ru.dbotthepony.mc.otm.core.util.ITickable
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
open class GraphNode<N : GraphNode<N, G>, G : GraphNodeList<N, G>>(val graphFactory: () -> G) {
|
open class GraphNode<N : GraphNode<N, G>, G : GraphNodeList<N, G>>(val graphFactory: () -> G) {
|
||||||
interface Link {
|
interface Link {
|
||||||
@ -30,6 +32,7 @@ open class GraphNode<N : GraphNode<N, G>, G : GraphNodeList<N, G>>(val graphFact
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val neighbours = Object2ObjectOpenHashMap<Link, N>()
|
private val neighbours = Object2ObjectOpenHashMap<Link, N>()
|
||||||
|
val neighboursView: Map<Link, N> = Collections.unmodifiableMap(neighbours)
|
||||||
|
|
||||||
var graph: G = graphFactory.invoke()
|
var graph: G = graphFactory.invoke()
|
||||||
internal set
|
internal set
|
||||||
|
@ -15,7 +15,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.*
|
|||||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntityExplosionDebugger
|
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntityExplosionDebugger
|
||||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntitySphereDebugger
|
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntitySphereDebugger
|
||||||
import ru.dbotthepony.mc.otm.block.entity.cable.EnergyCableBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.cable.SimpleEnergyCableBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
|
||||||
@ -30,6 +30,9 @@ import ru.dbotthepony.mc.otm.block.entity.tech.EnergyServoBlockEntity
|
|||||||
import ru.dbotthepony.mc.otm.block.entity.tech.GravitationStabilizerBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.tech.GravitationStabilizerBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.client.render.blockentity.*
|
import ru.dbotthepony.mc.otm.client.render.blockentity.*
|
||||||
|
import ru.dbotthepony.mc.otm.config.CablesConfig
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
|
||||||
|
import ru.dbotthepony.mc.otm.core.getValue
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
|
|
||||||
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // Type<*> is unused in BlockEntityType.Builder
|
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // Type<*> is unused in BlockEntityType.Builder
|
||||||
@ -74,7 +77,12 @@ object MBlockEntities {
|
|||||||
val DEV_CHEST by register(MNames.DEV_CHEST, ::DevChestBlockEntity, MBlocks::DEV_CHEST)
|
val DEV_CHEST by register(MNames.DEV_CHEST, ::DevChestBlockEntity, MBlocks::DEV_CHEST)
|
||||||
val PAINTER by register(MNames.PAINTER, ::PainterBlockEntity, MBlocks::PAINTER)
|
val PAINTER by register(MNames.PAINTER, ::PainterBlockEntity, MBlocks::PAINTER)
|
||||||
val MATTER_ENTANGLER by register(MNames.MATTER_ENTANGLER, ::MatterEntanglerBlockEntity, MBlocks::MATTER_ENTANGLER)
|
val MATTER_ENTANGLER by register(MNames.MATTER_ENTANGLER, ::MatterEntanglerBlockEntity, MBlocks::MATTER_ENTANGLER)
|
||||||
val ENERGY_CABLE by register(MNames.ENERGY_CABLE, ::EnergyCableBlockEntity, MBlocks::ENERGY_CABLE)
|
|
||||||
|
val ENERGY_CABLES: Map<CablesConfig.E, BlockEntityType<*>> = SupplierMap(CablesConfig.E.entries.map { conf ->
|
||||||
|
var selfFeed: Supplier<BlockEntityType<*>> = Supplier { TODO() }
|
||||||
|
selfFeed = register("${conf.name.lowercase()}_energy_cable", { a, b -> SimpleEnergyCableBlockEntity(selfFeed.get(), a, b, conf) }) as Supplier<BlockEntityType<*>>
|
||||||
|
conf to selfFeed::get
|
||||||
|
})
|
||||||
|
|
||||||
val POWERED_FURNACE: BlockEntityType<PoweredFurnaceBlockEntity> by registry.register(MNames.POWERED_FURNACE) { BlockEntityType.Builder.of({ a, b -> MBlocks.POWERED_FURNACE.newBlockEntity(a, b) }, MBlocks.POWERED_FURNACE).build(null) }
|
val POWERED_FURNACE: BlockEntityType<PoweredFurnaceBlockEntity> by registry.register(MNames.POWERED_FURNACE) { BlockEntityType.Builder.of({ a, b -> MBlocks.POWERED_FURNACE.newBlockEntity(a, b) }, MBlocks.POWERED_FURNACE).build(null) }
|
||||||
val POWERED_BLAST_FURNACE: BlockEntityType<PoweredFurnaceBlockEntity> by registry.register(MNames.POWERED_BLAST_FURNACE) { BlockEntityType.Builder.of({ a, b -> MBlocks.POWERED_BLAST_FURNACE.newBlockEntity(a, b) }, MBlocks.POWERED_BLAST_FURNACE).build(null) }
|
val POWERED_BLAST_FURNACE: BlockEntityType<PoweredFurnaceBlockEntity> by registry.register(MNames.POWERED_BLAST_FURNACE) { BlockEntityType.Builder.of({ a, b -> MBlocks.POWERED_BLAST_FURNACE.newBlockEntity(a, b) }, MBlocks.POWERED_BLAST_FURNACE).build(null) }
|
||||||
|
@ -77,9 +77,11 @@ import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
|
|||||||
import ru.dbotthepony.mc.otm.block.tech.PhantomAttractorBlock
|
import ru.dbotthepony.mc.otm.block.tech.PhantomAttractorBlock
|
||||||
import ru.dbotthepony.mc.otm.block.tech.PlatePressBlock
|
import ru.dbotthepony.mc.otm.block.tech.PlatePressBlock
|
||||||
import ru.dbotthepony.mc.otm.block.tech.PoweredFurnaceBlock
|
import ru.dbotthepony.mc.otm.block.tech.PoweredFurnaceBlock
|
||||||
|
import ru.dbotthepony.mc.otm.config.CablesConfig
|
||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.collect.SupplierList
|
import ru.dbotthepony.mc.otm.core.collect.SupplierList
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
|
||||||
import ru.dbotthepony.mc.otm.shapes.BlockShapes
|
import ru.dbotthepony.mc.otm.shapes.BlockShapes
|
||||||
|
|
||||||
object MBlocks {
|
object MBlocks {
|
||||||
@ -115,7 +117,10 @@ object MBlocks {
|
|||||||
val MATTER_RECONSTRUCTOR: MatterReconstructorBlock by registry.register(MNames.MATTER_RECONSTRUCTOR) { MatterReconstructorBlock() }
|
val MATTER_RECONSTRUCTOR: MatterReconstructorBlock by registry.register(MNames.MATTER_RECONSTRUCTOR) { MatterReconstructorBlock() }
|
||||||
val PAINTER: PainterBlock by registry.register(MNames.PAINTER) { PainterBlock() }
|
val PAINTER: PainterBlock by registry.register(MNames.PAINTER) { PainterBlock() }
|
||||||
val MATTER_ENTANGLER: MatterEntanglerBlock by registry.register(MNames.MATTER_ENTANGLER) { MatterEntanglerBlock() }
|
val MATTER_ENTANGLER: MatterEntanglerBlock by registry.register(MNames.MATTER_ENTANGLER) { MatterEntanglerBlock() }
|
||||||
val ENERGY_CABLE: EnergyCableBlock by registry.register(MNames.ENERGY_CABLE) { EnergyCableBlock() }
|
|
||||||
|
val ENERGY_CABLES: Map<CablesConfig.E, EnergyCableBlock> = SupplierMap(CablesConfig.E.entries.map { conf ->
|
||||||
|
conf to registry.register("${conf.name.lowercase()}_energy_cable") { EnergyCableBlock { a, b -> MBlockEntities.ENERGY_CABLES[conf]!!.create(a, b)!! } }::get
|
||||||
|
})
|
||||||
|
|
||||||
val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS) { StorageBusBlock() }
|
val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS) { StorageBusBlock() }
|
||||||
val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER) { StorageImporterBlock() }
|
val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER) { StorageImporterBlock() }
|
||||||
|
@ -129,7 +129,7 @@ private fun CreativeModeTab.Output.fluids(value: Item) {
|
|||||||
|
|
||||||
private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
|
private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
|
||||||
with(consumer) {
|
with(consumer) {
|
||||||
accept(MItems.ENERGY_CABLE)
|
accept(MItems.ENERGY_CABLES.values)
|
||||||
accept(MItems.MACHINES)
|
accept(MItems.MACHINES)
|
||||||
accept(MItems.MachineUpgrades.Basic.LIST)
|
accept(MItems.MachineUpgrades.Basic.LIST)
|
||||||
accept(MItems.MachineUpgrades.Normal.LIST)
|
accept(MItems.MachineUpgrades.Normal.LIST)
|
||||||
|
@ -17,9 +17,11 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
|||||||
import ru.dbotthepony.mc.otm.capability.ITieredUpgradeSet
|
import ru.dbotthepony.mc.otm.capability.ITieredUpgradeSet
|
||||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||||
import ru.dbotthepony.mc.otm.capability.UpgradeType
|
import ru.dbotthepony.mc.otm.capability.UpgradeType
|
||||||
|
import ru.dbotthepony.mc.otm.config.CablesConfig
|
||||||
import ru.dbotthepony.mc.otm.config.ItemsConfig
|
import ru.dbotthepony.mc.otm.config.ItemsConfig
|
||||||
import ru.dbotthepony.mc.otm.core.collect.SupplierList
|
import ru.dbotthepony.mc.otm.core.collect.SupplierList
|
||||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.SupplierMap
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.item.*
|
import ru.dbotthepony.mc.otm.item.*
|
||||||
import ru.dbotthepony.mc.otm.item.exopack.ExopackProbeItem
|
import ru.dbotthepony.mc.otm.item.exopack.ExopackProbeItem
|
||||||
@ -46,7 +48,9 @@ object MItems {
|
|||||||
registry.register(bus)
|
registry.register(bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
val ENERGY_CABLE: BlockItem by registry.register(MNames.ENERGY_CABLE) { BlockItem(MBlocks.ENERGY_CABLE, DEFAULT_PROPERTIES) }
|
val ENERGY_CABLES: Map<CablesConfig.E, BlockItem> = SupplierMap(CablesConfig.E.entries.map { conf ->
|
||||||
|
conf to registry.register("${conf.name.lowercase()}_energy_cable") { BlockItem(MBlocks.ENERGY_CABLES[conf]!!, DEFAULT_PROPERTIES) }::get
|
||||||
|
})
|
||||||
|
|
||||||
val ANDROID_STATION: BlockItem by registry.register(MNames.ANDROID_STATION) { BlockItem(MBlocks.ANDROID_STATION, DEFAULT_PROPERTIES) }
|
val ANDROID_STATION: BlockItem by registry.register(MNames.ANDROID_STATION) { BlockItem(MBlocks.ANDROID_STATION, DEFAULT_PROPERTIES) }
|
||||||
val ANDROID_CHARGER: BlockItem by registry.register(MNames.ANDROID_CHARGER) { BlockItem(MBlocks.ANDROID_CHARGER, DEFAULT_PROPERTIES) }
|
val ANDROID_CHARGER: BlockItem by registry.register(MNames.ANDROID_CHARGER) { BlockItem(MBlocks.ANDROID_CHARGER, DEFAULT_PROPERTIES) }
|
||||||
|
@ -17,7 +17,6 @@ object MNames {
|
|||||||
const val DEV_CHEST = "dev_chest"
|
const val DEV_CHEST = "dev_chest"
|
||||||
const val PAINTER = "painter"
|
const val PAINTER = "painter"
|
||||||
const val MATTER_ENTANGLER = "matter_entangler"
|
const val MATTER_ENTANGLER = "matter_entangler"
|
||||||
const val ENERGY_CABLE = "energy_cable"
|
|
||||||
|
|
||||||
// blocks
|
// blocks
|
||||||
const val ANDROID_STATION = "android_station"
|
const val ANDROID_STATION = "android_station"
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"multipart": [
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_core"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_south": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_west": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_north": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 180
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_east": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_up": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_down": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"multipart": [
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_core"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_south": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_west": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_north": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 180
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_east": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_up": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_down": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"multipart": [
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_core"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_south": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_west": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_north": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 180
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_east": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_up": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_down": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"multipart": [
|
||||||
|
{
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_core"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_south": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_west": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_north": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 180
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_east": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_up": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 90
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"when": {
|
||||||
|
"connect_down": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"apply": {
|
||||||
|
"model": "overdrive_that_matters:block/storage_cable_connection",
|
||||||
|
"x": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user