Energy cables test
This commit is contained in:
parent
6de2f14fcd
commit
79aeca5720
@ -5,6 +5,7 @@ import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.CapabilityToken;
|
||||
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ru.dbotthepony.mc.otm.block.entity.cable.EnergyCableBlockEntity;
|
||||
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage;
|
||||
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage;
|
||||
@ -50,6 +51,10 @@ public class MatteryCapability {
|
||||
@NotNull
|
||||
public static final Capability<StorageNode> STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
public static final Capability<EnergyCableBlockEntity.Node> ENERGY_CABLE_NODE = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
|
||||
@Nonnull
|
||||
@NotNull
|
||||
public static final Capability<ICuriosItemHandler> CURIOS_INVENTORY = CapabilityManager.get(new CapabilityToken<>() {});
|
||||
|
@ -21,10 +21,11 @@ import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatterCableBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.StorageCableBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.cable.EnergyCableBlockEntity
|
||||
import java.util.Collections
|
||||
import java.util.EnumMap
|
||||
|
||||
abstract class CableBlock(properties: Properties) : Block(properties) {
|
||||
abstract class CableBlock(properties: Properties) : MatteryBlock(properties) {
|
||||
init {
|
||||
registerDefaultState(defaultBlockState()
|
||||
.setValue(CONNECTION_SOUTH, false)
|
||||
@ -127,3 +128,16 @@ class StorageCableBlock : CableBlock(Properties.of().mapColor(MapColor.METAL).re
|
||||
return StorageCableBlockEntity(blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
class EnergyCableBlock : CableBlock(Properties.of().mapColor(MapColor.METAL).requiresCorrectToolForDrops().sound(SoundType.METAL).strength(1.0f, 6.0f)), EntityBlock {
|
||||
private val shapes = generateShapes(0.125)
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
override fun getShape(blockState: BlockState, accessor: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
return shapes[blockState] ?: Shapes.block()
|
||||
}
|
||||
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
|
||||
return EnergyCableBlockEntity(blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
@ -70,9 +70,7 @@ fun interface INeighbourChangeListener {
|
||||
)
|
||||
}
|
||||
|
||||
abstract class MatteryBlock @JvmOverloads constructor(
|
||||
properties: Properties = DEFAULT_PROPERTIES
|
||||
) : Block(properties), INeighbourChangeListener {
|
||||
abstract class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(properties), INeighbourChangeListener {
|
||||
override fun setPlacedBy(
|
||||
level: Level,
|
||||
blockPos: BlockPos,
|
||||
|
@ -0,0 +1,133 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.cable
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
||||
import ru.dbotthepony.mc.otm.block.CableBlock
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
import ru.dbotthepony.mc.otm.graph.GraphNode
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import java.util.Collections
|
||||
import java.util.EnumMap
|
||||
|
||||
// after some thinking, team decided to settle with IC2's side (techreborn, gregtech, integrated dynamics*, pipez*, p2p tunnels, ...) of implementation,
|
||||
// where cables have no residue capacitance, and never pull/push energy by themselves
|
||||
|
||||
// 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) {
|
||||
inner class CableSide(val side: RelativeSide) : IMatteryEnergyStorage {
|
||||
var isEnabled = true
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
if (value) {
|
||||
node.graph.livelyNodes.add(node)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
check(side !in energySidesInternal)
|
||||
energySidesInternal[side] = this
|
||||
sides[side]!!.Cap(ForgeCapabilities.ENERGY, this)
|
||||
}
|
||||
|
||||
val neighbour = sides[side]!!.trackEnergy()
|
||||
|
||||
init {
|
||||
neighbour.addListener {
|
||||
if (isEnabled) {
|
||||
if (it.isPresent) {
|
||||
if (it.resolve().get() !is CableSide) {
|
||||
node.graph.livelyNodes.add(node)
|
||||
}
|
||||
|
||||
ru.dbotthepony.mc.otm.onceServer {
|
||||
val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[blockRotation.side2Dir(side)]!!, true)
|
||||
|
||||
if (newState !== blockState)
|
||||
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS)
|
||||
}
|
||||
} else {
|
||||
ru.dbotthepony.mc.otm.onceServer {
|
||||
val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[blockRotation.side2Dir(side)]!!, false)
|
||||
|
||||
if (newState !== blockState)
|
||||
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return Decimal.ZERO
|
||||
}
|
||||
|
||||
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return node.graph.receiveEnergy(howMuch, simulate)
|
||||
}
|
||||
|
||||
override var batteryLevel: Decimal
|
||||
get() = Decimal.ZERO
|
||||
set(value) {}
|
||||
|
||||
override val maxBatteryLevel: Decimal get() = Decimal.ZERO
|
||||
override var energyFlow: FlowDirection = FlowDirection.BI_DIRECTIONAL
|
||||
private set
|
||||
}
|
||||
|
||||
inner class Node : GraphNode<Node, EnergyCableGraph>(::EnergyCableGraph) {
|
||||
val sides get() = energySides
|
||||
|
||||
override fun onNeighbour(link: Link) {
|
||||
if (link is DirectionLink) {
|
||||
val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[link.direction]!!, true)
|
||||
|
||||
if (newState !== blockState && SERVER_IS_LIVE)
|
||||
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUnNeighbour(link: Link) {
|
||||
if (link is DirectionLink) {
|
||||
val newState = blockState.setValue(CableBlock.MAPPING_CONNECTION_PROP[link.direction]!!, false)
|
||||
|
||||
if (newState !== blockState && SERVER_IS_LIVE)
|
||||
level?.setBlock(blockPos, newState, Block.UPDATE_CLIENTS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val blockRotation: BlockRotation
|
||||
get() = BlockRotation.NORTH
|
||||
|
||||
private val energySidesInternal = EnumMap<RelativeSide, CableSide>(RelativeSide::class.java)
|
||||
val energySides: Map<RelativeSide, CableSide> = Collections.unmodifiableMap(energySidesInternal)
|
||||
val node = Node()
|
||||
|
||||
override fun setLevel(level: Level) {
|
||||
super.setLevel(level)
|
||||
node.discover(this, MatteryCapability.ENERGY_CABLE_NODE)
|
||||
}
|
||||
|
||||
override fun setRemoved() {
|
||||
super.setRemoved()
|
||||
node.isValid = false
|
||||
}
|
||||
|
||||
init {
|
||||
sides.keys.forEach { CableSide(it) }
|
||||
exposeGlobally(MatteryCapability.ENERGY_CABLE_NODE, node)
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.cable
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.graph.GraphNodeList
|
||||
|
||||
class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableGraph>() {
|
||||
val livelyNodes = ObjectOpenHashSet<EnergyCableBlockEntity.Node>()
|
||||
|
||||
override fun onNodeRemoved(node: EnergyCableBlockEntity.Node) {
|
||||
livelyNodes.remove(node)
|
||||
}
|
||||
|
||||
override fun onNodeAdded(node: EnergyCableBlockEntity.Node) {
|
||||
livelyNodes.add(node)
|
||||
}
|
||||
|
||||
fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
val itr = livelyNodes.iterator()
|
||||
var received = Decimal.ZERO
|
||||
var residue = howMuch
|
||||
|
||||
for (node in itr) {
|
||||
var hit = false
|
||||
|
||||
for (side in node.sides.values) {
|
||||
if (side.isEnabled) {
|
||||
side.neighbour.get().ifPresentK {
|
||||
if (it !is EnergyCableBlockEntity.CableSide) {
|
||||
hit = true
|
||||
|
||||
val thisReceived = it.receiveEnergy(residue, simulate)
|
||||
received += thisReceived
|
||||
residue -= thisReceived
|
||||
|
||||
if (!residue.isPositive) return received
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hit) {
|
||||
itr.remove()
|
||||
}
|
||||
}
|
||||
|
||||
return received
|
||||
}
|
||||
}
|
@ -11,6 +11,8 @@ import net.minecraftforge.common.capabilities.Capability
|
||||
import ru.dbotthepony.mc.otm.addTicker
|
||||
import ru.dbotthepony.mc.otm.core.math.plus
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
|
||||
import ru.dbotthepony.mc.otm.core.util.ITickable
|
||||
|
||||
open class GraphNode<N : GraphNode<N, G>, G : GraphNodeList<N, G>>(val graphFactory: () -> G) {
|
||||
interface Link {
|
||||
@ -38,6 +40,11 @@ open class GraphNode<N : GraphNode<N, G>, G : GraphNodeList<N, G>>(val graphFact
|
||||
|
||||
private var seen: Int = 0
|
||||
|
||||
fun beginTicking() {
|
||||
require(this is IConditionalTickable || this is ITickable) { "Node must implement either ITickable or IConditionalTickable to tick" }
|
||||
graph.beginTicking(this as N)
|
||||
}
|
||||
|
||||
operator fun get(key: Link): N? = neighbours[key]
|
||||
|
||||
operator fun set(key: Link, node: N?) {
|
||||
|
@ -35,14 +35,32 @@ open class GraphNodeList<N : GraphNode<N, G>, G : GraphNodeList<N, G>> : ICondit
|
||||
return false
|
||||
}
|
||||
|
||||
fun beginTicking(node: N) {
|
||||
require(node in nodesInternal || node in queuedAdd) { "Node $node does not belong to $this" }
|
||||
if (node in queuedRemove) return
|
||||
|
||||
if (node is IConditionalTickable) {
|
||||
conditional.add(node)
|
||||
beginTicking()
|
||||
} else if (node is ITickable) {
|
||||
always.add(node)
|
||||
beginTicking()
|
||||
} else {
|
||||
throw ClassCastException("$node does not implement ITickable nor IConditionalTickable")
|
||||
}
|
||||
}
|
||||
|
||||
private fun addNow(node: N) {
|
||||
node.graph = this as G
|
||||
nodesInternal.add(node)
|
||||
|
||||
if (node is IConditionalTickable)
|
||||
if (node is IConditionalTickable) {
|
||||
conditional.add(node)
|
||||
else if (node is ITickable)
|
||||
beginTicking()
|
||||
} else if (node is ITickable) {
|
||||
always.add(node)
|
||||
beginTicking()
|
||||
}
|
||||
|
||||
onNodeAdded(node)
|
||||
}
|
||||
@ -178,7 +196,7 @@ open class GraphNodeList<N : GraphNode<N, G>, G : GraphNodeList<N, G>> : ICondit
|
||||
private val graphs = ArrayList<WeakReference<GraphNodeList<*, *>>>()
|
||||
private val queue = ArrayList<WeakReference<GraphNodeList<*, *>>>()
|
||||
|
||||
fun tick() {
|
||||
internal fun tick() {
|
||||
if (queue.isNotEmpty()) {
|
||||
graphs.addAll(queue)
|
||||
queue.clear()
|
||||
|
@ -15,6 +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.BlockEntityExplosionDebugger
|
||||
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.decorative.CargoCrateBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
|
||||
@ -73,6 +74,7 @@ object MBlockEntities {
|
||||
val DEV_CHEST by register(MNames.DEV_CHEST, ::DevChestBlockEntity, MBlocks::DEV_CHEST)
|
||||
val PAINTER by register(MNames.PAINTER, ::PainterBlockEntity, MBlocks::PAINTER)
|
||||
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 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) }
|
||||
|
@ -36,6 +36,7 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.block.BlackHoleBlock
|
||||
import ru.dbotthepony.mc.otm.block.BlockExplosionDebugger
|
||||
import ru.dbotthepony.mc.otm.block.BlockSphereDebugger
|
||||
import ru.dbotthepony.mc.otm.block.EnergyCableBlock
|
||||
import ru.dbotthepony.mc.otm.block.MatterCableBlock
|
||||
import ru.dbotthepony.mc.otm.block.StorageCableBlock
|
||||
import ru.dbotthepony.mc.otm.block.decorative.DevChestBlock
|
||||
@ -114,6 +115,7 @@ object MBlocks {
|
||||
val MATTER_RECONSTRUCTOR: MatterReconstructorBlock by registry.register(MNames.MATTER_RECONSTRUCTOR) { MatterReconstructorBlock() }
|
||||
val PAINTER: PainterBlock by registry.register(MNames.PAINTER) { PainterBlock() }
|
||||
val MATTER_ENTANGLER: MatterEntanglerBlock by registry.register(MNames.MATTER_ENTANGLER) { MatterEntanglerBlock() }
|
||||
val ENERGY_CABLE: EnergyCableBlock by registry.register(MNames.ENERGY_CABLE) { EnergyCableBlock() }
|
||||
|
||||
val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS) { StorageBusBlock() }
|
||||
val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER) { StorageImporterBlock() }
|
||||
|
@ -129,6 +129,7 @@ private fun CreativeModeTab.Output.fluids(value: Item) {
|
||||
|
||||
private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
|
||||
with(consumer) {
|
||||
accept(MItems.ENERGY_CABLE)
|
||||
accept(MItems.MACHINES)
|
||||
accept(MItems.MachineUpgrades.Basic.LIST)
|
||||
accept(MItems.MachineUpgrades.Normal.LIST)
|
||||
|
@ -46,6 +46,8 @@ object MItems {
|
||||
registry.register(bus)
|
||||
}
|
||||
|
||||
val ENERGY_CABLE: BlockItem by registry.register(MNames.ENERGY_CABLE) { BlockItem(MBlocks.ENERGY_CABLE, 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 BATTERY_BANK: BlockItem by registry.register(MNames.BATTERY_BANK) { BlockItem(MBlocks.BATTERY_BANK, DEFAULT_PROPERTIES) }
|
||||
|
@ -17,6 +17,7 @@ object MNames {
|
||||
const val DEV_CHEST = "dev_chest"
|
||||
const val PAINTER = "painter"
|
||||
const val MATTER_ENTANGLER = "matter_entangler"
|
||||
const val ENERGY_CABLE = "energy_cable"
|
||||
|
||||
// blocks
|
||||
const val ANDROID_STATION = "android_station"
|
||||
|
Loading…
Reference in New Issue
Block a user