121 lines
3.8 KiB
Kotlin
121 lines
3.8 KiB
Kotlin
package net.shadowfacts.phycon.block.netswitch
|
|
|
|
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
|
import net.minecraft.block.BlockState
|
|
import net.minecraft.block.entity.BlockEntity
|
|
import net.minecraft.entity.ItemEntity
|
|
import net.minecraft.nbt.CompoundTag
|
|
import net.minecraft.util.Tickable
|
|
import net.minecraft.util.math.Direction
|
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
|
import net.shadowfacts.phycon.api.Interface
|
|
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
|
import net.shadowfacts.phycon.api.frame.PacketFrame
|
|
import net.shadowfacts.phycon.api.util.MACAddress
|
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
|
import net.shadowfacts.phycon.util.NetworkUtil
|
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
|
import java.lang.ref.WeakReference
|
|
|
|
/**
|
|
* @author shadowfacts
|
|
*/
|
|
class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
|
BlockEntityClientSerializable,
|
|
Tickable {
|
|
|
|
companion object {
|
|
var SWITCHING_CAPACITY = 256 // 256 items/tick
|
|
}
|
|
|
|
val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) }
|
|
|
|
private val macTable = mutableMapOf<MACAddress, Direction>()
|
|
private var itemsHandledThisTick = 0
|
|
|
|
fun interfaceForSide(side: Direction): SwitchInterface {
|
|
return interfaces.find { it.side == side }!!
|
|
}
|
|
|
|
private fun handle(frame: EthernetFrame, fromItf: SwitchInterface) {
|
|
macTable[frame.source] = fromItf.side
|
|
|
|
if (frame is PacketFrame && frame.packet is ItemStackPacket) {
|
|
val packet = frame.packet as ItemStackPacket
|
|
if (itemsHandledThisTick + packet.stack.count > SWITCHING_CAPACITY) {
|
|
// 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
|
|
} else {
|
|
itemsHandledThisTick += packet.stack.count
|
|
}
|
|
}
|
|
|
|
if (frame.destination.type != MACAddress.Type.BROADCAST && macTable.containsKey(frame.destination)) {
|
|
val dir = macTable[frame.destination]!!
|
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) forwarding {} to side {}", this, fromItf.side, fromItf.macAddress, frame, dir)
|
|
interfaceForSide(dir).send(frame)
|
|
} else {
|
|
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) flooding {}", this, fromItf.side, fromItf.macAddress, 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() {
|
|
itemsHandledThisTick = 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<SwitchBlockEntity>,
|
|
@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)
|
|
}
|
|
}
|
|
|
|
}
|