package net.shadowfacts.phycon.network.block.netswitch import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable import net.minecraft.block.BlockState import net.minecraft.block.entity.BlockEntity import net.minecraft.nbt.CompoundTag import net.minecraft.util.Tickable import net.minecraft.util.math.Direction import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.api.frame.EthernetFrame import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.network.NetworkUtil import java.lang.ref.WeakReference /** * @author shadowfacts */ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH), BlockEntityClientSerializable, Tickable { companion object { var SWITCHING_CAPACITY = 256 } val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) } private val macTable = mutableMapOf() private var packetsHandledThisTick = 0 // override fun handle(packet: Packet, itf: Interface) { // if (packetsHandledThisTick >= SWITCHING_CAPACITY) { // if (packet is ItemStackPacket) { // // todo: calculate entity spawn point by finding non-obstructed location // val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack) // world!!.spawnEntity(entity) // } // return // } // // packetsHandledThisTick++ // // if (packet.destination.isBroadcast) { //// for (other in interfaces) { //// if (other == itf) continue //// sendPacket(packet, other) //// } // flood(packet, itf) // } else { // val direction = ipTable[packet.destination] // if (direction != null) { // sendPacket() //// val dest = findDestination(direction) //// if (dest != null && packet.destination == dest.macAddress) { //// sendPacke(packet, dest) //// return //// } // } // flood(packet, itf) // } // } fun interfaceForSide(side: Direction): SwitchInterface { return interfaces.find { it.side == side }!! } private fun handle(frame: EthernetFrame, fromItf: Interface) { val itfSide = (fromItf as SwitchInterface).side macTable[frame.source] = itfSide val knownDir = macTable[frame.destination] if (knownDir != null) { println("$this ($itfSide, ${fromItf.macAddress}) forwarding $frame to side $knownDir") interfaceForSide(knownDir).send(frame) } else { println("$this ($itfSide, ${fromItf.macAddress}) flooding $frame") flood(frame, fromItf) } } private fun flood(frame: EthernetFrame, source: Interface) { for (itf in interfaces) { if (source == itf) continue itf.send(frame) } } private fun findDestination(fromItf: Interface): Interface? { val side = (fromItf as SwitchInterface).side return NetworkUtil.findConnectedInterface(world!!, pos, side) } override fun tick() { packetsHandledThisTick = 0 } override fun toTag(tag: CompoundTag): CompoundTag { tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) return super.toTag(tag) } override fun fromTag(state: BlockState, tag: CompoundTag) { super.fromTag(state, tag) tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> interfaces[i].macAddress = MACAddress(l) } } override fun toClientTag(tag: CompoundTag): CompoundTag { tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) return tag } override fun fromClientTag(tag: CompoundTag) { tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> interfaces[i].macAddress = MACAddress(l) } } class SwitchInterface( val side: Direction, val switch: WeakReference, @JvmField var macAddress: MACAddress, ): Interface { override fun getMACAddress() = macAddress override fun receive(frame: EthernetFrame) { switch.get()?.handle(frame, this) } override fun send(frame: EthernetFrame) { switch.get()?.findDestination(this)?.receive(frame) } } }