clean code, acceptable performance

This commit is contained in:
2026-04-26 16:05:46 +00:00
parent ed6ddddf98
commit 8edd36124b
24 changed files with 365 additions and 341 deletions

View File

@@ -4,38 +4,35 @@ import net.minecraft.client.player.LocalPlayer
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.ChatType
import net.minecraft.network.chat.OutgoingChatMessage
import net.minecraft.network.chat.PlayerChatMessage
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.PowerRole
import kotlin.math.min
open class CapacitorEntity(val capacity: Long, type: BlockEntityType<*>, pos: BlockPos, state: BlockState) : NodeBlockEntity(type, pos, state) {
override val node = object : Networking.Node() {
override val deviceNode = object : DeviceNode() {
override var powerRole = PowerRole.STORAGE
override var energyCapacity: Long = capacity
}
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
node.energy = min(compoundTag.getLong("energy"), node.energyCapacity)
deviceNode.energy = min(compoundTag.getLong("energy"), deviceNode.energyCapacity)
}
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.saveAdditional(compoundTag, provider)
compoundTag.putLong("energy", node.energy)
compoundTag.putLong("energy", deviceNode.energy)
}
}
@@ -65,8 +62,8 @@ class CapacitorBlock(val tier: Int) : NodeBlock() {
val p = player as LocalPlayer
val ent = level.getBlockEntity(blockPos)
if(ent is CapacitorEntity) {
if(p.isCrouching) ent.node.giveEnergy(1)
val msg = PlayerChatMessage.system("energy: ${ent.node.energy} / ${ent.capacity} (${ent.computeEdges().size} edges, ${ent.node.getReachable().size} connected)")
if(p.isCrouching) ent.deviceNode.giveEnergy(1)
val msg = PlayerChatMessage.system("energy: ${ent.deviceNode.energy} / ${ent.capacity} (${ent.computeEdges().size} edges, ${ent.deviceNode.getReachable().size} connected)")
p.sendSystemMessage(OutgoingChatMessage.create(msg).content())
}
}

View File

@@ -21,6 +21,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.DeviceNode
import java.time.Duration
object NodeSynchronizer {
@@ -148,30 +149,30 @@ object NodeSynchronizer {
}
abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState) : BlockEntity(blockEntityType, blockPos, blockState) {
abstract val node: Networking.Node
abstract val deviceNode: DeviceNode
fun initNetworking(): NodeBlockEntity {
Networking.addNode(node)
Networking.addNode(deviceNode)
invalidateNodeState()
return this
}
// runs on the server, meant to encode state to send to all players
open fun encodeDownstreamData(packet: FriendlyByteBuf) {
packet.writeUUID(node.address)
packet.writeLong(node.energy)
packet.writeLong(node.energyCapacity)
packet.writeEnum(node.reachability)
packet.writeEnum(node.powerRole)
packet.writeUUID(deviceNode.address)
packet.writeLong(deviceNode.energy)
packet.writeLong(deviceNode.energyCapacity)
packet.writeEnum(deviceNode.reachability)
packet.writeEnum(deviceNode.powerRole)
}
// runs on the client, meant to decode server state packets to synchronize client state
open fun syncWithUpstream(packet: FriendlyByteBuf) {
Networking.changeNodeAddress(node, packet.readUUID())
node.energy = packet.readLong()
node.energyCapacity = packet.readLong()
node.reachability = packet.readEnum(node.reachability.javaClass)
node.powerRole = packet.readEnum(node.powerRole.javaClass)
Networking.changeNodeAddress(deviceNode, packet.readUUID())
deviceNode.energy = packet.readLong()
deviceNode.energyCapacity = packet.readLong()
deviceNode.reachability = packet.readEnum(deviceNode.reachability.javaClass)
deviceNode.powerRole = packet.readEnum(deviceNode.powerRole.javaClass)
}
// Encodes data meant for the associated screen of a player
@@ -223,7 +224,7 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl
if(!stateIsDirty) return
stateIsDirty = false
computeEdges().forEach {
node.connectTo(it.node)
deviceNode.connectTo(it.deviceNode)
}
}
@@ -235,7 +236,7 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl
override fun setRemoved() {
super.setRemoved()
Networking.removeNode(node)
Networking.removeNode(deviceNode)
}
override fun clearRemoved() {
@@ -259,7 +260,7 @@ abstract class NodeBlock(properties: Properties = Properties.of()): BaseBlock(pr
return object : BlockEntityTicker<T> {
override fun tick(level: Level, blockPos: BlockPos, blockState: BlockState, blockEntity: T) {
if(blockEntity !is NodeBlockEntity) return
if(Networking.getNode(blockEntity.node.address) == null) blockEntity.initNetworking()
if(Networking.getNode(blockEntity.deviceNode.address) == null) blockEntity.initNetworking()
blockEntity.tickNode(level)
}
}

View File

@@ -7,14 +7,13 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.RedStoneWireBlock
import net.minecraft.world.level.block.RedstoneTorchBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.DeviceNode
fun dirToIdx(direction: Direction) = Direction.entries.indexOf(direction)
@@ -23,7 +22,7 @@ class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnt
val redstoneOut = Array<Int>(Direction.entries.size) {0}
// TODO: have redstone I/O node for component and shi
override val node = object : Networking.Node() {
override val deviceNode = object : DeviceNode() {
}
@@ -42,7 +41,7 @@ class RedstoneIOEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnt
}
fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) {
Networking.emitMessage(node, Networking.ComputerUncheckedSignal(node, "redstone_changed", arrayOf(node.address.toString(), dirToIdx(dir), oldValue, newValue)))
Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dirToIdx(dir), oldValue, newValue)))
NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue")
}
}

