From 8edd36124bf06b960da6a3c1ba14b1b3b4d05289 Mon Sep 17 00:00:00 2001 From: ionut Date: Sun, 26 Apr 2026 16:05:46 +0000 Subject: [PATCH] clean code, acceptable performance --- .../neoflock/neocomputers/block/Capacitor.kt | 15 +- .../neoflock/neocomputers/block/NodeBlock.kt | 31 +- .../neoflock/neocomputers/block/RedstoneIO.kt | 7 +- .../neocomputers/block/ScreenBlock.kt | 11 +- .../neocomputers/entity/CaseBlockEntity.kt | 36 +-- .../entity/CombustionGeneratorBlockEntity.kt | 15 +- .../neocomputers/entity/MachineEntity.kt | 3 +- .../neocomputers/entity/ScreenEntity.kt | 9 +- .../entity/SolarGeneratorBlockEntity.kt | 9 +- .../neoflock/neocomputers/item/CBUSItem.kt | 8 +- .../org/neoflock/neocomputers/item/CPUItem.kt | 2 +- .../neocomputers/item/ComponentItem.kt | 5 +- .../neoflock/neocomputers/item/DataCard.kt | 2 +- .../neoflock/neocomputers/item/EEPROMItem.kt | 2 +- .../org/neoflock/neocomputers/item/GPUCard.kt | 2 +- .../org/neoflock/neocomputers/item/HDDItem.kt | 2 +- .../neocomputers/item/InternetCard.kt | 2 +- .../neoflock/neocomputers/item/MemoryItem.kt | 3 +- .../neoflock/neocomputers/item/NetworkCard.kt | 2 +- .../neocomputers/item/RedstoneCard.kt | 2 +- .../neoflock/neocomputers/item/TunnelCard.kt | 2 +- .../neocomputers/network/DeviceNode.kt | 235 +++++++++++++++ .../neocomputers/network/Networking.kt | 281 +++--------------- .../neocomputers/network/PowerManager.kt | 20 +- 24 files changed, 365 insertions(+), 341 deletions(-) create mode 100644 src/main/kotlin/org/neoflock/neocomputers/network/DeviceNode.kt diff --git a/src/main/kotlin/org/neoflock/neocomputers/block/Capacitor.kt b/src/main/kotlin/org/neoflock/neocomputers/block/Capacitor.kt index efebf8f..ebc0b82 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/block/Capacitor.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/block/Capacitor.kt @@ -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()) } } diff --git a/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt b/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt index d4a0b5c..9fe9c89 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt @@ -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 { 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) } } diff --git a/src/main/kotlin/org/neoflock/neocomputers/block/RedstoneIO.kt b/src/main/kotlin/org/neoflock/neocomputers/block/RedstoneIO.kt index bb820e9..b106a0f 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/block/RedstoneIO.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/block/RedstoneIO.kt @@ -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(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") } } diff --git a/src/main/kotlin/org/neoflock/neocomputers/block/ScreenBlock.kt b/src/main/kotlin/org/neoflock/neocomputers/block/ScreenBlock.kt index c57e8a5..6a8e2b7 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/block/ScreenBlock.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/block/ScreenBlock.kt @@ -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 }; diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt index 0b9cdc6..ea0535c 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt @@ -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") } } } diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/CombustionGeneratorBlockEntity.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/CombustionGeneratorBlockEntity.kt index 43969ec..a2f60e6 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/CombustionGeneratorBlockEntity.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/CombustionGeneratorBlockEntity.kt @@ -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) } diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt index 87a54e4..48db41e 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt @@ -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 diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/ScreenEntity.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/ScreenEntity.kt index 602abf4..e3821c2 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/ScreenEntity.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/ScreenEntity.kt @@ -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() diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/SolarGeneratorBlockEntity.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/SolarGeneratorBlockEntity.kt index 1c099ea..fdf21b6 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/SolarGeneratorBlockEntity.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/SolarGeneratorBlockEntity.kt @@ -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) } } \ No newline at end of file diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/CBUSItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/CBUSItem.kt index 57f7e9d..f036efd 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/CBUSItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/CBUSItem.kt @@ -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 = 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) diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt index 70285d4..d8637c7 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt @@ -15,7 +15,7 @@ open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties( override fun getArchitecturesProvided(itemStack: ItemStack): Set = 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) diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt index 766ffbe..86a4c60 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt @@ -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) diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/DataCard.kt b/src/main/kotlin/org/neoflock/neocomputers/item/DataCard.kt index 32c6b28..1dff84f 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/DataCard.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/DataCard.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt index b73b15d..988e23a 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/GPUCard.kt b/src/main/kotlin/org/neoflock/neocomputers/item/GPUCard.kt index a4d85a6..33fe733 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/GPUCard.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/GPUCard.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/HDDItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/HDDItem.kt index 93a4e6a..1f86e9e 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/HDDItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/HDDItem.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/InternetCard.kt b/src/main/kotlin/org/neoflock/neocomputers/item/InternetCard.kt index cee91d8..5eff792 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/InternetCard.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/InternetCard.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/MemoryItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/MemoryItem.kt index 943cffe..5537450 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/MemoryItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/MemoryItem.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/NetworkCard.kt b/src/main/kotlin/org/neoflock/neocomputers/item/NetworkCard.kt index 96457c1..fd7fd68 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/NetworkCard.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/NetworkCard.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/RedstoneCard.kt b/src/main/kotlin/org/neoflock/neocomputers/item/RedstoneCard.kt index 2b2a519..148ab17 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/RedstoneCard.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/RedstoneCard.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/TunnelCard.kt b/src/main/kotlin/org/neoflock/neocomputers/item/TunnelCard.kt index 3e21327..c5ab224 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/TunnelCard.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/TunnelCard.kt @@ -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, diff --git a/src/main/kotlin/org/neoflock/neocomputers/network/DeviceNode.kt b/src/main/kotlin/org/neoflock/neocomputers/network/DeviceNode.kt new file mode 100644 index 0000000..4cb972e --- /dev/null +++ b/src/main/kotlin/org/neoflock/neocomputers/network/DeviceNode.kt @@ -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() + private var reachableCache: Set? = 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 = 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 { + if(reachableCache == null) { + reachableCache = computeReachable(); + } + return reachableCache!!; + } + + fun invalidateReachableCache() { + reachableCache = null + } + + fun computeReachable(): Set { + if(reachability == Visibility.NONE) { + return setOf(); + } + if(reachability == Visibility.DIRECT) { + return connections.minus(this); + } + if(reachability == Visibility.NETWORK) { + // absolute cinema + val working = HashSet(); + 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) +} \ No newline at end of file diff --git a/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt b/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt index 914830a..362113e 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt @@ -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, val hopCount: Int) : Message(sender) { + class ClassicPacket(sender: DeviceNode, val src: String, val dst: String, val port: Int, val data: List, 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): Message(sender) - class ComputerUncheckedSignal(sender: Node, val name: String, val data: Array): Message(sender) - class ComputerEvent(sender: Node, val machineEvent: MachineEvent): Message(sender) - - open class Node(_address: UUID? = null) { - val connections = mutableSetOf() - private var reachableCache: Set? = 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 = 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 { - if(reachableCache == null) { - reachableCache = computeReachable(); - } - return reachableCache!!; - } - - fun invalidateReachableCache() { - reachableCache = null - } - - fun computeReachable(): Set { - if(reachability == Visibility.NONE) { - return setOf(); - } - if(reachability == Visibility.DIRECT) { - return connections.minus(this); - } - if(reachability == Visibility.NETWORK) { - // absolute cinema - val working = HashSet(); - 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): Message(sender) + class ComputerUncheckedSignal(sender: DeviceNode, val name: String, val data: Array): Message(sender) + class ComputerEvent(sender: DeviceNode, val machineEvent: MachineEvent): Message(sender) val wirelessNodes = ThreadLocal.withInitial { HashSet() } - val allNodes = ThreadLocal.withInitial { HashMap() } + val allNodes = ThreadLocal.withInitial { HashMap() } // 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>() } + val channels = ThreadLocal.withInitial { HashMap>() } - 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); }; diff --git a/src/main/kotlin/org/neoflock/neocomputers/network/PowerManager.kt b/src/main/kotlin/org/neoflock/neocomputers/network/PowerManager.kt index 7537b64..2abb8d0 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/network/PowerManager.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/network/PowerManager.kt @@ -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 }