PhysicalConnectivity/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt

184 lines
5.7 KiB
Kotlin
Raw Normal View History

2019-10-27 01:36:31 +00:00
package net.shadowfacts.phycon.network
2021-02-13 23:24:36 +00:00
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
2021-02-10 23:55:49 +00:00
import net.minecraft.block.BlockState
2019-10-27 01:36:31 +00:00
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.nbt.CompoundTag
2021-02-13 23:24:36 +00:00
import net.minecraft.util.Tickable
2021-02-26 22:04:18 +00:00
import net.shadowfacts.phycon.PhysicalConnectivity
2019-10-27 01:36:31 +00:00
import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.PacketSource
2021-02-13 23:24:36 +00:00
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.api.frame.EthernetFrame
import net.shadowfacts.phycon.api.frame.PacketFrame
2019-10-27 01:36:31 +00:00
import net.shadowfacts.phycon.api.packet.Packet
2021-02-13 23:24:36 +00:00
import net.shadowfacts.phycon.api.util.IPAddress
2019-10-27 01:36:31 +00:00
import net.shadowfacts.phycon.api.util.MACAddress
2021-02-13 23:24:36 +00:00
import net.shadowfacts.phycon.network.frame.ARPQueryFrame
import net.shadowfacts.phycon.network.frame.ARPResponseFrame
import net.shadowfacts.phycon.network.frame.BasePacketFrame
2021-02-24 03:05:05 +00:00
import net.shadowfacts.phycon.network.packet.*
2021-02-13 23:24:36 +00:00
import java.util.*
2019-10-27 01:36:31 +00:00
/**
* @author shadowfacts
*/
2021-02-13 23:24:36 +00:00
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
BlockEntityClientSerializable,
Tickable,
PacketSink,
PacketSource,
Interface {
2021-02-13 23:24:36 +00:00
companion object {
private const val ARP_RETRY_TIMEOUT = 200
}
var macAddress: MACAddress = MACAddress.random()
protected set
2019-10-27 01:36:31 +00:00
2021-02-13 23:24:36 +00:00
var ipAddress: IPAddress = IPAddress.random()
2019-10-27 01:36:31 +00:00
protected set
2021-02-13 23:24:36 +00:00
private val arpTable = mutableMapOf<IPAddress, MACAddress>()
private val packetQueue = LinkedList<PendingPacket>()
var counter: Long = 0
2019-10-27 03:13:26 +00:00
2021-02-13 23:24:36 +00:00
override fun getIPAddress() = ipAddress
override fun getMACAddress() = macAddress
2021-02-13 23:24:36 +00:00
abstract override fun handle(packet: Packet)
2021-02-13 23:24:36 +00:00
2021-02-24 03:05:05 +00:00
private fun doHandlePacket(packet: Packet) {
2021-02-26 22:04:18 +00:00
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}) received packet: {}", this, ipAddress, packet)
2021-02-24 03:05:05 +00:00
when (packet) {
is DeviceRemovedPacket -> {
arpTable.remove(packet.source)
}
}
handle(packet)
}
override fun send(frame: EthernetFrame) {
findDestination()?.receive(frame)
}
2021-02-13 23:24:36 +00:00
override fun receive(frame: EthernetFrame) {
2021-02-26 22:04:18 +00:00
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}, {}) received frame from {}: {}", this, ipAddress, macAddress, frame.source, frame)
2021-02-13 23:24:36 +00:00
when (frame) {
is ARPQueryFrame -> handleARPQuery(frame)
is ARPResponseFrame -> handleARPResponse(frame)
2021-02-13 23:24:36 +00:00
is PacketFrame -> {
if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) {
2021-02-24 03:05:05 +00:00
doHandlePacket(frame.packet)
2021-02-13 23:24:36 +00:00
}
}
2019-10-27 01:36:31 +00:00
}
}
private fun handleARPQuery(frame: ARPQueryFrame) {
2021-02-26 22:04:18 +00:00
PhysicalConnectivity.NETWORK_LOGGER.debug("{}, ({}), received ARP query for {}", this, ipAddress, frame.queryIP)
2021-02-13 23:24:36 +00:00
arpTable[frame.sourceIP] = frame.source
if (frame.queryIP == ipAddress) {
2021-02-26 22:04:18 +00:00
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}) sending ARP response to {} with {}", this, ipAddress, frame.sourceIP, macAddress)
send(ARPResponseFrame(ipAddress, macAddress, frame.source))
2019-10-27 01:36:31 +00:00
}
}
private fun handleARPResponse(frame: ARPResponseFrame) {
2021-02-13 23:24:36 +00:00
arpTable[frame.query] = frame.source
2021-02-26 22:04:18 +00:00
PhysicalConnectivity.NETWORK_LOGGER.debug("{}, ({}) received ARP response for {} with {}", this, ipAddress, frame.query, frame.source)
2021-02-13 23:24:36 +00:00
2021-02-14 21:03:52 +00:00
val toRemove = packetQueue.filter { (packet, _) ->
2021-02-13 23:24:36 +00:00
if (packet.destination == frame.query) {
send(BasePacketFrame(packet, macAddress, frame.source))
2021-02-13 23:24:36 +00:00
true
} else {
false
}
}
2021-02-14 21:03:52 +00:00
packetQueue.removeAll(toRemove)
2019-10-27 01:36:31 +00:00
}
override fun sendPacket(packet: Packet) {
if (packet.destination.isBroadcast) {
send(BasePacketFrame(packet, macAddress, MACAddress.BROADCAST))
} else if (arpTable.containsKey(packet.destination)) {
send(BasePacketFrame(packet, macAddress, arpTable[packet.destination]!!))
2021-02-13 23:24:36 +00:00
} else {
packetQueue.add(PendingPacket(packet, counter))
2021-02-13 23:24:36 +00:00
2021-02-26 22:04:18 +00:00
PhysicalConnectivity.NETWORK_LOGGER.debug("{} ({}) sending ARP query for {}", this, ipAddress, packet.destination)
send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
}
2019-10-27 03:13:26 +00:00
}
open fun findDestination(): Interface? {
2021-02-13 23:24:36 +00:00
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
if (sides.size != 1) {
throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
}
return NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
2019-10-27 01:36:31 +00:00
}
2021-02-13 23:24:36 +00:00
override fun tick() {
counter++
2021-02-13 23:24:36 +00:00
if (!world!!.isClient) {
2021-02-14 21:03:52 +00:00
val toRemove = packetQueue.filter { entry ->
val (packet, timestamp) = entry
2021-02-13 23:24:36 +00:00
if (arpTable.containsKey(packet.destination)) {
send(BasePacketFrame(packet, macAddress, arpTable[packet.destination]!!))
2021-02-13 23:24:36 +00:00
true
} else if (counter - timestamp >= ARP_RETRY_TIMEOUT) {
send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
2021-02-13 23:24:36 +00:00
entry.timestamp = counter
// todo: should there be a retry counter?
true
} else {
false
}
}
2021-02-14 21:03:52 +00:00
packetQueue.removeAll(toRemove)
2019-10-27 01:36:31 +00:00
}
}
override fun toTag(tag: CompoundTag): CompoundTag {
2021-02-13 23:24:36 +00:00
tag.putInt("IPAddress", ipAddress.address)
tag.putLong("MACAddress", macAddress.address)
2019-10-27 01:36:31 +00:00
return super.toTag(tag)
}
2021-02-10 23:55:49 +00:00
override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag)
2021-02-13 23:24:36 +00:00
ipAddress = IPAddress(tag.getInt("IPAddress"))
macAddress = MACAddress(tag.getLong("MACAddress"))
2021-02-13 23:24:36 +00:00
}
override fun toClientTag(tag: CompoundTag): CompoundTag {
tag.putInt("IPAddress", ipAddress.address)
tag.putLong("MACAddress", macAddress.address)
2021-02-13 23:24:36 +00:00
return tag
}
override fun fromClientTag(tag: CompoundTag) {
ipAddress = IPAddress(tag.getInt("IPAddress"))
macAddress = MACAddress(tag.getLong("MACAddress"))
2019-10-27 01:36:31 +00:00
}
fun onBreak() {
if (!world!!.isClient) {
sendPacket(DeviceRemovedPacket(this))
}
}
2021-02-13 23:24:36 +00:00
data class PendingPacket(
val packet: Packet,
var timestamp: Long,
)
2019-10-27 01:36:31 +00:00
}