View File

@@ -7,32 +7,23 @@ import net.minecraft.core.Direction
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.block.state.properties.EnumProperty.*
import net.minecraft.world.level.block.state.properties.IntegerProperty
import net.minecraft.world.phys.BlockHitResult
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.BlockEntities
import org.neoflock.neocomputers.entity.ScreenEntity
import org.neoflock.neocomputers.gui.menu.Menus
import org.neoflock.neocomputers.gui.menu.ScreenMenu
import org.neoflock.neocomputers.network.Networking
import kotlin.math.abs
import kotlin.math.max
@@ -62,7 +53,7 @@ class ScreenBlock() : NodeBlock() {
): InteractionResult {
if(!level.isClientSide) {
val screenState = level.getBlockEntity(blockPos, BlockEntities.SCREEN_ENTITY.get()).get()
if(!screenState.node.consumeEnergy(ENERGY)) {
if(!screenState.deviceNode.consumeEnergy(ENERGY)) {
player.sendSystemMessage(Component.literal("Not enough power."))
return InteractionResult.SUCCESS
};

View File

@@ -25,6 +25,7 @@ import org.neoflock.neocomputers.block.NodeSynchronizer
import org.neoflock.neocomputers.block.dirToIdx
import org.neoflock.neocomputers.gui.menu.CaseMenu
import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole
import org.neoflock.neocomputers.sounds.ComputerRunningSoundInstance
@@ -44,7 +45,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
var arch = "Lua 5.3"
var soundInstance: SoundInstance? = null
override val node = object : Networking.Node() {
override val deviceNode = object : DeviceNode() {
override var powerRole = PowerRole.CONSUMER
override var energyCapacity: Long = 500
}
@@ -79,8 +80,8 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
super.encodeScreenData(player, packet)
packet.writeBoolean(isOn)
packet.writeByteArray((err ?: "").encodeToByteArray())
packet.writeLong(node.energy)
packet.writeLong(node.energyCapacity)
packet.writeLong(deviceNode.energy)
packet.writeLong(deviceNode.energyCapacity)
packet.writeLong(getMachineMemoryUsed())
packet.writeLong(getMachineMemoryTotal())
packet.writeLong(getMachineComponentsUsed())
@@ -112,12 +113,12 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
item.onMachineEvent(it, this, event)
}
}
Networking.emitMessage(node, Networking.ComputerEvent(node, event))
Networking.emitMessage(deviceNode, Networking.ComputerEvent(deviceNode, event))
}
fun onRedstoneSignalChanged(dir: Direction, oldValue: Int, newValue: Int) {
sendMachineEvent(MachineRedstoneEvent(this, dir, oldValue, newValue))
Networking.emitMessage(node, Networking.ComputerUncheckedSignal(node, "redstone_changed", arrayOf(node.address.toString(), dirToIdx(dir), oldValue, newValue)))
Networking.emitMessage(deviceNode, Networking.ComputerUncheckedSignal(deviceNode, "redstone_changed", arrayOf(deviceNode.address.toString(), dirToIdx(dir), oldValue, newValue)))
NeoComputers.LOGGER.info("redstone in direction ${dir.name} changed from $oldValue to $newValue")
if(oldValue == 0) {
// Rising edge
@@ -133,7 +134,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
fun setRunning(value: Boolean) {
if(isOn == value) return
NeoComputers.LOGGER.info("[${node.address}] Going from $isOn to $value")
NeoComputers.LOGGER.info("[${deviceNode.address}] Going from $isOn to $value")
isOn = value
val world = level ?: return
blockState?.setValue(CaseBlock.COMPUTER_RUNNING, isOn)
@@ -167,10 +168,10 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
return false
}
// less than 20% energy is bad
if(node.energy < node.energyCapacity/5) {
if(deviceNode.energy < deviceNode.energyCapacity/5) {
crash("@neocomputers.errors.ENOENJ")
// we add a beep for the special case where we do have a little bit of energy :P
if(node.energy > 0) beepAsync("..")
if(deviceNode.energy > 0) beepAsync("..")
return false
}
if(getMachineMemoryTotal() == 0L) {
@@ -205,7 +206,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
override fun getLastError(): String? = err
override fun getMachineNode(): Networking.Node = node
override fun getMachineNode() = deviceNode
override fun getRedstoneInput(direction: Direction): Int = redstoneIn[dirToIdx(direction)]
@@ -233,7 +234,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
override fun getMachineMemoryTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getMemoryCapacity(it) }.sum().toLong()
override fun getMachineMemoryUsed(): Long = 0
override fun getMachineComponentsUsed(): Long = node.getReachable().size.toLong()
override fun getMachineComponentsUsed(): Long = deviceNode.getReachable().size.toLong()
override fun getMachineComponentsTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getComponentCapacity(it) }.sum().toLong()
override fun getMachineArchitecture() = arch
override fun getMachineArchitectures() = stacks.mapNotNull { (it.item as? ComponentItem)?.getArchitecturesProvided(it) }.flatten().toSet()
@@ -252,14 +253,14 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
node.energy = min(node.energyCapacity, compoundTag.getLong("energy"))
deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy"))
//isOn = compoundTag.getBoolean("powerOn")
ContainerHelper.loadAllItems(compoundTag, getItems(), provider)
}
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.saveAdditional(compoundTag, provider)
compoundTag.putLong("energy", node.energy)
compoundTag.putLong("energy", deviceNode.energy)
//compoundTag.putBoolean("powerOn", isOn)
ContainerHelper.saveAllItems(compoundTag, getItems(), provider)
}
@@ -278,11 +279,12 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti
if (isRunning()) {
if(diskActivityTime > 0) diskActivityTime--
if(networkActivityTime > 0) networkActivityTime--
if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
crash("too many components")
}
if (!node.consumeEnergy(1)) {
crash("out of energy")
if(getMachineArchitectures().isEmpty()) {
crash("@neocomputers.errors.ENOCPU")
} else if(getMachineComponentsUsed() > getMachineComponentsTotal()) {
crash("@neocomputers.errors.E2BIG")
} else if (!deviceNode.consumeEnergy(1)) {
crash("@neocomputers.errors.ENOENJ")
}
}
}

