Refactor DeviceBlockEntity to only have 1 interface

This commit is contained in:
Shadowfacts 2021-02-13 21:28:44 -05:00
parent e8425b80fd
commit fc3716153f
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
11 changed files with 61 additions and 204 deletions

View File

@ -1,7 +1,6 @@
package net.shadowfacts.phycon.api; package net.shadowfacts.phycon.api;
import net.shadowfacts.phycon.api.frame.EthernetFrame; import net.shadowfacts.phycon.api.frame.EthernetFrame;
import net.shadowfacts.phycon.api.packet.Packet;
import net.shadowfacts.phycon.api.util.MACAddress; import net.shadowfacts.phycon.api.util.MACAddress;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -17,6 +16,4 @@ public interface Interface {
void send(@NotNull EthernetFrame frame); void send(@NotNull EthernetFrame frame);
// void send(@NotNull Packet packet);
} }

View File

@ -8,9 +8,6 @@ import org.jetbrains.annotations.NotNull;
*/ */
public interface PacketSink extends NetworkDevice { public interface PacketSink extends NetworkDevice {
@NotNull void handle(@NotNull Packet packet);
Iterable<Interface> getDeviceInterfaces();
void handle(@NotNull Packet packet, @NotNull Interface itf);
} }

View File

@ -10,7 +10,7 @@ import org.jetbrains.annotations.Nullable;
// todo: does PacketSource actually need to extend NetworkDevice? // todo: does PacketSource actually need to extend NetworkDevice?
public interface PacketSource extends NetworkDevice { public interface PacketSource extends NetworkDevice {
// todo: better name for this // todo: better name for this
void sendPacket(@NotNull Packet packet, @Nullable Interface itf); void sendPacket(@NotNull Packet packet);
// void sendToAll(@NotNull Packet packet); // void sendToAll(@NotNull Packet packet);
// //

View File

@ -1,53 +0,0 @@
package net.shadowfacts.phycon.network
import net.shadowfacts.phycon.api.frame.EthernetFrame
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.network.frame.BaseFrame
import java.lang.ref.WeakReference
/**
* @author shadowfacts
*/
open class BaseInterface(
var macAddress: MACAddress,
private val delegate: WeakReference<InterfaceDelegate>
): Interface {
constructor(delegate: InterfaceDelegate): this(MACAddress.random(), WeakReference(delegate))
override fun getMACAddress(): MACAddress {
return macAddress
}
override fun receive(frame: EthernetFrame) {
delegate.get()?.handle(frame, this)
}
override fun send(frame: EthernetFrame) {
delegate.get()?.findDestination(this)?.receive(frame)
}
// override fun send(packet: Packet) {
// delegate.get()?.findDestination(this)?.also {
// it.receive(BaseFrame(packet, this.macAddress, it.macAddress))
// }
// }
override fun equals(other: Any?): Boolean {
return (other as? BaseInterface)?.macAddress == macAddress
}
override fun hashCode(): Int {
return macAddress.hashCode()
}
}
interface InterfaceDelegate {
fun findDestination(fromItf: Interface): Interface?
fun handle(frame: EthernetFrame, fromItf: Interface)
}

View File

@ -3,7 +3,9 @@ package net.shadowfacts.phycon.network
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.World import net.minecraft.world.World
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkComponentBlock import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.block.BlockWithEntity import net.shadowfacts.phycon.block.BlockWithEntity
@ -12,6 +14,10 @@ import net.shadowfacts.phycon.block.BlockWithEntity
*/ */
abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithEntity<T>(settings), NetworkComponentBlock { abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithEntity<T>(settings), NetworkComponentBlock {
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
return getBlockEntity(world, pos)!!
}
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) { override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
super.onBreak(world, pos, state, player) super.onBreak(world, pos, state, player)
getBlockEntity(world, pos)!!.onBreak() getBlockEntity(world, pos)!!.onBreak()

View File

@ -30,61 +30,61 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
Tickable, Tickable,
PacketSink, PacketSink,
PacketSource, PacketSource,
InterfaceDelegate { Interface {
companion object { companion object {
private const val ARP_RETRY_TIMEOUT = 200 private const val ARP_RETRY_TIMEOUT = 200
} }
// var macAddress: MACAddress = MACAddress.random() var macAddress: MACAddress = MACAddress.random()
// protected set protected set
var ipAddress: IPAddress = IPAddress.random() var ipAddress: IPAddress = IPAddress.random()
protected set protected set
open val interfaces: List<BaseInterface> = listOf()
// abstract val itf: BaseInterface
private val arpTable = mutableMapOf<IPAddress, MACAddress>() private val arpTable = mutableMapOf<IPAddress, MACAddress>()
private val packetQueue = LinkedList<PendingPacket>() private val packetQueue = LinkedList<PendingPacket>()
protected var counter: Long = 0 protected var counter: Long = 0
override fun getIPAddress() = ipAddress override fun getIPAddress() = ipAddress
override fun getMACAddress() = macAddress
override fun getDeviceInterfaces() = interfaces abstract override fun handle(packet: Packet)
abstract override fun handle(packet: Packet, itf: Interface) override fun send(frame: EthernetFrame) {
findDestination()?.receive(frame)
}
override fun handle(frame: EthernetFrame, fromItf: Interface) { override fun receive(frame: EthernetFrame) {
println("$this ($ipAddress, ${fromItf.macAddress}) received frame from ${frame.source}: $frame") println("$this ($ipAddress, ${macAddress}) received frame from ${frame.source}: $frame")
when (frame) { when (frame) {
is ARPQueryFrame -> handleARPQuery(frame, fromItf) is ARPQueryFrame -> handleARPQuery(frame)
is ARPResponseFrame -> handleARPResponse(frame, fromItf) is ARPResponseFrame -> handleARPResponse(frame)
is PacketFrame -> { is PacketFrame -> {
if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) { if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) {
handle(frame.packet, fromItf) handle(frame.packet)
} }
} }
} }
} }
private fun handleARPQuery(frame: ARPQueryFrame, fromItf: Interface) { private fun handleARPQuery(frame: ARPQueryFrame) {
println("$this ($ipAddress) received ARP query for ${frame.queryIP}") println("$this ($ipAddress) received ARP query for ${frame.queryIP}")
arpTable[frame.sourceIP] = frame.source arpTable[frame.sourceIP] = frame.source
if (frame.queryIP == ipAddress) { if (frame.queryIP == ipAddress) {
println("$this ($ipAddress) sending ARP response to ${frame.source} with ${fromItf.macAddress}") println("$this ($ipAddress) sending ARP response to ${frame.source} with $macAddress")
fromItf.send(ARPResponseFrame(ipAddress, fromItf.macAddress, frame.source)) send(ARPResponseFrame(ipAddress, macAddress, frame.source))
} }
} }
private fun handleARPResponse(frame: ARPResponseFrame, fromItf: Interface) { private fun handleARPResponse(frame: ARPResponseFrame) {
arpTable[frame.query] = frame.source arpTable[frame.query] = frame.source
println("$this ($ipAddress) received ARP response for ${frame.query} with ${frame.source}") println("$this ($ipAddress) received ARP response for ${frame.query} with ${frame.source}")
packetQueue.removeIf { (packet, itf, _) -> packetQueue.removeIf { (packet, _) ->
if (packet.destination == frame.query) { if (packet.destination == frame.query) {
itf.send(BasePacketFrame(packet, itf.macAddress, frame.source)) send(BasePacketFrame(packet, macAddress, frame.source))
true true
} else { } else {
false false
@ -92,79 +92,19 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
} }
} }
// protected abstract fun handlePacket(packet: Packet, itf: Interface) override fun sendPacket(packet: Packet) {
//
// protected open fun acceptsPacket(packet: Packet, itf: Interface): Boolean {
// return when (packet.destination.type) {
// MACAddress.Type.BROADCAST -> true
// MACAddress.Type.UNICAST -> itf.macAddress == packet.destination
// MACAddress.Type.MULTICAST -> acceptsMulticastPacket(packet)
// }
// }
// open fun acceptsMulticastPacket(packet: Packet): Boolean {
// return false
// }
fun sendPacket(packet: Packet) {
sendPacket(packet, null)
}
override fun sendPacket(packet: Packet, itf: Interface?) {
@Suppress("NAME_SHADOWING") var itf = itf
if (itf == null) {
if (interfaces.size == 1) {
itf = interfaces.first()
} else {
throw RuntimeException("Cannot send packet from device with multiple interfaces without explicitly specifying interface")
}
}
val cached = arpTable[packet.destination] val cached = arpTable[packet.destination]
if (cached != null) { if (cached != null) {
itf.send(BasePacketFrame(packet, itf.macAddress, cached)) send(BasePacketFrame(packet, macAddress, cached))
} else { } else {
// packetQueue.add(packet to itf) packetQueue.add(PendingPacket(packet, counter))
packetQueue.add(PendingPacket(packet, itf, counter))
println("$this ($ipAddress) sending ARP query for ${packet.destination}") println("$this ($ipAddress) sending ARP query for ${packet.destination}")
itf.send(ARPQueryFrame(packet.destination, ipAddress, itf.macAddress)) send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
// after sending an ARP query we expect to have received a response and added an entry to our ARP table
// todo: this makes the assumption that packets are sent the entire way synchronously, and then a response
// is immediately sent and forwarded also synchronously
// cached = arpTable[packet.destination]
} }
} }
// fun findMACAddressFor(ipAddress: IPAddress): MACAddress? { open fun findDestination(): Interface? {
// if (arpTable.containsKey(ipAddress)) {
// return arpTable[ipAddress]
// } else {
//
// }
// }
// override fun sendToSingle(packet: Packet) {
// val destinations = NetworkUtil.findDestinations(world!!, pos)
// if (destinations.size != 1) {
// // todo: handle this better
// println("Can't send packet, multiple destinations available: $destinations")
// return
// }
// send(packet))
// }
// override fun sendToAll(packet: Packet) {
// sendToAll(packet, NetworkUtil.findDestinations(world!!, pos))
// }
//
// override fun sendToAll(packet: Packet, destinations: Iterable<PacketSink>) {
// destinations.forEach {
// it.handle(packet)
// }
// }
override fun findDestination(fromItf: Interface): Interface? {
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos) val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
if (sides.size != 1) { if (sides.size != 1) {
throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side") throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
@ -177,12 +117,12 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
counter++ counter++
packetQueue.removeIf { entry -> packetQueue.removeIf { entry ->
val (packet, itf, timestamp) = entry val (packet, timestamp) = entry
if (arpTable.containsKey(packet.destination)) { if (arpTable.containsKey(packet.destination)) {
itf.send(BasePacketFrame(packet, itf.macAddress, arpTable[packet.destination]!!)) send(BasePacketFrame(packet, macAddress, arpTable[packet.destination]!!))
true true
} else if (counter - timestamp >= ARP_RETRY_TIMEOUT) { } else if (counter - timestamp >= ARP_RETRY_TIMEOUT) {
itf.send(ARPQueryFrame(packet.destination, ipAddress, itf.macAddress)) send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
entry.timestamp = counter entry.timestamp = counter
// todo: should there be a retry counter? // todo: should there be a retry counter?
true true
@ -195,31 +135,25 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
override fun toTag(tag: CompoundTag): CompoundTag { override fun toTag(tag: CompoundTag): CompoundTag {
tag.putInt("IPAddress", ipAddress.address) tag.putInt("IPAddress", ipAddress.address)
// tag.putLong("MACAddress", macAddress.address) tag.putLong("MACAddress", macAddress.address)
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
return super.toTag(tag) return super.toTag(tag)
} }
override fun fromTag(state: BlockState, tag: CompoundTag) { override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag) super.fromTag(state, tag)
ipAddress = IPAddress(tag.getInt("IPAddress")) ipAddress = IPAddress(tag.getInt("IPAddress"))
// todo: what happens if the defined number of ports changes between mod versions? macAddress = MACAddress(tag.getLong("MACAddress"))
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
interfaces[i].macAddress = MACAddress(l)
}
} }
override fun toClientTag(tag: CompoundTag): CompoundTag { override fun toClientTag(tag: CompoundTag): CompoundTag {
tag.putInt("IPAddress", ipAddress.address) tag.putInt("IPAddress", ipAddress.address)
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) tag.putLong("MACAddress", macAddress.address)
return tag return tag
} }
override fun fromClientTag(tag: CompoundTag) { override fun fromClientTag(tag: CompoundTag) {
ipAddress = IPAddress(tag.getInt("IPAddress")) ipAddress = IPAddress(tag.getInt("IPAddress"))
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> macAddress = MACAddress(tag.getLong("MACAddress"))
interfaces[i].macAddress = MACAddress(l)
}
} }
fun onBreak() { fun onBreak() {
@ -228,7 +162,6 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
data class PendingPacket( data class PendingPacket(
val packet: Packet, val packet: Packet,
val sourceItf: Interface,
var timestamp: Long, var timestamp: Long,
) )

View File

@ -8,27 +8,23 @@ import net.minecraft.util.Tickable
import net.minecraft.util.math.Direction import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.frame.EthernetFrame import net.shadowfacts.phycon.api.frame.EthernetFrame
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.BaseInterface
import net.shadowfacts.phycon.network.InterfaceDelegate
import net.shadowfacts.phycon.network.NetworkUtil import net.shadowfacts.phycon.network.NetworkUtil
import java.lang.ref.WeakReference
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH), class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
BlockEntityClientSerializable, BlockEntityClientSerializable,
InterfaceDelegate,
Tickable { Tickable {
companion object { companion object {
var SWITCHING_CAPACITY = 256 var SWITCHING_CAPACITY = 256
} }
val interfaces = Direction.values().map { SwitchInterface(it, this) } val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) }
private val macTable = mutableMapOf<MACAddress, Direction>() private val macTable = mutableMapOf<MACAddress, Direction>()
private var packetsHandledThisTick = 0 private var packetsHandledThisTick = 0
@ -69,7 +65,7 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
return interfaces.find { it.side == side }!! return interfaces.find { it.side == side }!!
} }
override fun handle(frame: EthernetFrame, fromItf: Interface) { private fun handle(frame: EthernetFrame, fromItf: Interface) {
val itfSide = (fromItf as SwitchInterface).side val itfSide = (fromItf as SwitchInterface).side
macTable[frame.source] = itfSide macTable[frame.source] = itfSide
@ -90,7 +86,7 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
} }
} }
override fun findDestination(fromItf: Interface): Interface? { private fun findDestination(fromItf: Interface): Interface? {
val side = (fromItf as SwitchInterface).side val side = (fromItf as SwitchInterface).side
return NetworkUtil.findConnectedInterface(world!!, pos, side) return NetworkUtil.findConnectedInterface(world!!, pos, side)
} }
@ -122,8 +118,20 @@ class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
} }
} }
class SwitchInterface(val side: Direction, delegate: InterfaceDelegate): BaseInterface(delegate) { 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)
}
} }
} }

