2021-02-28 18:48:39 +00:00
|
|
|
package net.shadowfacts.phycon.block
|
2019-10-27 01:36:31 +00:00
|
|
|
|
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
|
2021-02-12 04:11:50 +00:00
|
|
|
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-28 18:48:39 +00:00
|
|
|
import net.shadowfacts.phycon.util.NetworkUtil
|
|
|
|
import net.shadowfacts.phycon.frame.ARPQueryFrame
|
|
|
|
import net.shadowfacts.phycon.frame.ARPResponseFrame
|
|
|
|
import net.shadowfacts.phycon.frame.BasePacketFrame
|
|
|
|
import net.shadowfacts.phycon.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,
|
2021-02-14 02:28:44 +00:00
|
|
|
Interface {
|
2021-02-13 23:24:36 +00:00
|
|
|
|
|
|
|
companion object {
|
|
|
|
private const val ARP_RETRY_TIMEOUT = 200
|
|
|
|
}
|
|
|
|
|
2021-02-14 02:28:44 +00:00
|
|
|
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>()
|
|
|
|
|
2021-02-18 03:09:44 +00:00
|
|
|
var counter: Long = 0
|
2019-10-27 03:13:26 +00:00
|
|
|
|
2021-02-13 23:24:36 +00:00
|
|
|
override fun getIPAddress() = ipAddress
|
2021-02-14 02:28:44 +00:00
|
|
|
override fun getMACAddress() = macAddress
|
2021-02-13 23:24:36 +00:00
|
|
|
|
2021-02-14 02:28:44 +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)
|
|
|
|
}
|
|
|
|
|
2021-02-14 02:28:44 +00:00
|
|
|
override fun send(frame: EthernetFrame) {
|
|
|
|
findDestination()?.receive(frame)
|
|
|
|
}
|
2021-02-13 23:24:36 +00:00
|
|
|
|
2021-02-14 02:28:44 +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) {
|
2021-02-14 02:28:44 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 02:28:44 +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)
|
2021-02-14 02:28:44 +00:00
|
|
|
send(ARPResponseFrame(ipAddress, macAddress, frame.source))
|
2019-10-27 01:36:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 02:28:44 +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) {
|
2021-02-14 02:28:44 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-02-14 02:28:44 +00:00
|
|
|
override fun sendPacket(packet: Packet) {
|
2021-02-14 02:37:39 +00:00
|
|
|
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 {
|
2021-02-14 02:28:44 +00:00
|
|
|
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)
|
2021-02-14 02:28:44 +00:00
|
|
|
send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
|
2019-10-27 02:09:16 +00:00
|
|
|
}
|
2019-10-27 03:13:26 +00:00
|
|
|
}
|
|
|
|
|
2021-02-14 02:28:44 +00:00
|
|
|
open fun findDestination(): Interface? {
|
2021-02-13 23:24:36 +00:00
|
|
|
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
|
2021-03-06 20:32:38 +00:00
|
|
|
return when (sides.size) {
|
|
|
|
0 -> null
|
|
|
|
1 -> NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
|
|
|
|
else -> throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
2021-02-13 23:24:36 +00:00
|
|
|
}
|
2019-10-27 01:36:31 +00:00
|
|
|
}
|
|
|
|
|
2021-02-13 23:24:36 +00:00
|
|
|
override fun tick() {
|
2021-02-14 02:37:39 +00:00
|
|
|
counter++
|
2021-02-13 23:24:36 +00:00
|
|
|
|
2021-02-14 02:37:39 +00:00
|
|
|
if (!world!!.isClient) {
|
2021-02-14 21:03:52 +00:00
|
|
|
val toRemove = packetQueue.filter { entry ->
|
2021-02-14 02:28:44 +00:00
|
|
|
val (packet, timestamp) = entry
|
2021-02-13 23:24:36 +00:00
|
|
|
if (arpTable.containsKey(packet.destination)) {
|
2021-02-14 02:28:44 +00:00
|
|
|
send(BasePacketFrame(packet, macAddress, arpTable[packet.destination]!!))
|
2021-02-13 23:24:36 +00:00
|
|
|
true
|
|
|
|
} else if (counter - timestamp >= ARP_RETRY_TIMEOUT) {
|
2021-02-14 02:28:44 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-01 03:47:54 +00:00
|
|
|
protected open fun toCommonTag(tag: CompoundTag) {
|
2021-02-13 23:24:36 +00:00
|
|
|
tag.putInt("IPAddress", ipAddress.address)
|
2021-02-14 02:28:44 +00:00
|
|
|
tag.putLong("MACAddress", macAddress.address)
|
2021-03-01 03:47:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected open fun fromCommonTag(tag: CompoundTag) {
|
|
|
|
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
|
|
|
macAddress = MACAddress(tag.getLong("MACAddress"))
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun toTag(tag: CompoundTag): CompoundTag {
|
|
|
|
toCommonTag(tag)
|
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-03-01 03:47:54 +00:00
|
|
|
fromCommonTag(tag)
|
2021-02-13 23:24:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
2021-03-01 03:47:54 +00:00
|
|
|
toCommonTag(tag)
|
2021-02-13 23:24:36 +00:00
|
|
|
return tag
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun fromClientTag(tag: CompoundTag) {
|
2021-03-01 03:47:54 +00:00
|
|
|
fromCommonTag(tag)
|
2019-10-27 01:36:31 +00:00
|
|
|
}
|
|
|
|
|
2019-10-28 21:48:10 +00:00
|
|
|
fun onBreak() {
|
2021-02-14 21:04:03 +00:00
|
|
|
if (!world!!.isClient) {
|
|
|
|
sendPacket(DeviceRemovedPacket(this))
|
|
|
|
}
|
2019-10-28 21:48:10 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|