diff --git a/src/main/java/net/shadowfacts/phycon/api/PacketSink.java b/src/main/java/net/shadowfacts/phycon/api/PacketSink.java index 2aacc3c..a8840ef 100644 --- a/src/main/java/net/shadowfacts/phycon/api/PacketSink.java +++ b/src/main/java/net/shadowfacts/phycon/api/PacketSink.java @@ -1,6 +1,7 @@ package net.shadowfacts.phycon.api; import net.shadowfacts.phycon.api.packet.Packet; +import net.shadowfacts.phycon.api.util.MACAddress; import org.jetbrains.annotations.NotNull; /** @@ -8,6 +9,9 @@ import org.jetbrains.annotations.NotNull; */ public interface PacketSink { + @NotNull + MACAddress getMACAddress(); + void handle(@NotNull Packet packet); } diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt index 4791bbe..dadaf12 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt @@ -7,6 +7,8 @@ import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity +import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock +import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity import net.shadowfacts.phycon.network.block.terminal.TerminalBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity @@ -17,6 +19,7 @@ object PhyBlockEntities { val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE) val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL) + val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH) private fun create(builder: () -> T, block: Block): BlockEntityType { return BlockEntityType.Builder.create(builder, arrayOf(block)).build(null) @@ -25,6 +28,7 @@ object PhyBlockEntities { fun init() { register(InterfaceBlock.ID, INTERFACE) register(TerminalBlock.ID, TERMINAL) + register(SwitchBlock.ID, SWITCH) } private fun register(id: Identifier, type: BlockEntityType<*>) { diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt index afd7d41..d8d33c8 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt @@ -4,6 +4,7 @@ import net.minecraft.block.Block import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock +import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlock /** @@ -13,10 +14,12 @@ object PhyBlocks { val INTERFACE = InterfaceBlock() val TERMINAL = TerminalBlock() + val SWITCH = SwitchBlock() fun init() { register(InterfaceBlock.ID, INTERFACE) register(TerminalBlock.ID, TERMINAL) + register(SwitchBlock.ID, SWITCH) } private fun register(id: Identifier, block: Block) { diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt index 7b03128..c032dcd 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt @@ -5,6 +5,7 @@ import net.minecraft.item.Item import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock +import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlock /** @@ -14,10 +15,12 @@ object PhyItems { val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings()) val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings()) + val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings()) fun init() { register(InterfaceBlock.ID, INTERFACE) register(TerminalBlock.ID, TERMINAL) + register(SwitchBlock.ID, SWITCH) } private fun register(id: Identifier, item: Item) { diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt index 26bf15f..fe11dac 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt @@ -20,13 +20,17 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), T private val sendQueue = LinkedList>>() + override fun getMACAddress(): MACAddress { + return macAddress + } + override fun handle(packet: Packet) { if (acceptsPacket(packet)) { handlePacket(packet) } } - abstract fun handlePacket(packet: Packet) + protected abstract fun handlePacket(packet: Packet) fun acceptsPacket(packet: Packet): Boolean { return when (packet.destination.type) { @@ -56,7 +60,11 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), T } fun enqueueToAll(packet: Packet) { - sendQueue.addAll(NetworkUtil.findDestinations(world!!, pos).map { packet to WeakReference(it) }) + enqueueToAll(packet, NetworkUtil.findDestinations(world!!, pos)) + } + + fun enqueueToAll(packet: Packet, destinations: Iterable) { + sendQueue.addAll(destinations.map { packet to WeakReference(it) }) } override fun tick() { diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt b/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt index 0ec0751..9eaa25b 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt @@ -13,11 +13,15 @@ import java.util.* */ object NetworkUtil { - fun findDestinations(world: World, startPos: BlockPos): List { + fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List { val results = LinkedList() val visited = hashSetOf(startPos) val queue = LinkedList() - addAdjacent(queue, visited, startPos) + if (direction != null) { + queue.add(startPos.offset(direction)) + } else { + addAdjacent(queue, visited, startPos) + } while (queue.isNotEmpty()) { val pos = queue.pop() diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlock.kt new file mode 100644 index 0000000..3b6b553 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlock.kt @@ -0,0 +1,27 @@ +package net.shadowfacts.phycon.network.block.netswitch + +import alexiil.mc.lib.attributes.AttributeList +import alexiil.mc.lib.attributes.AttributeProvider +import net.minecraft.block.BlockState +import net.minecraft.block.Material +import net.minecraft.util.Identifier +import net.minecraft.util.math.BlockPos +import net.minecraft.world.BlockView +import net.minecraft.world.World +import net.shadowfacts.phycon.PhysicalConnectivity +import net.shadowfacts.phycon.block.BlockWithEntity + +/** + * @author shadowfacts + */ +class SwitchBlock: BlockWithEntity(Settings.of(Material.METAL)), AttributeProvider { + companion object { + val ID = Identifier(PhysicalConnectivity.MODID, "switch") + } + + override fun createBlockEntity(world: BlockView) = SwitchBlockEntity() + + override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { + to.offer(getBlockEntity(world, pos)) + } +} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt new file mode 100644 index 0000000..d555d7e --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt @@ -0,0 +1,62 @@ +package net.shadowfacts.phycon.network.block.netswitch + +import net.minecraft.util.math.Direction +import net.shadowfacts.phycon.api.PacketSink +import net.shadowfacts.phycon.api.packet.Packet +import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.init.PhyBlockEntities +import net.shadowfacts.phycon.network.DeviceBlockEntity +import net.shadowfacts.phycon.network.NetworkUtil +import java.lang.RuntimeException +import javax.print.attribute.standard.Destination + +/** + * @author shadowfacts + */ +class SwitchBlockEntity: DeviceBlockEntity(PhyBlockEntities.SWITCH) { + + private val macTable = mutableMapOf() + + override fun handlePacket(packet: Packet) { + throw RuntimeException("Unreachable") + } + + override fun handle(packet: Packet) { + if (packet.destination == MACAddress.BROADCAST) { + val allDestinations = NetworkUtil.findDestinations(world!!, pos).filter { it.macAddress != packet.source } + enqueueToAll(packet, allDestinations) + } else { + val direction = macTable[packet.destination] + if (direction != null) { + val dest = findDestination(direction) + if (dest != null && packet.destination == dest.macAddress) { + enqueue(packet, dest) + return + } + } + flood(packet) + } + } + + private fun findDestination(direction: Direction): PacketSink? { + val allDestinations = NetworkUtil.findDestinations(world!!, pos, direction) + if (allDestinations.size > 1) { + // todo: do this better + println("Can't send packet, multiple destinations: $allDestinations") + return null + } + return allDestinations.firstOrNull() + } + + private fun flood(packet: Packet) { + for (dir in Direction.values()) { + val dest = findDestination(dir) + if (dest != null && packet.destination == dest.macAddress) { + macTable[packet.destination] = dir + enqueue(packet, dest) + break + } + } + } + +}