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

93 lines
2.4 KiB
Kotlin

package net.shadowfacts.phycon.network
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.nbt.CompoundTag
import net.minecraft.util.Tickable
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.packet.DeviceRemovedPacket
import java.lang.ref.WeakReference
import java.util.*
/**
* @author shadowfacts
*/
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), Tickable, PacketSink {
var macAddress = MACAddress.random()
protected set
private val sendQueue = LinkedList<Pair<Packet, WeakReference<PacketSink>>>()
override fun getMACAddress(): MACAddress {
return macAddress
}
override fun handle(packet: Packet) {
if (acceptsPacket(packet)) {
handlePacket(packet)
}
}
protected abstract fun handlePacket(packet: Packet)
fun acceptsPacket(packet: Packet): Boolean {
return when (packet.destination.type) {
MACAddress.Type.BROADCAST -> true
MACAddress.Type.UNICAST -> macAddress == packet.destination
MACAddress.Type.MULTICAST -> acceptsMulticastPacket(packet)
}
}
open fun acceptsMulticastPacket(packet: Packet): Boolean {
return false
}
fun enqueue(packet: Packet, destination: PacketSink) {
sendQueue.add(packet to WeakReference(destination))
}
// todo: better name for this
fun enqueueToSingle(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
}
enqueue(packet, destinations.first())
}
fun enqueueToAll(packet: Packet) {
enqueueToAll(packet, NetworkUtil.findDestinations(world!!, pos))
}
fun enqueueToAll(packet: Packet, destinations: Iterable<PacketSink>) {
sendQueue.addAll(destinations.map { packet to WeakReference(it) })
}
override fun tick() {
if (sendQueue.isNotEmpty()) {
val (packet, destination) = sendQueue.pop()
destination.get()?.handle(packet)
}
}
override fun toTag(tag: CompoundTag): CompoundTag {
tag.putLong("MACAddress", macAddress.address)
return super.toTag(tag)
}
override fun fromTag(tag: CompoundTag) {
super.fromTag(tag)
macAddress = MACAddress(tag.getLong("MACAddress"))
}
fun onBreak() {
enqueueToAll(DeviceRemovedPacket(this))
}
}