Compare commits

..

No commits in common. "a95621e3f1684fb5e2d9aa4967da0fee6cfbeddf" and "0eabbf9ec1572f81eb05a816ab2407b75a8b7ae6" have entirely different histories.

12 changed files with 56 additions and 177 deletions

View File

@ -1,7 +1,6 @@
package net.shadowfacts.phycon.api; package net.shadowfacts.phycon.api;
import net.shadowfacts.phycon.api.packet.Packet; import net.shadowfacts.phycon.api.packet.Packet;
import net.shadowfacts.phycon.api.util.MACAddress;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
@ -9,9 +8,6 @@ import org.jetbrains.annotations.NotNull;
*/ */
public interface PacketSink { public interface PacketSink {
@NotNull
MACAddress getMACAddress();
void handle(@NotNull Packet packet); void handle(@NotNull Packet packet);
} }

View File

@ -48,7 +48,7 @@ public final class MACAddress {
public Type getType() { public Type getType() {
if (this == BROADCAST) { if (this == BROADCAST) {
return Type.BROADCAST; return Type.BROADCAST;
} else if (((address >> 40) & 1) == 1) { } else if (((address >> 46) & 1) == 1) {
return Type.MULTICAST; return Type.MULTICAST;
} else { } else {
return Type.UNICAST; return Type.UNICAST;

View File

@ -5,10 +5,8 @@ import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType import net.minecraft.block.entity.BlockEntityType
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.networkinterface.NetworkInterfaceBlock
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity import net.shadowfacts.phycon.network.block.networkinterface.NetworkInterfaceBlockEntity
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
@ -17,18 +15,16 @@ import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
*/ */
object PhyBlockEntities { object PhyBlockEntities {
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE) val NETWORK_INTERFACE = create(::NetworkInterfaceBlockEntity, PhyBlocks.NETWORK_INTERFACE)
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL) val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> { private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
return BlockEntityType.Builder.create(builder, arrayOf(block)).build(null) return BlockEntityType.Builder.create(builder, arrayOf(block)).build(null)
} }
fun init() { fun init() {
register(InterfaceBlock.ID, INTERFACE) register(NetworkInterfaceBlock.ID, NETWORK_INTERFACE)
register(TerminalBlock.ID, TERMINAL) register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH)
} }
private fun register(id: Identifier, type: BlockEntityType<*>) { private fun register(id: Identifier, type: BlockEntityType<*>) {

View File

@ -3,8 +3,7 @@ package net.shadowfacts.phycon.init
import net.minecraft.block.Block import net.minecraft.block.Block
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.networkinterface.NetworkInterfaceBlock
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
/** /**
@ -12,14 +11,12 @@ import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
*/ */
object PhyBlocks { object PhyBlocks {
val INTERFACE = InterfaceBlock() val NETWORK_INTERFACE = NetworkInterfaceBlock()
val TERMINAL = TerminalBlock() val TERMINAL = TerminalBlock()
val SWITCH = SwitchBlock()
fun init() { fun init() {
register(InterfaceBlock.ID, INTERFACE) register(NetworkInterfaceBlock.ID, NETWORK_INTERFACE)
register(TerminalBlock.ID, TERMINAL) register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH)
} }
private fun register(id: Identifier, block: Block) { private fun register(id: Identifier, block: Block) {

View File

@ -4,8 +4,7 @@ import net.minecraft.item.BlockItem
import net.minecraft.item.Item import net.minecraft.item.Item
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.networkinterface.NetworkInterfaceBlock
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
/** /**
@ -13,14 +12,12 @@ import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
*/ */
object PhyItems { object PhyItems {
val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings()) val NETWORK_INTERFACE = BlockItem(PhyBlocks.NETWORK_INTERFACE, Item.Settings())
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings()) val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
fun init() { fun init() {
register(InterfaceBlock.ID, INTERFACE) register(NetworkInterfaceBlock.ID, NETWORK_INTERFACE)
register(TerminalBlock.ID, TERMINAL) register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH)
} }
private fun register(id: Identifier, item: Item) { private fun register(id: Identifier, item: Item) {

View File

@ -7,7 +7,6 @@ import net.minecraft.util.Tickable
import net.shadowfacts.phycon.api.PacketSink import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.MACAddress
import java.lang.ref.WeakReference
import java.util.* import java.util.*
/** /**
@ -18,11 +17,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), T
var macAddress = MACAddress.random() var macAddress = MACAddress.random()
protected set protected set
private val sendQueue = LinkedList<Pair<Packet, WeakReference<PacketSink>>>() private val sendQueue = LinkedList<Packet>()
override fun getMACAddress(): MACAddress {
return macAddress
}
override fun handle(packet: Packet) { override fun handle(packet: Packet) {
if (acceptsPacket(packet)) { if (acceptsPacket(packet)) {
@ -30,7 +25,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), T
} }
} }
protected abstract fun handlePacket(packet: Packet) abstract fun handlePacket(packet: Packet)
fun acceptsPacket(packet: Packet): Boolean { fun acceptsPacket(packet: Packet): Boolean {
return when (packet.destination.type) { return when (packet.destination.type) {
@ -40,37 +35,21 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), T
} }
} }
open fun acceptsMulticastPacket(packet: Packet): Boolean { fun acceptsMulticastPacket(packet: Packet): Boolean {
return false return false
} }
fun enqueue(packet: Packet, destination: PacketSink) { fun enqueue(packet: Packet) {
sendQueue.add(packet to WeakReference(destination)) sendQueue.add(packet)
}
// 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() { override fun tick() {
if (sendQueue.isNotEmpty()) { if (sendQueue.isNotEmpty()) {
val (packet, destination) = sendQueue.pop() val packet = sendQueue.pop()
destination.get()?.handle(packet) val destinations = NetworkUtil.findDestinations(world!!, pos)
destinations.forEach {
it.handle(packet)
}
} }
} }

View File

@ -13,35 +13,26 @@ import java.util.*
*/ */
object NetworkUtil { object NetworkUtil {
fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List<PacketSink> { fun findDestinations(world: World, startPos: BlockPos): List<PacketSink> {
val results = LinkedList<PacketSink>() val results = mutableListOf<PacketSink>()
val visited = hashSetOf(startPos) val visited = hashSetOf(startPos)
val queue = LinkedList<BlockPos>() val queue = LinkedList<BlockPos>()
if (direction != null) { addAdjacent(queue, visited, startPos)
queue.add(startPos.offset(direction))
} else {
addAdjacent(queue, visited, startPos)
}
while (queue.isNotEmpty()) { while (queue.isNotEmpty()) {
val pos = queue.pop() val pos = queue.pop()
val sink = PhyAttributes.PACKET_SINK.getFirstOrNull(world, pos) val sink = PhyAttributes.PACKET_SINK.getFirstOrNull(world, pos)
if (sink != null) { if (sink != null) {
results.add(sink) results.add(sink)
} }
if (pos === startPos || world.getBlockState(pos).block is NetworkCable) {
if (world.getBlockState(pos).block is NetworkCable) {
addAdjacent(queue, visited, pos) addAdjacent(queue, visited, pos)
} }
visited.add(pos) visited.add(pos)
} }
return results return results
} }
private fun addAdjacent(queue: MutableList<BlockPos>, visited: Set<BlockPos>, pos: BlockPos) { fun addAdjacent(queue: MutableList<BlockPos>, visited: Set<BlockPos>, pos: BlockPos) {
for (dir in Direction.values()) { for (dir in Direction.values()) {
val newPos = pos.offset(dir) val newPos = pos.offset(dir)
if (newPos !in visited) { if (newPos !in visited) {

View File

@ -1,27 +0,0 @@
package net.shadowfacts.phycon.network.block.netswitch
import alexiil.mc.lib.attributes.AttributeList
import alexiil.mc.lib.attributes.AttributeProvider
import net.minecraft.block.BlockState
import net.minecraft.block.Material
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.BlockWithEntity
/**
* @author shadowfacts
*/
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)), AttributeProvider {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "switch")
}
override fun createBlockEntity(world: BlockView) = SwitchBlockEntity()
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
to.offer(getBlockEntity(world, pos))
}
}

View File

@ -1,62 +0,0 @@
package net.shadowfacts.phycon.network.block.netswitch
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.NetworkUtil
import java.lang.RuntimeException
import javax.print.attribute.standard.Destination
/**
* @author shadowfacts
*/
class SwitchBlockEntity: DeviceBlockEntity(PhyBlockEntities.SWITCH) {
private val macTable = mutableMapOf<MACAddress, Direction>()
override fun handlePacket(packet: Packet) {
throw RuntimeException("Unreachable")
}
override fun handle(packet: Packet) {
if (packet.destination == MACAddress.BROADCAST) {
val allDestinations = NetworkUtil.findDestinations(world!!, pos).filter { it.macAddress != packet.source }
enqueueToAll(packet, allDestinations)
} else {
val direction = macTable[packet.destination]
if (direction != null) {
val dest = findDestination(direction)
if (dest != null && packet.destination == dest.macAddress) {
enqueue(packet, dest)
return
}
}
flood(packet)
}
}
private fun findDestination(direction: Direction): PacketSink? {
val allDestinations = NetworkUtil.findDestinations(world!!, pos, direction)
if (allDestinations.size > 1) {
// todo: do this better
println("Can't send packet, multiple destinations: $allDestinations")
return null
}
return allDestinations.firstOrNull()
}
private fun flood(packet: Packet) {
for (dir in Direction.values()) {
val dest = findDestination(dir)
if (dest != null && packet.destination == dest.macAddress) {
macTable[packet.destination] = dir
enqueue(packet, dest)
break
}
}
}
}

View File

@ -1,4 +1,4 @@
package net.shadowfacts.phycon.network.block.netinterface package net.shadowfacts.phycon.network.block.networkinterface
import alexiil.mc.lib.attributes.AttributeList import alexiil.mc.lib.attributes.AttributeList
import alexiil.mc.lib.attributes.AttributeProvider import alexiil.mc.lib.attributes.AttributeProvider
@ -6,11 +6,14 @@ import net.minecraft.block.Block
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.Material import net.minecraft.block.Material
import net.minecraft.entity.LivingEntity import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemPlacementContext import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.state.StateFactory import net.minecraft.state.StateFactory
import net.minecraft.state.property.Properties import net.minecraft.state.property.Properties
import net.minecraft.util.Hand
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.BlockView import net.minecraft.world.BlockView
import net.minecraft.world.World import net.minecraft.world.World
@ -20,7 +23,7 @@ import net.shadowfacts.phycon.block.BlockWithEntity
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material.METAL)), AttributeProvider { class NetworkInterfaceBlock: BlockWithEntity<NetworkInterfaceBlockEntity>(Settings.of(Material.METAL)), AttributeProvider {
companion object { companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "network_interface") val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
val FACING = Properties.FACING val FACING = Properties.FACING
@ -31,7 +34,7 @@ class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material
builder.add(FACING) builder.add(FACING)
} }
override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity() override fun createBlockEntity(world: BlockView) = NetworkInterfaceBlockEntity()
override fun getPlacementState(context: ItemPlacementContext): BlockState { override fun getPlacementState(context: ItemPlacementContext): BlockState {
val facing = if (context.player?.isSneaking == true) context.playerFacing else context.playerFacing.opposite val facing = if (context.player?.isSneaking == true) context.playerFacing else context.playerFacing.opposite
@ -50,6 +53,13 @@ class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material
} }
} }
override fun activate(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, result: BlockHitResult): Boolean {
if (!world.isClient) {
getBlockEntity(world, pos)!!.printContents()
}
return true
}
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
to.offer(getBlockEntity(world, pos)) to.offer(getBlockEntity(world, pos))
} }

View File

@ -1,4 +1,4 @@
package net.shadowfacts.phycon.network.block.netinterface package net.shadowfacts.phycon.network.block.networkinterface
import alexiil.mc.lib.attributes.SearchOptions import alexiil.mc.lib.attributes.SearchOptions
import alexiil.mc.lib.attributes.item.GroupedItemInv import alexiil.mc.lib.attributes.item.GroupedItemInv
@ -14,12 +14,11 @@ import net.shadowfacts.phycon.network.packet.RequestReadAllPacket
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE) { class NetworkInterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.NETWORK_INTERFACE) {
private val facing: Direction private val facing: Direction
get() = world!!.getBlockState(pos)[InterfaceBlock.FACING] get() = world!!.getBlockState(pos)[NetworkInterfaceBlock.FACING]
// todo: should this be a weak ref?
private var inventory: GroupedItemInv? = null private var inventory: GroupedItemInv? = null
fun updateInventory() { fun updateInventory() {
@ -28,6 +27,14 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE) {
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option) inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option)
} }
fun printContents() {
inventory?.also { inv ->
inv.storedStacks.forEach {
println(it)
}
}
}
override fun handlePacket(packet: Packet) { override fun handlePacket(packet: Packet) {
when (packet) { when (packet) {
is RequestReadAllPacket -> handleReadAll(packet) is RequestReadAllPacket -> handleReadAll(packet)
@ -35,14 +42,10 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE) {
} }
fun handleReadAll(packet: RequestReadAllPacket) { fun handleReadAll(packet: RequestReadAllPacket) {
enqueueToSingle(ReadAllPacket(readAll(), macAddress, packet.source)) enqueue(ReadAllPacket(readAll(), macAddress, packet.source))
} }
fun readAll(): Map<ItemStack, Int> { fun readAll(): Map<ItemStack, Int> {
// if we don't have an inventory, try to get one
// this happens when readAll is called before a neighbor state changes, such as immediately after world load
if (inventory == null) updateInventory()
return inventory?.let { return inventory?.let {
it.storedStacks.associateWith(it::getAmount) it.storedStacks.associateWith(it::getAmount)
} ?: mapOf() } ?: mapOf()

View File

@ -1,6 +1,5 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
import alexiil.mc.lib.attributes.item.ItemStackCollections
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
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
@ -13,7 +12,7 @@ import net.shadowfacts.phycon.network.packet.RequestReadAllPacket
*/ */
class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL) { class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL) {
private var cachedItems = ItemStackCollections.intMap() private var cachedItems = mutableMapOf<ItemStack, Int>()
override fun handlePacket(packet: Packet) { override fun handlePacket(packet: Packet) {
when (packet) { when (packet) {
@ -23,7 +22,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL) {
fun handleReadAll(packet: ReadAllPacket) { fun handleReadAll(packet: ReadAllPacket) {
packet.items.forEach { (stack, amount) -> packet.items.forEach { (stack, amount) ->
cachedItems.mergeInt(stack, amount) { a, b -> a + b } cachedItems.merge(stack, amount) { a, b -> a + b }
} }
println("new cached items: $cachedItems") println("new cached items: $cachedItems")
} }
@ -31,7 +30,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL) {
fun onActivate() { fun onActivate() {
if (!world!!.isClient) { if (!world!!.isClient) {
cachedItems.clear() cachedItems.clear()
enqueueToSingle(RequestReadAllPacket(macAddress)) enqueue(RequestReadAllPacket(macAddress))
} }
} }