View File

@@ -17,6 +17,7 @@ import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.block.CombustionGeneratorBlock
import org.neoflock.neocomputers.block.NodeBlockEntity
import org.neoflock.neocomputers.gui.menu.CombustionGeneratorMenu
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole
import org.neoflock.neocomputers.utils.GenericContainer
@@ -28,7 +29,7 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
var burningTimeRemaining: Int = 0
override val node = object : Networking.Node() {
override val deviceNode = object : DeviceNode() {
override var powerRole = PowerRole.GENERATOR
override var energyCapacity: Long = 100000
}
@@ -52,13 +53,13 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
// keep combusting and shi
if(burningTimeRemaining > 0) {
burningTimeRemaining--
node.giveEnergy(energyPerTick)
deviceNode.giveEnergy(energyPerTick)
setChanged()
return
}
// no point
if(node.energy >= node.energyCapacity) return;
if(deviceNode.energy >= deviceNode.energyCapacity) return;
// :fire:
val fuel = stacks[0]
@@ -79,20 +80,20 @@ class CombustionGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
}
override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) {
packet.writeLong(node.energy)
packet.writeLong(node.energyCapacity)
packet.writeLong(deviceNode.energy)
packet.writeLong(deviceNode.energyCapacity)
}
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
node.energy = min(node.energyCapacity, compoundTag.getLong("energy"))
deviceNode.energy = min(deviceNode.energyCapacity, compoundTag.getLong("energy"))
burningTimeRemaining = compoundTag.getInt("burningTimeRemaining")
ContainerHelper.loadAllItems(compoundTag, getItems(), provider)
}
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.saveAdditional(compoundTag, provider)
compoundTag.putLong("energy", node.energy)
compoundTag.putLong("energy", deviceNode.energy)
compoundTag.putInt("burningTimeRemaining", burningTimeRemaining)
ContainerHelper.saveAllItems(compoundTag, getItems(), provider)
}

View File

