Energy cable tiers, fix some Client -> Server logic leaks in singleplayer

This commit is contained in:
DBotThePony 2023-12-30 20:26:31 +07:00
parent 023081eaaa
commit 1c0cdb8b5b
Signed by: DBot
GPG Key ID: DCC23B5715498507
21 changed files with 487 additions and 37 deletions

View File

@ -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()) }

View File

@ -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,

View File

@ -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();

View File

@ -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)

View File

@ -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)
} }
} }

View File

@ -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()
} }
} }

View File

@ -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()
} }

View File

@ -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
}

View File

@ -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()

View 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
}
}

View File

@ -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")
} }

View File

@ -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

View File

@ -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) }

View File

@ -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() }

View File

@ -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)

View File

@ -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) }

View File

@ -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"

View File

@ -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
}
}
]
}

View File

@ -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
}
}
]
}

View File

@ -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
}
}
]
}

View File

@ -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
}
}
]
}