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

207 lines
6.1 KiB
Kotlin
Raw Normal View History

2021-02-28 18:48:39 +00:00
package net.shadowfacts.phycon.block
2019-10-27 01:36:31 +00:00
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
2021-12-22 23:59:51 +00:00
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
import net.minecraft.util.math.BlockPos
2021-02-26 22:04:18 +00:00
import net.shadowfacts.phycon.PhysicalConnectivity
2021-02-13 23:24:36 +00:00
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkComponentBlock
2021-12-22 23:59:51 +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.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.frame.ARPQueryFrame
import net.shadowfacts.phycon.frame.ARPResponseFrame
import net.shadowfacts.phycon.frame.BasePacketFrame
import net.shadowfacts.phycon.packet.*
2021-12-22 23:59:51 +00:00
import net.shadowfacts.phycon.util.NetworkUtil
2021-02-13 23:24:36 +00:00
import java.util.*
2019-10-27 01:36:31 +00:00
/**
* @author shadowfacts
*/
2021-12-22 23:59:51 +00:00
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state),
2021-02-13 23:24:36 +00:00
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)
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-12-22 23:59:51 +00:00
open 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
}
}
2021-12-22 23:59:51 +00:00
protected open fun toCommonTag(tag: NbtCompound) {
2021-02-13 23:24:36 +00:00
tag.putInt("IPAddress", ipAddress.address)
tag.putLong("MACAddress", macAddress.address)
}
2021-12-22 23:59:51 +00:00
protected open fun fromCommonTag(tag: NbtCompound) {
ipAddress = IPAddress(tag.getInt("IPAddress"))
macAddress = MACAddress(tag.getLong("MACAddress"))
}
2021-12-22 23:59:51 +00:00
override fun writeNbt(tag: NbtCompound) {
super.writeNbt(tag)
toCommonTag(tag)
2019-10-27 01:36:31 +00:00
}
2021-12-22 23:59:51 +00:00
override fun readNbt(tag: NbtCompound) {
super.readNbt(tag)
fromCommonTag(tag)
2021-12-22 23:59:51 +00:00
if (tag.getBoolean("_SyncPacket")) {
fromClientTag(tag)
}
2021-02-13 23:24:36 +00:00
}
2021-12-22 23:59:51 +00:00
override fun toUpdatePacket(): BlockEntityUpdateS2CPacket {
return BlockEntityUpdateS2CPacket.create(this)
}
override fun toInitialChunkDataNbt(): NbtCompound {
val tag = NbtCompound()
tag.putBoolean("_SyncPacket", true)
return toClientTag(tag)
}
open fun toClientTag(tag: NbtCompound): NbtCompound {
toCommonTag(tag)
2021-02-13 23:24:36 +00:00
return tag
}
2021-12-22 23:59:51 +00:00
open fun fromClientTag(tag: NbtCompound) {
}
fun markUpdate() {
markDirty()
world!!.updateListeners(pos, cachedState, cachedState, 3)
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
}