@@ -5,6 +5,7 @@ import net.minecraft.core.Direction
import net.minecraft.world.level.Level
import net.minecraft.world.phys.Vec3
import org.neoflock.neocomputers.item.ComponentItem
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import java.time.Duration
@@ -39,7 +40,7 @@ interface MachineEntity {
fun crash(error: String): Boolean
fun getLastError(): String?
fun getMachineNode(): Networking.Node
fun getMachineNode(): DeviceNode
// Some metadata
fun getMachineMemoryTotal(): Long

View File

@@ -1,8 +1,6 @@
package org.neoflock.neocomputers.entity;
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
@@ -11,15 +9,15 @@ import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.block.NodeBlockEntity
import org.neoflock.neocomputers.gui.buffer.BufferRenderer
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole
import org.neoflock.neocomputers.utils.GPUChar
import org.neoflock.neocomputers.utils.TextBuffer
class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
NodeBlockEntity(BlockEntities.SCREEN_ENTITY.get(), blockPos, blockState) {
override val node = object : Networking.Node() {
override val deviceNode = object : DeviceNode() {
override fun received(message: Networking.Message) {
super.received(message)
if(message is Networking.ComputerEvent) {
@@ -71,8 +69,7 @@ class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
}
private fun createscreenstuffs() {
bound = "screen/"+node.address.toString().replace("-", "_")
NeoComputers.LOGGER.info(bound)
bound = "screen/"+deviceNode.address.toString().replace("-", "_")
if (level!!.isClientSide) {
var renderer = BufferRenderer(ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, bound), textBuf)
renderer.drawBuffer()

View File

@@ -6,13 +6,14 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import org.neoflock.neocomputers.block.NodeBlockEntity
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.network.PowerRole
class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : NodeBlockEntity(BlockEntities.SOLARGEN_ENTITY.get(), blockPos, blockState) {
val energyPerTick: Long = 50
override val node = object : Networking.Node() {
override val deviceNode = object : DeviceNode() {
override var powerRole: PowerRole = PowerRole.GENERATOR
override var energyCapacity: Long = 50000
}
@@ -21,17 +22,17 @@ class SolarGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : No
super.tickNode(level)
val l = level
if(l.isDay) {
node.giveEnergy(energyPerTick)
deviceNode.giveEnergy(energyPerTick)
}
}
override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.loadAdditional(compoundTag, provider)
node.energy = compoundTag.getLong("energy")
deviceNode.energy = compoundTag.getLong("energy")
}
override fun saveAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) {
super.saveAdditional(compoundTag, provider)
compoundTag.putLong("energy", node.energy)
compoundTag.putLong("energy", deviceNode.energy)
}
}

View File

@@ -7,13 +7,13 @@ import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.Networking
open class CBUSItem(val tier: Int, val maxComponents: Int): Item(Item.Properties()), ComponentItem {
override fun getComponentRoles(itemStack: ItemStack): Set<String> = setOf(ComponentRoles.BUS)
override fun getComponentRoles(itemStack: ItemStack) = setOf(ComponentRoles.BUS)
override fun getComponentTier(itemStack: ItemStack): Int = tier
override fun getComponentTier(itemStack: ItemStack) = tier
override fun getComponentCapacity(itemStack: ItemStack): Int = maxComponents
override fun getComponentCapacity(itemStack: ItemStack) = maxComponents
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
}
class CBUS0: CBUSItem(1, 8)
class CBUS1: CBUSItem(2, 12)

View File

@@ -15,7 +15,7 @@ open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties(
override fun getArchitecturesProvided(itemStack: ItemStack): Set<String> = setOf("Lua 5.3")
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
}
class CPU0: CPUItem(1, 8)

View File

@@ -3,6 +3,7 @@ package org.neoflock.neocomputers.item
import net.minecraft.world.item.ItemStack
import org.neoflock.neocomputers.entity.MachineEntity
import org.neoflock.neocomputers.entity.MachineEvent
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import java.util.UUID
@@ -33,10 +34,10 @@ interface ComponentItem {
}
// To node, if applicable. Meant to create the node, but not add it, as it will use the itemStack's address to find it again
fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node?
fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): DeviceNode?
// Gets the node associated to an item, if it exists
fun getComponentNode(itemStack: ItemStack): Networking.Node? {
fun getComponentNode(itemStack: ItemStack): DeviceNode? {
val address = itemStack.get(DataComponents.ADDRESS) ?: return null
val uuid = UUID.fromString(address) ?: return null
return Networking.getNode(uuid)

View File

@@ -22,7 +22,7 @@ open class DataCard(val tier: Int, val limit: Long): Item(Properties()), Compone
}
// TODO: Modem Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -32,7 +32,7 @@ open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: In
super.whenComponentPlaced(itemStack, machine, newRole)
}
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -21,7 +21,7 @@ open class GPUCard(val tier: Int, val vram: Long): Item(Properties()), Component
}
// TODO: GPU Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -28,7 +28,7 @@ open class HardDiskItem(val tier: Int, val capacity: Long): Item(getDiskProperti
super.whenComponentPlaced(itemStack, machine, newRole)
}
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -20,7 +20,7 @@ class InternetCard: Item(Item.Properties()), ComponentItem {
}
// TODO: Internet Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -6,6 +6,7 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import org.neoflock.neocomputers.entity.MachineEntity
import org.neoflock.neocomputers.gui.widget.ComponentRoles
import org.neoflock.neocomputers.network.DeviceNode
import org.neoflock.neocomputers.network.Networking
import org.neoflock.neocomputers.utils.Formatting
@@ -19,7 +20,7 @@ open class MemoryItem(val tier: Int, val capacity: Int): Item(Item.Properties().
override fun getComponentCapacity(itemStack: ItemStack): Int = 0
// no node for memory
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -19,7 +19,7 @@ open class NetworkCard(val tier: Int, val maxRange: Int, val isWired: Boolean):
}
// TODO: Modem Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -21,7 +21,7 @@ open class RedstoneCard(val tier: Int): Item(Properties()), ComponentItem {
}
// TODO: Redstone Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -20,7 +20,7 @@ class TunnelCard: Item(Properties().component(DataComponents.TUNNEL_CHANNEL, "cr
}
// TODO: Tunnel Component
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?): Networking.Node? = null
override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity?) = null
override fun appendHoverText(
itemStack: ItemStack,

View File

@@ -0,0 +1,235 @@
package org.neoflock.neocomputers.network
import net.minecraft.core.BlockPos
import net.minecraft.network.FriendlyByteBuf
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.network.Networking.Message
import org.neoflock.neocomputers.network.Networking.Visibility
import org.neoflock.neocomputers.network.Networking.maxHopCount
import java.util.UUID
import kotlin.math.min
open class DeviceNode(_address: UUID? = null) {
val connections = HashSet<DeviceNode>()
private var reachableCache: Set<DeviceNode>? = null
var address = _address ?: UUID.randomUUID()
open var reachability = Visibility.NETWORK
open var powerRole = PowerRole.CONSUMER
open var energy: Long = 0
open var energyCapacity: Long = 0
// give energy, returns how much was actually given
// cannot exceed amount specified
open fun giveEnergy(amount: Long): Long {
val maximum = min(amount, energyCapacity - energy)
energy += maximum
markChanged()
return maximum
}
// take energy out, returns how much was actually taken
// cannot exceed amount specified
open fun withdrawEnergy(amount: Long): Long {
val maximum = min(amount, energy)
energy -= maximum
markChanged()
return maximum
}
fun getChargerNodes(): Set<DeviceNode> = getReachable().filter { it.powerRole != PowerRole.CONSUMER }.toSet()
fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energy }
fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energyCapacity }
// attempts to consume
fun consumeEnergy(energy: Long): Boolean {
// consumes energy, returns false if not enough
val total = totalEnergyInConnections() + this.energy
if(energy > total) return false
var remaining = energy
remaining -= withdrawEnergy(remaining)
if(remaining <= 0) return true
for (charger in getChargerNodes()) {
if(remaining <= 0) break
remaining -= charger.withdrawEnergy(remaining)
}
return true
}
// PLEASE only call if consumer, in the name of all that is holy
fun tryToChargeFully() {
var remaining = energyCapacity - energy
if(remaining <= 0) return
for (charger in getChargerNodes()) {
if(remaining <= 0) break
val amount = charger.withdrawEnergy(remaining)
val given = giveEnergy(amount)
remaining -= given
if(given < amount) {
val delta = amount - given // amount lost while given back
if(charger.giveEnergy(delta) < delta) {
NeoComputers.LOGGER.warn("LOSING ENERGY! Tried giving $delta back to $charger and we're losing our marbles!")
}
}
}
}
// only call if storage
fun balanceStorage() {
for(battery in getReachable()) {
if(battery.powerRole != PowerRole.STORAGE) continue
// its so if for example we have a battery with 2x the capacity
// we don't try to even the energy between them since that's just bad
// and might pointless delete energy over time
val capacityRatio = energyCapacity.toDouble() / battery.energyCapacity
val meaningfulSurplus = (battery.energy * capacityRatio - energy).toLong()
if(meaningfulSurplus <= 0) {
// WE'RE greedy (or negligible surplus)? Do nothing
continue
}
// steal from this greedy mf
val toSteal = meaningfulSurplus / 2
if(toSteal == 0L) continue // broke storahh
val stolen = battery.withdrawEnergy(toSteal)
if(giveEnergy(stolen) < stolen) {
NeoComputers.LOGGER.warn("LOSING ENERGY IN NODE $address!!!! THIS IS REALLY BAD!!!")
}
}
}
// rob the generators
fun stealGeneratorPower() {
var remaining = energyCapacity - energy
for(generator in getReachable()) {
if(generator.powerRole != PowerRole.GENERATOR) continue
// rob this mf
val robbed = generator.withdrawEnergy(remaining)
val taken = giveEnergy(robbed)
if(taken < robbed) {
NeoComputers.LOGGER.warn("energy caught being DELETED in the big 26")
}
remaining -= taken
}
}
open fun tick() {
if(powerRole == PowerRole.CONSUMER) tryToChargeFully()
if(powerRole == PowerRole.STORAGE) {
stealGeneratorPower()
balanceStorage()
}
}
// processes a received message
open fun received(message: Message) {}
// called when a new direct connection is made
open fun onConnect(deviceNode: DeviceNode) {}
// called when a direct connection is lost
open fun onDisconnect(deviceNode: DeviceNode) {}
// called when a new node is added globally
open fun onNodeAdded(deviceNode: DeviceNode) {
reachableCache = null;
}
// called when a node is removed globally
open fun onNodeRemoved(deviceNode: DeviceNode) {
reachableCache = null;
}
fun getReachable(): Set<DeviceNode> {
if(reachableCache == null) {
reachableCache = computeReachable();
}
return reachableCache!!;
}
fun invalidateReachableCache() {
reachableCache = null
}
fun computeReachable(): Set<DeviceNode> {
if(reachability == Visibility.NONE) {
return setOf();
}
if(reachability == Visibility.DIRECT) {
return connections.minus(this);
}
if(reachability == Visibility.NETWORK) {
// absolute cinema
val working = HashSet<DeviceNode>();
val pending = mutableListOf(this);
var iterCount = 0;
while(iterCount < maxHopCount && pending.isNotEmpty()) {
iterCount++;
val subnode = pending.removeFirst()
if(subnode in working) continue
working.add(subnode)
if(subnode.reachability == Visibility.NETWORK) {
pending.addAll(subnode.connections)
} else if(subnode.reachability == Visibility.DIRECT) {
working.addAll(subnode.connections)
}
}
// cannot send to itself!
working.remove(this);
return working;
}
throw NotImplementedError("visibility not implemented");
}
fun connectTo(other: DeviceNode) {
this.directConnectTo(other);
other.directConnectTo(this);
}
fun disconnectFrom(other: DeviceNode) {
this.directDisconnectFrom(other);
other.directDisconnectFrom(this);
}
fun directConnectTo(other: DeviceNode) {
if(other == this) return;
if(other in connections) return;
connections.add(other);
this.onConnect(other);
}
fun directDisconnectFrom(other: DeviceNode) {
if(other !in connections) return;
connections.remove(other);
this.onDisconnect(other);
}
// Network synchronization with the NodeSynchronizer
// TODO: process shi
var outOfSync = true
fun markChanged() {
outOfSync = true
}
open fun encodeScreenData(buf: FriendlyByteBuf) {}
// Meant to write the entire state as a single commit
// for clients which say they have no fucking idea what the server is storing
open fun writeFullStateCommit(buf: FriendlyByteBuf) {}
// client-side, meant to bring state forward
open fun processCommit(buf: FriendlyByteBuf) {}
}
abstract class WirelessEndpoint(address: UUID?) : DeviceNode(address) {
abstract fun getRange(): Double
abstract fun getDimension(): Int
abstract fun getPosition(): BlockPos
// separate from process for simplicity
abstract fun receiveWireless(message: Message, emitter: WirelessEndpoint)
}