View File

@ -12,7 +12,6 @@ import net.minecraft.util.math.Direction
import net.minecraft.world.BlockView import net.minecraft.world.BlockView
import net.minecraft.world.World import net.minecraft.world.World
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.network.DeviceBlock import net.shadowfacts.phycon.network.DeviceBlock
import java.util.* import java.util.*
@ -33,10 +32,6 @@ class DestBlock: DeviceBlock<DestBlockEntity>(Settings.of(Material.METAL)) {
return EnumSet.allOf(Direction::class.java) return EnumSet.allOf(Direction::class.java)
} }
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
return getBlockEntity(world, pos)!!.interfaces.first()
}
override fun onUse( override fun onUse(
blockState: BlockState?, blockState: BlockState?,
world: World, world: World,

View File

@ -2,10 +2,8 @@ package net.shadowfacts.phycon.network.block.test
import net.minecraft.util.math.Direction import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.frame.EthernetFrame
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.BaseInterface
import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.NetworkUtil import net.shadowfacts.phycon.network.NetworkUtil
@ -14,18 +12,11 @@ import net.shadowfacts.phycon.network.NetworkUtil
*/ */
class DestBlockEntity: DeviceBlockEntity(PhyBlockEntities.DEST) { class DestBlockEntity: DeviceBlockEntity(PhyBlockEntities.DEST) {
override val interfaces = listOf(BaseInterface(this)) override fun handle(packet: Packet) {
override fun handle(packet: Packet, itf: Interface) {
println("$this ($ipAddress) received packet: $packet") println("$this ($ipAddress) received packet: $packet")
} }
override fun handle(frame: EthernetFrame, fromItf: Interface) { override fun findDestination(): Interface? {
// println("dest ${fromItf.macAddress} received frame from ${frame.source}")
super.handle(frame, fromItf)
}
override fun findDestination(fromItf: Interface): Interface? {
for (dir in Direction.values()) { for (dir in Direction.values()) {
val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir) val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir)
if (itf != null) { if (itf != null) {

View File

@ -8,7 +8,6 @@ import net.minecraft.util.math.Direction
import net.minecraft.world.BlockView import net.minecraft.world.BlockView
import net.minecraft.world.World import net.minecraft.world.World
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.network.DeviceBlock import net.shadowfacts.phycon.network.DeviceBlock
import java.util.* import java.util.*
@ -29,8 +28,4 @@ class SourceBlock: DeviceBlock<SourceBlockEntity>(Settings.of(Material.METAL)) {
return EnumSet.allOf(Direction::class.java) return EnumSet.allOf(Direction::class.java)
} }
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
return getBlockEntity(world, pos)!!.interfaces.first()
}
} }

View File

@ -3,41 +3,29 @@ package net.shadowfacts.phycon.network.block.test
import net.minecraft.util.Tickable import net.minecraft.util.Tickable
import net.minecraft.util.math.Direction import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.frame.EthernetFrame
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.BaseInterface
import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.NetworkUtil import net.shadowfacts.phycon.network.NetworkUtil
import net.shadowfacts.phycon.network.frame.BaseFrame
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class SourceBlockEntity: DeviceBlockEntity(PhyBlockEntities.SOURCE), Tickable { class SourceBlockEntity: DeviceBlockEntity(PhyBlockEntities.SOURCE), Tickable {
override val interfaces = listOf(BaseInterface(this)) override fun handle(packet: Packet) {
override fun handle(packet: Packet, itf: Interface) {
TODO("Not yet implemented") TODO("Not yet implemented")
} }
override fun handle(frame: EthernetFrame, fromItf: Interface) {
// println("${fromItf.macAddress} received frame from ${frame.source}")
super.handle(frame, fromItf)
}
// var counter = 0
override fun tick() { override fun tick() {
super.tick() super.tick()
if (!world!!.isClient && counter % 40 == 0L) { if (!world!!.isClient && counter % 40 == 0L) {
sendPacket(TestPacket(ipAddress, IPAddress(67, 237, 255, 168))) sendPacket(TestPacket(ipAddress, IPAddress(170, 171, 101, 168)))
} }
} }
override fun findDestination(fromItf: Interface): Interface? { override fun findDestination(): Interface? {
for (dir in Direction.values()) { for (dir in Direction.values()) {
val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir) val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir)
if (itf != null) { if (itf != null) {