View File

@@ -1,7 +1,6 @@
package org.neoflock.neocomputers.network
import net.minecraft.core.BlockPos
import org.neoflock.neocomputers.NeoComputers
import org.neoflock.neocomputers.entity.MachineEvent
import java.util.UUID
import kotlin.math.min
@@ -35,226 +34,24 @@ object Networking {
}
abstract class Message(val sender: Node)
abstract class Message(val sender: DeviceNode)
class ClassicPacket(sender: Node, val src: String, val dst: String, val port: Int, val data: List<Any>, val hopCount: Int) : Message(sender) {
class ClassicPacket(sender: DeviceNode, val src: String, val dst: String, val port: Int, val data: List<Any>, val hopCount: Int) : Message(sender) {
fun hop() = ClassicPacket(sender, src, dst, port, data, hopCount + 1);
}
// for plugins and shi
class ComputerCheckedSignal(sender: Node, val player: String?, val name: String, val data: Array<Any>): Message(sender)
class ComputerUncheckedSignal(sender: Node, val name: String, val data: Array<Any>): Message(sender)
class ComputerEvent(sender: Node, val machineEvent: MachineEvent): Message(sender)
open class Node(_address: UUID? = null) {
val connections = mutableSetOf<Node>()
private var reachableCache: Set<Node>? = null
var address = _address ?: UUID.randomUUID()
open var reachability = Visibility.NETWORK
open var powerRole = PowerRole.CONSUMER
open var energy: Long = 0
open var energyCapacity: Long = 0
// give energy, returns how much was actually given
// cannot exceed amount specified
open fun giveEnergy(amount: Long): Long {
val maximum = min(amount, energyCapacity - energy)
energy += maximum
return maximum
}
// take energy out, returns how much was actually taken
// cannot exceed amount specified
open fun withdrawEnergy(amount: Long): Long {
val maximum = min(amount, energy)
energy -= maximum
return maximum
}
fun getChargerNodes(): Set<Node> = getReachable().filter { it.powerRole != PowerRole.CONSUMER }.toSet()
fun totalEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energy }
fun maxEnergyInConnections(): Long = getChargerNodes().fold(0) { acc, node -> acc + node.energyCapacity }
// attempts to consume
fun consumeEnergy(energy: Long): Boolean {
// consumes energy, returns false if not enough
val total = totalEnergyInConnections() + this.energy
if(energy > total) return false
var remaining = energy
remaining -= withdrawEnergy(remaining)
if(remaining <= 0) return true
for (charger in getChargerNodes()) {
if(remaining <= 0) break
remaining -= charger.withdrawEnergy(remaining)
}
return true
}
// PLEASE only call if consumer, in the name of all that is holy
fun tryToChargeFully() {
var remaining = energyCapacity - energy
if(remaining <= 0) return
for (charger in getChargerNodes()) {
if(remaining <= 0) break
val amount = charger.withdrawEnergy(remaining)
val given = giveEnergy(amount)
remaining -= given
if(given < amount) {
val delta = amount - given // amount lost while given back
if(charger.giveEnergy(delta) < delta) {
NeoComputers.LOGGER.warn("LOSING ENERGY! Tried giving $delta back to $charger and we're losing our marbles!")
}
}
}
}
// only call if storage
fun balanceStorage() {
for(battery in getReachable()) {
if(battery.powerRole != PowerRole.STORAGE) continue
// its so if for example we have a battery with 2x the capacity
// we don't try to even the energy between them since that's just bad
// and might pointless delete energy over time
val capacityRatio = energyCapacity.toDouble() / battery.energyCapacity
val meaningfulSurplus = (battery.energy * capacityRatio - energy).toLong()
if(meaningfulSurplus <= 0) {
// WE'RE greedy (or negligible surplus)? Do nothing
continue
}
// steal from this greedy mf
val toSteal = meaningfulSurplus / 2
if(toSteal == 0L) continue // broke storahh
val stolen = battery.withdrawEnergy(toSteal)
if(giveEnergy(stolen) < stolen) {
NeoComputers.LOGGER.warn("LOSING ENERGY IN NODE $this!!!! THIS IS REALLY BAD!!!")
}
}
}
// rob the generators
fun stealGeneratorPower() {
var remaining = energyCapacity - energy
for(generator in getReachable()) {
if(generator.powerRole != PowerRole.GENERATOR) continue
// rob this mf
val robbed = generator.withdrawEnergy(remaining)
val taken = giveEnergy(robbed)
if(taken < robbed) {
NeoComputers.LOGGER.warn("energy caught being DELETED in the big 26")
}
remaining -= taken
}
}
open fun tick() {
if(powerRole == PowerRole.CONSUMER) tryToChargeFully()
if(powerRole == PowerRole.STORAGE) {
stealGeneratorPower()
balanceStorage()
}
}
// processes a received message
open fun received(message: Message) {}
// called when a new direct connection is made
open fun onConnect(node: Node) {}
// called when a direct connection is lost
open fun onDisconnect(node: Node) {}
// called when a new node is added globally
open fun onNodeAdded(node: Node) {
reachableCache = null;
}
// called when a node is removed globally
open fun onNodeRemoved(node: Node) {
reachableCache = null;
}
fun getReachable(): Set<Node> {
if(reachableCache == null) {
reachableCache = computeReachable();
}
return reachableCache!!;
}
fun invalidateReachableCache() {
reachableCache = null
}
fun computeReachable(): Set<Node> {
if(reachability == Visibility.NONE) {
return setOf();
}
if(reachability == Visibility.DIRECT) {
return connections.minus(this);
}
if(reachability == Visibility.NETWORK) {
// absolute cinema
val working = HashSet<Node>();
val pending = mutableListOf(this);
var iterCount = 0;
while(iterCount < maxHopCount && pending.isNotEmpty()) {
iterCount++;
val subnode = pending.removeFirst();
if(subnode in working) continue;
working.add(subnode);
pending.addAll(subnode.connections);
}
// cannot send to itself!
working.remove(this);
return working;
}
throw NotImplementedError("visibility not implemented");
}
fun connectTo(other: Node) {
this.directConnectTo(other);
other.directConnectTo(this);
}
fun disconnectFrom(other: Node) {
this.directDisconnectFrom(other);
other.directDisconnectFrom(this);
}
fun directConnectTo(other: Node) {
if(other == this) return;
if(other in connections) return;
connections.add(other);
this.onConnect(other);
}
fun directDisconnectFrom(other: Node) {
if(other !in connections) return;
connections.remove(other);
this.onDisconnect(other);
}
}
abstract class WirelessEndpoint(address: UUID?) : Node(address) {
abstract fun getRange(): Double
abstract fun getDimension(): Int
abstract fun getPosition(): BlockPos
// separate from process for simplicity
abstract fun receiveWireless(message: Message, emitter: WirelessEndpoint)
}
class ComputerCheckedSignal(sender: DeviceNode, val player: String?, val name: String, val data: Array<Any>): Message(sender)
class ComputerUncheckedSignal(sender: DeviceNode, val name: String, val data: Array<Any>): Message(sender)
class ComputerEvent(sender: DeviceNode, val machineEvent: MachineEvent): Message(sender)
val wirelessNodes = ThreadLocal.withInitial { HashSet<WirelessEndpoint>() }
val allNodes = ThreadLocal.withInitial { HashMap<UUID, Node>() }
val allNodes = ThreadLocal.withInitial { HashMap<UUID, DeviceNode>() }
// node may differ from message.sender in the case of relays,
// as they might have DIRECT reachability but
fun emitMessage(node: Node, message: Message) {
node.getReachable().forEach { it.received(message) }
fun emitMessage(deviceNode: DeviceNode, message: Message) {
deviceNode.getReachable().forEach { it.received(message) }
}
fun computeRangeAllowedByHardness(src: BlockPos, dst: BlockPos): Double {
@@ -285,69 +82,69 @@ object Networking {
tickCount++
}
fun getNode(address: UUID): Node? = allNodes.get()[address]
fun getNode(address: UUID): DeviceNode? = allNodes.get()[address]
// TODO: use setter, more convenient
fun changeNodeAddress(node: Node, address: UUID) {
if(node.address.equals(address)) return
if(node.address !in allNodes.get()) return
allNodes.get().remove(node.address)
node.address = address
allNodes.get()[address] = node
fun changeNodeAddress(deviceNode: DeviceNode, address: UUID) {
if(deviceNode.address.equals(address)) return
if(deviceNode.address !in allNodes.get()) return
allNodes.get().remove(deviceNode.address)
deviceNode.address = address
allNodes.get()[address] = deviceNode
}
fun addNode(node: Node) {
if(node.address in allNodes.get()) return
allNodes.get()[node.address] = node
if(node is WirelessEndpoint) {
wirelessNodes.get().add(node);
fun addNode(deviceNode: DeviceNode) {
if(deviceNode.address in allNodes.get()) return
allNodes.get()[deviceNode.address] = deviceNode
if(deviceNode is WirelessEndpoint) {
wirelessNodes.get().add(deviceNode);
}
// notify at the end so it is notified of its own creation
allNodes.get().forEach { it.value.onNodeAdded(node) }
allNodes.get().forEach { it.value.onNodeAdded(deviceNode) }
}
fun addNodes(vararg nodes: Node) {
nodes.forEach { addNode(it) }
fun addNodes(vararg deviceNodes: DeviceNode) {
deviceNodes.forEach { addNode(it) }
}
fun removeNode(node: Node) {
if(node.address !in allNodes.get()) return
allNodes.get().forEach { it.value.onNodeRemoved(node) }
fun removeNode(deviceNode: DeviceNode) {
if(deviceNode.address !in allNodes.get()) return
allNodes.get().forEach { it.value.onNodeRemoved(deviceNode) }
// toList() in order to copy it
node.connections.toList().forEach {
node.disconnectFrom(it)
deviceNode.connections.toList().forEach {
deviceNode.disconnectFrom(it)
}
// actually remove at the end so it can listen to its own removal
allNodes.get().remove(node.address)
if(node is WirelessEndpoint) {
wirelessNodes.get().remove(node);
allNodes.get().remove(deviceNode.address)
if(deviceNode is WirelessEndpoint) {
wirelessNodes.get().remove(deviceNode);
}
}
fun removeNodes(vararg nodes: Node) {
nodes.forEach { removeNode(it) }
fun removeNodes(vararg deviceNodes: DeviceNode) {
deviceNodes.forEach { removeNode(it) }
}
val channels = ThreadLocal.withInitial { HashMap<String, MutableSet<Node>>() }
val channels = ThreadLocal.withInitial { HashMap<String, MutableSet<DeviceNode>>() }
fun addToChannel(channel: String, node: Node) {
fun addToChannel(channel: String, deviceNode: DeviceNode) {
val localChannels = channels.get()
if(!localChannels.containsKey(channel)) {
localChannels[channel] = mutableSetOf();
}
localChannels[channel]!!.add(node);
localChannels[channel]!!.add(deviceNode);
}
fun removeFromChannel(channel: String, node: Node) {
fun removeFromChannel(channel: String, deviceNode: DeviceNode) {
val localChannels = channels.get()
if(!localChannels.containsKey(channel)) return;
localChannels[channel]?.remove(node);
localChannels[channel]?.remove(deviceNode);
if(localChannels[channel].isNullOrEmpty()) {
localChannels.remove(channel);
}
}
fun emitChannelMessage(starter: Node, channel: String, message: Message) {
fun emitChannelMessage(starter: DeviceNode, channel: String, message: Message) {
val localChannels = channels.get()
val c = localChannels[channel] ?: return;
c.forEach { if(it != starter) it.received(message); };

View File

@@ -15,23 +15,23 @@ object PowerManager {
//? if fabric {
EnergyStorage.SIDED.registerForBlockEntity({
entity, dir -> object : EnergyStorage {
override fun getAmount() = entity.node.energy
override fun getCapacity() = entity.node.energyCapacity
override fun supportsExtraction() = entity.node.powerRole != PowerRole.CONSUMER && entity.node.energyCapacity > 0
override fun supportsInsertion() = entity.node.powerRole != PowerRole.GENERATOR
override fun getAmount() = entity.deviceNode.energy
override fun getCapacity() = entity.deviceNode.energyCapacity
override fun supportsExtraction() = entity.deviceNode.powerRole != PowerRole.CONSUMER && entity.deviceNode.energyCapacity > 0
override fun supportsInsertion() = entity.deviceNode.powerRole != PowerRole.GENERATOR
override fun extract(maxAmount: Long, transaction: TransactionContext?): Long {
if(entity.node.powerRole == PowerRole.CONSUMER) return 0
val taken = entity.node.withdrawEnergy(maxAmount)
if(entity.deviceNode.powerRole == PowerRole.CONSUMER) return 0
val taken = entity.deviceNode.withdrawEnergy(maxAmount)
transaction?.addCloseCallback {
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.node.giveEnergy(taken)
ctx, res -> if(res.wasAborted() || !res.wasCommitted()) entity.deviceNode.giveEnergy(taken)
}
return taken
}
override fun insert(maxAmount: Long, transaction: TransactionContext?): Long {
if(entity.node.powerRole == PowerRole.GENERATOR) return 0
val given = entity.node.giveEnergy(maxAmount)
if(entity.deviceNode.powerRole == PowerRole.GENERATOR) return 0
val given = entity.deviceNode.giveEnergy(maxAmount)
transaction?.addCloseCallback { ctx, res ->
if (res.wasAborted() || !res.wasCommitted()) entity.node.withdrawEnergy(given)
if (res.wasAborted() || !res.wasCommitted()) entity.deviceNode.withdrawEnergy(given)
}
return given
}