diff --git a/src/main/java/net/shadowfacts/phycon/api/Interface.java b/src/main/java/net/shadowfacts/phycon/api/Interface.java new file mode 100644 index 0000000..6ff71be --- /dev/null +++ b/src/main/java/net/shadowfacts/phycon/api/Interface.java @@ -0,0 +1,22 @@ +package net.shadowfacts.phycon.api; + +import net.shadowfacts.phycon.api.frame.EthernetFrame; +import net.shadowfacts.phycon.api.packet.Packet; +import net.shadowfacts.phycon.api.util.MACAddress; +import org.jetbrains.annotations.NotNull; + +/** + * @author shadowfacts + */ +public interface Interface { + + @NotNull + MACAddress getMACAddress(); + + void receive(@NotNull EthernetFrame frame); + + void send(@NotNull EthernetFrame frame); + +// void send(@NotNull Packet packet); + +} diff --git a/src/main/java/net/shadowfacts/phycon/api/NetworkCable.java b/src/main/java/net/shadowfacts/phycon/api/NetworkCableBlock.java similarity index 51% rename from src/main/java/net/shadowfacts/phycon/api/NetworkCable.java rename to src/main/java/net/shadowfacts/phycon/api/NetworkCableBlock.java index 96521e4..203909c 100644 --- a/src/main/java/net/shadowfacts/phycon/api/NetworkCable.java +++ b/src/main/java/net/shadowfacts/phycon/api/NetworkCableBlock.java @@ -3,6 +3,6 @@ package net.shadowfacts.phycon.api; /** * @author shadowfacts */ -public interface NetworkCable extends NetworkComponent { +public interface NetworkCableBlock extends NetworkComponentBlock { } diff --git a/src/main/java/net/shadowfacts/phycon/api/NetworkComponent.java b/src/main/java/net/shadowfacts/phycon/api/NetworkComponent.java deleted file mode 100644 index bfacdf7..0000000 --- a/src/main/java/net/shadowfacts/phycon/api/NetworkComponent.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.shadowfacts.phycon.api; - -import net.minecraft.block.BlockState; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - -import java.util.Collection; - -/** - * @author shadowfacts - */ -public interface NetworkComponent { - - Collection getNetworkConnectedSides(BlockState state, World world, BlockPos pos); - -} diff --git a/src/main/java/net/shadowfacts/phycon/api/NetworkComponentBlock.java b/src/main/java/net/shadowfacts/phycon/api/NetworkComponentBlock.java new file mode 100644 index 0000000..b9f2412 --- /dev/null +++ b/src/main/java/net/shadowfacts/phycon/api/NetworkComponentBlock.java @@ -0,0 +1,23 @@ +package net.shadowfacts.phycon.api; + +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * @author shadowfacts + */ +public interface NetworkComponentBlock { + + @NotNull + Collection getNetworkConnectedSides(@NotNull BlockState state, @NotNull World world, @NotNull BlockPos pos); + + @Nullable + Interface getNetworkInterfaceForSide(@NotNull Direction side, @NotNull BlockState state, @NotNull World world, @NotNull BlockPos pos); + +} diff --git a/src/main/java/net/shadowfacts/phycon/api/NetworkDevice.java b/src/main/java/net/shadowfacts/phycon/api/NetworkDevice.java new file mode 100644 index 0000000..07eaad2 --- /dev/null +++ b/src/main/java/net/shadowfacts/phycon/api/NetworkDevice.java @@ -0,0 +1,23 @@ +package net.shadowfacts.phycon.api; + +import net.shadowfacts.phycon.api.util.IPAddress; +import org.jetbrains.annotations.NotNull; + +/** + * @author shadowfacts + */ +public interface NetworkDevice { + + /** + * The IP address of this device. + * + * If a device has not been assigned an address by a DHCP server, it may self-assign a randomly generated one. + * + * The address of a network device should never be the broadcast address. + * + * @return The IP address of this device. + */ + @NotNull + IPAddress getIPAddress(); + +} diff --git a/src/main/java/net/shadowfacts/phycon/api/NetworkInterface.java b/src/main/java/net/shadowfacts/phycon/api/NetworkInterface.java deleted file mode 100644 index a5c0529..0000000 --- a/src/main/java/net/shadowfacts/phycon/api/NetworkInterface.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.shadowfacts.phycon.api; - -import net.minecraft.item.ItemStack; - -import java.util.Map; - -/** - * @author shadowfacts - */ -public interface NetworkInterface extends PacketSink { - - Map readAll(); - -} diff --git a/src/main/java/net/shadowfacts/phycon/api/PacketSink.java b/src/main/java/net/shadowfacts/phycon/api/PacketSink.java index a8840ef..b8ce2f1 100644 --- a/src/main/java/net/shadowfacts/phycon/api/PacketSink.java +++ b/src/main/java/net/shadowfacts/phycon/api/PacketSink.java @@ -1,17 +1,16 @@ package net.shadowfacts.phycon.api; import net.shadowfacts.phycon.api.packet.Packet; -import net.shadowfacts.phycon.api.util.MACAddress; import org.jetbrains.annotations.NotNull; /** * @author shadowfacts */ -public interface PacketSink { +public interface PacketSink extends NetworkDevice { @NotNull - MACAddress getMACAddress(); + Iterable getDeviceInterfaces(); - void handle(@NotNull Packet packet); + void handle(@NotNull Packet packet, @NotNull Interface itf); } diff --git a/src/main/java/net/shadowfacts/phycon/api/PacketSource.java b/src/main/java/net/shadowfacts/phycon/api/PacketSource.java index 7b6eed1..c7a8d0d 100644 --- a/src/main/java/net/shadowfacts/phycon/api/PacketSource.java +++ b/src/main/java/net/shadowfacts/phycon/api/PacketSource.java @@ -1,15 +1,18 @@ package net.shadowfacts.phycon.api; import net.shadowfacts.phycon.api.packet.Packet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author shadowfacts */ -public interface PacketSource { +// todo: does PacketSource actually need to extend NetworkDevice? +public interface PacketSource extends NetworkDevice { // todo: better name for this - void sendToSingle(Packet packet); + void sendPacket(@NotNull Packet packet, @Nullable Interface itf); - void sendToAll(Packet packet); - - void sendToAll(Packet packet, Iterable destinations); +// void sendToAll(@NotNull Packet packet); +// +// void sendToAll(@NotNull Packet packet, @NotNull Iterable destinations); } diff --git a/src/main/java/net/shadowfacts/phycon/api/PhyAttributes.java b/src/main/java/net/shadowfacts/phycon/api/PhyAttributes.java index 5cd009a..4b960bb 100644 --- a/src/main/java/net/shadowfacts/phycon/api/PhyAttributes.java +++ b/src/main/java/net/shadowfacts/phycon/api/PhyAttributes.java @@ -9,6 +9,5 @@ import alexiil.mc.lib.attributes.Attributes; public class PhyAttributes { public static final Attribute PACKET_SINK = Attributes.create(PacketSink.class); - public static final Attribute NETWORK_INTERFACE = Attributes.create(NetworkInterface.class); } diff --git a/src/main/java/net/shadowfacts/phycon/api/frame/EthernetFrame.java b/src/main/java/net/shadowfacts/phycon/api/frame/EthernetFrame.java new file mode 100644 index 0000000..1f1c20c --- /dev/null +++ b/src/main/java/net/shadowfacts/phycon/api/frame/EthernetFrame.java @@ -0,0 +1,17 @@ +package net.shadowfacts.phycon.api.frame; + +import net.shadowfacts.phycon.api.util.MACAddress; +import org.jetbrains.annotations.NotNull; + +/** + * @author shadowfacts + */ +public interface EthernetFrame { + + @NotNull + MACAddress getSource(); + + @NotNull + MACAddress getDestination(); + +} diff --git a/src/main/java/net/shadowfacts/phycon/api/frame/PacketFrame.java b/src/main/java/net/shadowfacts/phycon/api/frame/PacketFrame.java new file mode 100644 index 0000000..71cf8da --- /dev/null +++ b/src/main/java/net/shadowfacts/phycon/api/frame/PacketFrame.java @@ -0,0 +1,14 @@ +package net.shadowfacts.phycon.api.frame; + +import net.shadowfacts.phycon.api.packet.Packet; +import org.jetbrains.annotations.NotNull; + +/** + * @author shadowfacts + */ +public interface PacketFrame extends EthernetFrame { + + @NotNull + Packet getPacket(); + +} diff --git a/src/main/java/net/shadowfacts/phycon/api/packet/Packet.java b/src/main/java/net/shadowfacts/phycon/api/packet/Packet.java index fb89376..4fd7dff 100644 --- a/src/main/java/net/shadowfacts/phycon/api/packet/Packet.java +++ b/src/main/java/net/shadowfacts/phycon/api/packet/Packet.java @@ -1,6 +1,6 @@ package net.shadowfacts.phycon.api.packet; -import net.shadowfacts.phycon.api.util.MACAddress; +import net.shadowfacts.phycon.api.util.IPAddress; import org.jetbrains.annotations.NotNull; /** @@ -9,9 +9,9 @@ import org.jetbrains.annotations.NotNull; public interface Packet { @NotNull - MACAddress getSource(); + IPAddress getSource(); @NotNull - MACAddress getDestination(); + IPAddress getDestination(); } diff --git a/src/main/java/net/shadowfacts/phycon/api/util/IPAddress.java b/src/main/java/net/shadowfacts/phycon/api/util/IPAddress.java new file mode 100644 index 0000000..737b239 --- /dev/null +++ b/src/main/java/net/shadowfacts/phycon/api/util/IPAddress.java @@ -0,0 +1,75 @@ +package net.shadowfacts.phycon.api.util; + +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +/** + * @author shadowfacts + */ +public final class IPAddress { + + @NotNull + public static IPAddress random(@NotNull Random random) { + int value = 0; + // don't accidentally generate reserved, broadcast, or loopback addresses + while (value == 0 || value == 0xff_ff_ff_ff || (value >> 24) == 127) { + value = random.nextInt(); + } + return new IPAddress(value); + } + + private static final Random ipAddressRandom = new Random(); + @NotNull + public static IPAddress random() { + return random(ipAddressRandom); + } + + public static final IPAddress BROADCAST = new IPAddress(0xff_ff_ff_ff); + + public final int address; + + public IPAddress(int address) { + if (address == 0) { + throw new RuntimeException("IP address 0.0.0.0 is reserved"); + } + this.address = address; + } + + public IPAddress(int a, int b, int c, int d) { + this(((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff)); + } + + /** + * @return If this IP address is a broadcast address (255.255.255.255). + */ + public boolean isBroadcast() { + return address == 0xff_ff_ff_ff; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + IPAddress ipAddress = (IPAddress) o; + return address == ipAddress.address; + } + + @Override + public int hashCode() { + return address; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int i = 3; i >= 0; i--) { + if (i < 3) { + builder.append('.'); + } + int octet = (address >> (i * 8)) & 0xff; + builder.append(octet); + } + return builder.toString(); + } +} diff --git a/src/main/java/net/shadowfacts/phycon/api/util/MACAddress.java b/src/main/java/net/shadowfacts/phycon/api/util/MACAddress.java index c4be10e..92096b7 100644 --- a/src/main/java/net/shadowfacts/phycon/api/util/MACAddress.java +++ b/src/main/java/net/shadowfacts/phycon/api/util/MACAddress.java @@ -15,12 +15,14 @@ public final class MACAddress { public static final MACAddress BROADCAST = new MACAddress(0xffffffffffffL); + @NotNull public static MACAddress random(Random random) { long value = random.nextLong() & 0xfeffffffffffL; return new MACAddress(value); } private static final Random macAddressRandom = new Random(); + @NotNull public static MACAddress random() { return random(macAddressRandom); } diff --git a/src/main/java/net/shadowfacts/phycon/mixin/client/MixinHandledScreen.java b/src/main/java/net/shadowfacts/phycon/mixin/client/MixinHandledScreen.java index 8adf475..55c278f 100644 --- a/src/main/java/net/shadowfacts/phycon/mixin/client/MixinHandledScreen.java +++ b/src/main/java/net/shadowfacts/phycon/mixin/client/MixinHandledScreen.java @@ -3,7 +3,7 @@ package net.shadowfacts.phycon.mixin.client; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.screen.slot.Slot; -import net.shadowfacts.phycon.network.block.terminal.TerminalScreen; +//import net.shadowfacts.phycon.network.block.terminal.TerminalScreen; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -17,10 +17,10 @@ public class MixinHandledScreen { @Inject(method = "drawSlot(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/screen/slot/Slot;)V", at = @At(value = "INVOKE", target = "enableDepthTest()V")) private void drawSlot(MatrixStack matrixStack, Slot slot, CallbackInfo ci) { - if ((Object)this instanceof TerminalScreen) { - TerminalScreen self = (TerminalScreen)(Object)this; - self.drawSlotUnderlay(matrixStack, slot); - } +// if ((Object)this instanceof TerminalScreen) { +// TerminalScreen self = (TerminalScreen)(Object)this; +// self.drawSlotUnderlay(matrixStack, slot); +// } } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivityClient.kt b/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivityClient.kt index 4575fbb..6785b47 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivityClient.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivityClient.kt @@ -6,7 +6,7 @@ import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry import net.minecraft.client.render.RenderLayer import net.shadowfacts.phycon.init.PhyBlocks import net.shadowfacts.phycon.init.PhyScreens -import net.shadowfacts.phycon.network.block.terminal.TerminalScreen +//import net.shadowfacts.phycon.network.block.terminal.TerminalScreen /** * @author shadowfacts @@ -15,6 +15,6 @@ object PhysicalConnectivityClient: ClientModInitializer { override fun onInitializeClient() { BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent()) - ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen) +// ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen) } } diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt index 4ed2be9..117eb52 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlockEntities.kt @@ -5,30 +5,39 @@ import net.minecraft.block.entity.BlockEntity import net.minecraft.block.entity.BlockEntityType import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry -import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock -import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity 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.TerminalBlockEntity +import net.shadowfacts.phycon.network.block.test.DestBlock +import net.shadowfacts.phycon.network.block.test.DestBlockEntity +import net.shadowfacts.phycon.network.block.test.SourceBlock +import net.shadowfacts.phycon.network.block.test.SourceBlockEntity + +//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock +//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity +//import net.shadowfacts.phycon.network.block.terminal.TerminalBlock +//import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity /** * @author shadowfacts */ object PhyBlockEntities { - val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE) - val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL) +// val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE) +// val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL) val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH) + val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE) + val DEST = create(::DestBlockEntity, PhyBlocks.DEST) private fun create(builder: () -> T, block: Block): BlockEntityType { - return BlockEntityType.Builder.create(builder, arrayOf(block)).build(null) + return BlockEntityType.Builder.create(builder, block).build(null) } fun init() { - register(InterfaceBlock.ID, INTERFACE) - register(TerminalBlock.ID, TERMINAL) +// register(InterfaceBlock.ID, INTERFACE) +// register(TerminalBlock.ID, TERMINAL) register(SwitchBlock.ID, SWITCH) + register(SourceBlock.ID, SOURCE) + register(DestBlock.ID, DEST) } private fun register(id: Identifier, type: BlockEntityType<*>) { diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt index 542ea7a..22bede0 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyBlocks.kt @@ -4,25 +4,29 @@ import net.minecraft.block.Block import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import net.shadowfacts.phycon.network.block.cable.CableBlock -import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock -import net.shadowfacts.phycon.network.block.terminal.TerminalBlock +import net.shadowfacts.phycon.network.block.test.DestBlock +import net.shadowfacts.phycon.network.block.test.SourceBlock /** * @author shadowfacts */ object PhyBlocks { - val INTERFACE = InterfaceBlock() - val TERMINAL = TerminalBlock() +// val INTERFACE = InterfaceBlock() +// val TERMINAL = TerminalBlock() val SWITCH = SwitchBlock() val CABLE = CableBlock() + val SOURCE = SourceBlock() + val DEST = DestBlock() fun init() { - register(InterfaceBlock.ID, INTERFACE) - register(TerminalBlock.ID, TERMINAL) +// register(InterfaceBlock.ID, INTERFACE) +// register(TerminalBlock.ID, TERMINAL) register(SwitchBlock.ID, SWITCH) register(CableBlock.ID, CABLE) + register(SourceBlock.ID, SOURCE) + register(DestBlock.ID, DEST) } private fun register(id: Identifier, block: Block) { diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt index c25c1c7..d6254a3 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyItems.kt @@ -6,27 +6,34 @@ import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import net.shadowfacts.phycon.item.ScrewdriverItem import net.shadowfacts.phycon.network.block.cable.CableBlock -import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock -import net.shadowfacts.phycon.network.block.terminal.TerminalBlock +import net.shadowfacts.phycon.network.block.test.DestBlock +import net.shadowfacts.phycon.network.block.test.SourceBlock + +//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock +//import net.shadowfacts.phycon.network.block.terminal.TerminalBlock /** * @author shadowfacts */ object PhyItems { - val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings()) - val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings()) +// val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings()) +// val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings()) val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings()) val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings()) + val SOURCE = BlockItem(PhyBlocks.SOURCE, Item.Settings()) + val DEST = BlockItem(PhyBlocks.DEST , Item.Settings()) val SCREWDRIVER = ScrewdriverItem() fun init() { - register(InterfaceBlock.ID, INTERFACE) - register(TerminalBlock.ID, TERMINAL) +// register(InterfaceBlock.ID, INTERFACE) +// register(TerminalBlock.ID, TERMINAL) register(SwitchBlock.ID, SWITCH) register(CableBlock.ID, CABLE) + register(SourceBlock.ID, SOURCE) + register(DestBlock.ID, DEST) register(ScrewdriverItem.ID, SCREWDRIVER) } diff --git a/src/main/kotlin/net/shadowfacts/phycon/init/PhyScreens.kt b/src/main/kotlin/net/shadowfacts/phycon/init/PhyScreens.kt index dfe3172..e6c2e51 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/init/PhyScreens.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/init/PhyScreens.kt @@ -3,10 +3,10 @@ package net.shadowfacts.phycon.init import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry import net.minecraft.util.Identifier import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler +//import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler object PhyScreens { - val TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler) +// val TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler) } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/BaseInterface.kt b/src/main/kotlin/net/shadowfacts/phycon/network/BaseInterface.kt new file mode 100644 index 0000000..b1f5a53 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/BaseInterface.kt @@ -0,0 +1,53 @@ +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 +): 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) +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt index ee624ce..f9af942 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlock.kt @@ -4,12 +4,13 @@ import net.minecraft.block.BlockState import net.minecraft.entity.player.PlayerEntity import net.minecraft.util.math.BlockPos import net.minecraft.world.World +import net.shadowfacts.phycon.api.NetworkComponentBlock import net.shadowfacts.phycon.block.BlockWithEntity /** * @author shadowfacts */ -abstract class DeviceBlock(settings: Settings): BlockWithEntity(settings) { +abstract class DeviceBlock(settings: Settings): BlockWithEntity(settings), NetworkComponentBlock { override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) { super.onBreak(world, pos, state, player) diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt index 2e61680..f36720a 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/DeviceBlockEntity.kt @@ -1,83 +1,235 @@ package net.shadowfacts.phycon.network +import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable import net.minecraft.block.BlockState 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.PacketSource +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 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.network.frame.ARPQueryFrame +import net.shadowfacts.phycon.network.frame.ARPResponseFrame +import net.shadowfacts.phycon.network.frame.BasePacketFrame import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket +import java.lang.RuntimeException +import java.util.* /** * @author shadowfacts */ -abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), PacketSink, PacketSource { +abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), + BlockEntityClientSerializable, + Tickable, + PacketSink, + PacketSource, + InterfaceDelegate { - var macAddress = MACAddress.random() + companion object { + private const val ARP_RETRY_TIMEOUT = 200 + } + +// var macAddress: MACAddress = MACAddress.random() +// protected set + + var ipAddress: IPAddress = IPAddress.random() protected set - override fun getMACAddress(): MACAddress { - return macAddress - } + open val interfaces: List = listOf() +// abstract val itf: BaseInterface - override fun handle(packet: Packet) { - if (acceptsPacket(packet)) { - handlePacket(packet) + private val arpTable = mutableMapOf() + private val packetQueue = LinkedList() + + protected var counter: Long = 0 + + override fun getIPAddress() = ipAddress + + override fun getDeviceInterfaces() = interfaces + + abstract override fun handle(packet: Packet, itf: Interface) + + override fun handle(frame: EthernetFrame, fromItf: Interface) { + println("$this ($ipAddress, ${fromItf.macAddress}) received frame from ${frame.source}: $frame") + when (frame) { + is ARPQueryFrame -> handleARPQuery(frame, fromItf) + is ARPResponseFrame -> handleARPResponse(frame, fromItf) + is PacketFrame -> { + if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) { + handle(frame.packet, fromItf) + } + } } } - protected abstract fun handlePacket(packet: Packet) - - protected open 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) + private fun handleARPQuery(frame: ARPQueryFrame, fromItf: Interface) { + println("$this ($ipAddress) received ARP query for ${frame.queryIP}") + arpTable[frame.sourceIP] = frame.source + if (frame.queryIP == ipAddress) { + println("$this ($ipAddress) sending ARP response to ${frame.source} with ${fromItf.macAddress}") + fromItf.send(ARPResponseFrame(ipAddress, fromItf.macAddress, frame.source)) } } - open fun acceptsMulticastPacket(packet: Packet): Boolean { - return false - } + private fun handleARPResponse(frame: ARPResponseFrame, fromItf: Interface) { + arpTable[frame.query] = frame.source + println("$this ($ipAddress) received ARP response for ${frame.query} with ${frame.source}") - fun send(packet: Packet, destination: PacketSink) { - destination.handle(packet) - } - - 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 + packetQueue.removeIf { (packet, itf, _) -> + if (packet.destination == frame.query) { + itf.send(BasePacketFrame(packet, itf.macAddress, frame.source)) + true + } else { + false + } } - send(packet, destinations.first()) } - override fun sendToAll(packet: Packet) { - sendToAll(packet, NetworkUtil.findDestinations(world!!, pos)) +// protected abstract fun handlePacket(packet: Packet, itf: Interface) +// +// 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 sendToAll(packet: Packet, destinations: Iterable) { - destinations.forEach { - it.handle(packet) + 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] + if (cached != null) { + itf.send(BasePacketFrame(packet, itf.macAddress, cached)) + } else { +// packetQueue.add(packet to itf) + packetQueue.add(PendingPacket(packet, itf, counter)) + + println("$this ($ipAddress) sending ARP query for ${packet.destination}") + itf.send(ARPQueryFrame(packet.destination, ipAddress, itf.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? { +// 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) { +// destinations.forEach { +// it.handle(packet) +// } +// } + + override fun findDestination(fromItf: Interface): Interface? { + val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos) + if (sides.size != 1) { + throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side") + } + return NetworkUtil.findConnectedInterface(world!!, pos, sides.first()) + } + + override fun tick() { + if (!world!!.isClient) { + counter++ + + packetQueue.removeIf { entry -> + val (packet, itf, timestamp) = entry + if (arpTable.containsKey(packet.destination)) { + itf.send(BasePacketFrame(packet, itf.macAddress, arpTable[packet.destination]!!)) + true + } else if (counter - timestamp >= ARP_RETRY_TIMEOUT) { + itf.send(ARPQueryFrame(packet.destination, ipAddress, itf.macAddress)) + entry.timestamp = counter + // todo: should there be a retry counter? + true + } else { + false + } + } } } override fun toTag(tag: CompoundTag): CompoundTag { - tag.putLong("MACAddress", macAddress.address) + tag.putInt("IPAddress", ipAddress.address) +// tag.putLong("MACAddress", macAddress.address) + tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) return super.toTag(tag) } override fun fromTag(state: BlockState, tag: CompoundTag) { super.fromTag(state, tag) - macAddress = MACAddress(tag.getLong("MACAddress")) + ipAddress = IPAddress(tag.getInt("IPAddress")) + // todo: what happens if the defined number of ports changes between mod versions? + tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> + interfaces[i].macAddress = MACAddress(l) + } + } + + override fun toClientTag(tag: CompoundTag): CompoundTag { + tag.putInt("IPAddress", ipAddress.address) + tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) + return tag + } + + override fun fromClientTag(tag: CompoundTag) { + ipAddress = IPAddress(tag.getInt("IPAddress")) + tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> + interfaces[i].macAddress = MACAddress(l) + } } fun onBreak() { - sendToAll(DeviceRemovedPacket(this)) + sendPacket(DeviceRemovedPacket(this)) } + data class PendingPacket( + val packet: Packet, + val sourceItf: Interface, + var timestamp: Long, + ) + } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt b/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt index 2930e3f..71966c2 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/NetworkUtil.kt @@ -3,10 +3,7 @@ package net.shadowfacts.phycon.network import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.world.World -import net.shadowfacts.phycon.api.NetworkCable -import net.shadowfacts.phycon.api.NetworkComponent -import net.shadowfacts.phycon.api.PacketSink -import net.shadowfacts.phycon.api.PhyAttributes +import net.shadowfacts.phycon.api.* import java.util.* /** @@ -14,6 +11,28 @@ import java.util.* */ object NetworkUtil { + fun findConnectedInterface(world: World, startPos: BlockPos, startSide: Direction): Interface? { + var curSide = startSide + var pos = startPos.offset(startSide) + var state = world.getBlockState(pos) + while (state.block is NetworkComponentBlock) { + val block = state.block as NetworkComponentBlock + val itf = block.getNetworkInterfaceForSide(curSide.opposite, state, world, pos) + if (itf != null) { + return itf + } + val connectedSides = block.getNetworkConnectedSides(state, world, pos).filter { it != curSide.opposite } + if (connectedSides.size == 1) { + curSide = connectedSides.first() + pos = pos.offset(curSide) + state = world.getBlockState(pos) + } else { + return null + } + } + return null + } + fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List { val results = LinkedList() val visited = hashSetOf(startPos) @@ -43,7 +62,7 @@ object NetworkUtil { private fun findEdges(queue: MutableList, visited: Set, world: World, pos: BlockPos, includeNonCables: Boolean = false) { val state = world.getBlockState(pos) val block = state.block - if (block is NetworkComponent && (includeNonCables || block is NetworkCable)) { + if (block is NetworkComponentBlock && (includeNonCables || block is NetworkCableBlock)) { val connections = block.getNetworkConnectedSides(state, world, pos) for (side in connections) { val newPos = pos.offset(side) diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/cable/CableBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/cable/CableBlock.kt index 73764fc..8ab2c0d 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/cable/CableBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/cable/CableBlock.kt @@ -19,8 +19,9 @@ import net.minecraft.world.BlockView import net.minecraft.world.World import net.minecraft.world.WorldAccess import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.api.NetworkCable -import net.shadowfacts.phycon.api.NetworkComponent +import net.shadowfacts.phycon.api.Interface +import net.shadowfacts.phycon.api.NetworkCableBlock +import net.shadowfacts.phycon.api.NetworkComponentBlock import net.shadowfacts.phycon.init.PhyItems import net.shadowfacts.phycon.util.CableConnection import java.util.* @@ -31,7 +32,7 @@ import java.util.* class CableBlock: Block( Settings.of(CABLE_MATERIAL) .nonOpaque() -), NetworkCable { +), NetworkCableBlock { companion object { val ID = Identifier(PhysicalConnectivity.MODID, "cable") val CABLE_MATERIAL = Material(MaterialColor.IRON, false, false, true, false, true, false, PistonBehavior.NORMAL) @@ -108,11 +109,16 @@ class CableBlock: Block( else -> CableConnection.ON } } - is NetworkComponent -> CableConnection.ON + is NetworkComponentBlock -> CableConnection.ON else -> CableConnection.OFF } } + override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { + // cables don't have network interfaces + return null + } + override fun onUse( state: BlockState, world: World, @@ -141,7 +147,7 @@ class CableBlock: Block( world.setBlockState(connectedToPos, connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON)) } - state.with(prop, if (connectedTo.block is NetworkComponent) CableConnection.ON else CableConnection.OFF) + state.with(prop, if (connectedTo.block is NetworkComponentBlock) CableConnection.ON else CableConnection.OFF) } else -> state.with(prop, CableConnection.DISABLED) } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlock.kt index 9fa9726..68672fa 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlock.kt @@ -1,120 +1,128 @@ package net.shadowfacts.phycon.network.block.netinterface - -import alexiil.mc.lib.attributes.AttributeList -import alexiil.mc.lib.attributes.AttributeProvider -import net.minecraft.block.Block -import net.minecraft.block.BlockState -import net.minecraft.block.Material -import net.minecraft.block.ShapeContext -import net.minecraft.entity.LivingEntity -import net.minecraft.item.ItemPlacementContext -import net.minecraft.item.ItemStack -import net.minecraft.state.StateManager -import net.minecraft.state.property.EnumProperty -import net.minecraft.state.property.Properties -import net.minecraft.util.Identifier -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Direction -import net.minecraft.util.shape.VoxelShape -import net.minecraft.util.shape.VoxelShapes -import net.minecraft.world.BlockView -import net.minecraft.world.World -import net.minecraft.world.WorldAccess -import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.api.NetworkComponent -import net.shadowfacts.phycon.block.BlockWithEntity -import net.shadowfacts.phycon.network.block.cable.CableBlock -import java.util.* - -/** - * @author shadowfacts - */ -class InterfaceBlock: BlockWithEntity(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider { - companion object { - val ID = Identifier(PhysicalConnectivity.MODID, "network_interface") - val FACING = Properties.FACING - val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java) - private val SIDE_SHAPES = mapOf( - Direction.DOWN to createCuboidShape(2.0, 0.0, 2.0, 14.0, 2.0, 14.0), - Direction.UP to createCuboidShape(2.0, 14.0, 2.0, 14.0, 16.0, 14.0), - Direction.NORTH to createCuboidShape(2.0, 2.0, 0.0, 14.0, 14.0, 2.0), - Direction.SOUTH to createCuboidShape(2.0, 2.0, 14.0, 14.0, 14.0, 16.0), - Direction.WEST to createCuboidShape(0.0, 2.0, 2.0, 2.0, 14.0, 14.0), - Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.0) - ) - private val CENTER_SHAPES = mapOf( - Direction.DOWN to createCuboidShape(6.0, 2.0, 6.0, 10.0, 10.0, 10.0), - Direction.UP to createCuboidShape(6.0, 6.0, 6.0, 10.0, 14.0, 10.0), - Direction.NORTH to createCuboidShape(6.0, 6.0, 2.0, 10.0, 10.0, 10.0), - Direction.SOUTH to createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 14.0), - Direction.WEST to createCuboidShape(2.0, 6.0, 6.0, 10.0, 10.0, 10.0), - Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 14.0, 10.0, 10.0) - ) - - private val shapeCache = mutableMapOf, VoxelShape>() - fun getShape(facing: Direction, cableConnection: Direction): VoxelShape { - return shapeCache.getOrPut(facing to cableConnection) { - VoxelShapes.union( - VoxelShapes.union(SIDE_SHAPES[facing], CENTER_SHAPES[facing]), - CableBlock.SIDE_SHAPES[cableConnection] - ) - } - } - } - - override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection { - return EnumSet.of(state[CABLE_CONNECTION]) - } - - override fun appendProperties(builder: StateManager.Builder) { - super.appendProperties(builder) - builder.add(FACING) - builder.add(CABLE_CONNECTION) - } - - override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity() - - override fun getPlacementState(context: ItemPlacementContext): BlockState { - val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite - val cableConnection = getCableConnectionSide(context.world, context.blockPos) ?: facing.opposite - return defaultState.with(FACING, facing).with(CABLE_CONNECTION, cableConnection) - } - - private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? { - for (side in Direction.values()) { - val offsetPos = pos.offset(side) - if (world.getBlockState(offsetPos).block is NetworkComponent) { - return side - } - } - return null - } - - override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) { - if (!world.isClient) { - getBlockEntity(world, pos)!!.updateInventory() - } - } - - override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, boolean_1: Boolean) { - if (!world.isClient) { - getBlockEntity(world, pos)!!.updateInventory() - } - } - - override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState { - if (neighborState.block is NetworkComponent && world.getBlockState(pos.offset(state[CABLE_CONNECTION])).block !is NetworkComponent) { - return state.with(CABLE_CONNECTION, side) - } - return state - } - - override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { - to.offer(getBlockEntity(world, pos)) - } - - override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape { - return getShape(state[FACING], state[CABLE_CONNECTION]) - } - -} +// +//import alexiil.mc.lib.attributes.AttributeList +//import alexiil.mc.lib.attributes.AttributeProvider +//import net.minecraft.block.Block +//import net.minecraft.block.BlockState +//import net.minecraft.block.Material +//import net.minecraft.block.ShapeContext +//import net.minecraft.entity.LivingEntity +//import net.minecraft.item.ItemPlacementContext +//import net.minecraft.item.ItemStack +//import net.minecraft.state.StateManager +//import net.minecraft.state.property.EnumProperty +//import net.minecraft.state.property.Properties +//import net.minecraft.util.Identifier +//import net.minecraft.util.math.BlockPos +//import net.minecraft.util.math.Direction +//import net.minecraft.util.shape.VoxelShape +//import net.minecraft.util.shape.VoxelShapes +//import net.minecraft.world.BlockView +//import net.minecraft.world.World +//import net.minecraft.world.WorldAccess +//import net.shadowfacts.phycon.PhysicalConnectivity +//import net.shadowfacts.phycon.api.NetworkComponentBlock +//import net.shadowfacts.phycon.api.Interface +//import net.shadowfacts.phycon.block.BlockWithEntity +//import net.shadowfacts.phycon.network.block.cable.CableBlock +//import java.util.* +// +///** +// * @author shadowfacts +// */ +//class InterfaceBlock: BlockWithEntity(Settings.of(Material.METAL)), +// NetworkComponentBlock, +// AttributeProvider { +// +// companion object { +// val ID = Identifier(PhysicalConnectivity.MODID, "network_interface") +// val FACING = Properties.FACING +// val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java) +// private val SIDE_SHAPES = mapOf( +// Direction.DOWN to createCuboidShape(2.0, 0.0, 2.0, 14.0, 2.0, 14.0), +// Direction.UP to createCuboidShape(2.0, 14.0, 2.0, 14.0, 16.0, 14.0), +// Direction.NORTH to createCuboidShape(2.0, 2.0, 0.0, 14.0, 14.0, 2.0), +// Direction.SOUTH to createCuboidShape(2.0, 2.0, 14.0, 14.0, 14.0, 16.0), +// Direction.WEST to createCuboidShape(0.0, 2.0, 2.0, 2.0, 14.0, 14.0), +// Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.0) +// ) +// private val CENTER_SHAPES = mapOf( +// Direction.DOWN to createCuboidShape(6.0, 2.0, 6.0, 10.0, 10.0, 10.0), +// Direction.UP to createCuboidShape(6.0, 6.0, 6.0, 10.0, 14.0, 10.0), +// Direction.NORTH to createCuboidShape(6.0, 6.0, 2.0, 10.0, 10.0, 10.0), +// Direction.SOUTH to createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 14.0), +// Direction.WEST to createCuboidShape(2.0, 6.0, 6.0, 10.0, 10.0, 10.0), +// Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 14.0, 10.0, 10.0) +// ) +// +// private val shapeCache = mutableMapOf, VoxelShape>() +// fun getShape(facing: Direction, cableConnection: Direction): VoxelShape { +// return shapeCache.getOrPut(facing to cableConnection) { +// VoxelShapes.union( +// VoxelShapes.union(SIDE_SHAPES[facing], CENTER_SHAPES[facing]), +// CableBlock.SIDE_SHAPES[cableConnection] +// ) +// } +// } +// } +// +// override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection { +// return EnumSet.of(state[CABLE_CONNECTION]) +// } +// +// override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { +// return getBlockEntity(world, pos)?.deviceInterfaces?.first() +// } +// +// override fun appendProperties(builder: StateManager.Builder) { +// super.appendProperties(builder) +// builder.add(FACING) +// builder.add(CABLE_CONNECTION) +// } +// +// override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity() +// +// override fun getPlacementState(context: ItemPlacementContext): BlockState { +// val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite +// val cableConnection = getCableConnectionSide(context.world, context.blockPos) ?: facing.opposite +// return defaultState.with(FACING, facing).with(CABLE_CONNECTION, cableConnection) +// } +// +// private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? { +// for (side in Direction.values()) { +// val offsetPos = pos.offset(side) +// if (world.getBlockState(offsetPos).block is NetworkComponentBlock) { +// return side +// } +// } +// return null +// } +// +// override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) { +// if (!world.isClient) { +// getBlockEntity(world, pos)!!.updateInventory() +// } +// } +// +// override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, boolean_1: Boolean) { +// if (!world.isClient) { +// getBlockEntity(world, pos)!!.updateInventory() +// } +// } +// +// override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState { +// if (neighborState.block is NetworkComponentBlock && world.getBlockState(pos.offset(state[CABLE_CONNECTION])).block !is NetworkComponentBlock) { +// return state.with(CABLE_CONNECTION, side) +// } +// return state +// } +// +// override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { +// to.offer(getBlockEntity(world, pos)) +// } +// +// override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape { +// return getShape(state[FACING], state[CABLE_CONNECTION]) +// } +// +//} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlockEntity.kt index 1300771..2caf0f1 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/netinterface/InterfaceBlockEntity.kt @@ -1,89 +1,93 @@ package net.shadowfacts.phycon.network.block.netinterface - -import alexiil.mc.lib.attributes.SearchOptions -import alexiil.mc.lib.attributes.Simulation -import alexiil.mc.lib.attributes.item.GroupedItemInv -import alexiil.mc.lib.attributes.item.ItemAttributes -import net.minecraft.item.ItemStack -import net.minecraft.util.math.Direction -import net.shadowfacts.phycon.api.packet.Packet -import net.shadowfacts.phycon.init.PhyBlockEntities -import net.shadowfacts.phycon.network.DeviceBlockEntity -import net.shadowfacts.phycon.network.component.ItemStackPacketHandler -import net.shadowfacts.phycon.network.component.handleItemStack -import net.shadowfacts.phycon.network.packet.* - -/** - * @author shadowfacts - */ -class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler { - - private val facing: Direction - get() = world!!.getBlockState(pos)[InterfaceBlock.FACING] - - // todo: should this be a weak ref? - private var inventory: GroupedItemInv? = null - - fun updateInventory() { - val offsetPos = pos.offset(facing) - val option = SearchOptions.inDirection(facing) - inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option) - } - - private fun getInventory(): GroupedItemInv? { - // 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 - } - - override fun handlePacket(packet: Packet) { - when (packet) { - is RequestInventoryPacket -> handleRequestInventory(packet) - is LocateStackPacket -> handleLocateStack(packet) - is ExtractStackPacket -> handleExtractStack(packet) - is CheckCapacityPacket -> handleCheckCapacity(packet) - is ItemStackPacket -> handleItemStack(packet) - } - } - - private fun handleRequestInventory(packet: RequestInventoryPacket) { - getInventory()?.also { inv -> - sendToSingle(ReadInventoryPacket(inv, macAddress, packet.source)) - } - } - - private fun handleLocateStack(packet: LocateStackPacket) { - getInventory()?.also { inv -> - val amount = inv.getAmount(packet.stack) - sendToSingle(StackLocationPacket(packet.stack, amount, this, macAddress, packet.source)) - } - } - - private fun handleExtractStack(packet: ExtractStackPacket) { - getInventory()?.also { inv -> - val extracted = inv.extract(packet.stack, packet.amount) - sendToSingle(ItemStackPacket(extracted, macAddress, packet.source)) - } - } - - private fun handleCheckCapacity(packet: CheckCapacityPacket) { - getInventory()?.also { inv -> - val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE) - val couldAccept = packet.stack.count - remaining.count - sendToSingle(CapacityPacket(packet.stack, couldAccept, this, macAddress, packet.source)) - } - } - - override fun doHandleItemStack(packet: ItemStackPacket): ItemStack { - val inventory = getInventory() - if (inventory != null) { - val remaining = inventory.insert(packet.stack) - // whatever could not be inserted will be sent back to the packet's source - return remaining - } else { - return packet.stack - } - } - -} +// +//import alexiil.mc.lib.attributes.SearchOptions +//import alexiil.mc.lib.attributes.Simulation +//import alexiil.mc.lib.attributes.item.GroupedItemInv +//import alexiil.mc.lib.attributes.item.ItemAttributes +//import net.minecraft.item.ItemStack +//import net.minecraft.util.math.Direction +//import net.shadowfacts.phycon.api.Interface +//import net.shadowfacts.phycon.api.packet.Packet +//import net.shadowfacts.phycon.init.PhyBlockEntities +//import net.shadowfacts.phycon.network.BaseInterface +//import net.shadowfacts.phycon.network.DeviceBlockEntity +//import net.shadowfacts.phycon.network.component.ItemStackPacketHandler +//import net.shadowfacts.phycon.network.component.handleItemStack +//import net.shadowfacts.phycon.network.packet.* +// +///** +// * @author shadowfacts +// */ +//class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler { +// +// override val interfaces = listOf(BaseInterface(this)) +// +// private val facing: Direction +// get() = world!!.getBlockState(pos)[InterfaceBlock.FACING] +// +// // todo: should this be a weak ref? +// private var inventory: GroupedItemInv? = null +// +// fun updateInventory() { +// val offsetPos = pos.offset(facing) +// val option = SearchOptions.inDirection(facing) +// inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option) +// } +// +// private fun getInventory(): GroupedItemInv? { +// // 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 +// } +// +// override fun handle(packet: Packet, itf: Interface) { +// when (packet) { +// is RequestInventoryPacket -> handleRequestInventory(packet) +// is LocateStackPacket -> handleLocateStack(packet) +// is ExtractStackPacket -> handleExtractStack(packet) +// is CheckCapacityPacket -> handleCheckCapacity(packet) +// is ItemStackPacket -> handleItemStack(packet) +// } +// } +// +// private fun handleRequestInventory(packet: RequestInventoryPacket) { +// getInventory()?.also { inv -> +// sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source)) +// } +// } +// +// private fun handleLocateStack(packet: LocateStackPacket) { +// getInventory()?.also { inv -> +// val amount = inv.getAmount(packet.stack) +// sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source)) +// } +// } +// +// private fun handleExtractStack(packet: ExtractStackPacket) { +// getInventory()?.also { inv -> +// val extracted = inv.extract(packet.stack, packet.amount) +// sendPacket(ItemStackPacket(extracted, ipAddress, packet.source)) +// } +// } +// +// private fun handleCheckCapacity(packet: CheckCapacityPacket) { +// getInventory()?.also { inv -> +// val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE) +// val couldAccept = packet.stack.count - remaining.count +// sendPacket(CapacityPacket(packet.stack, couldAccept, this, ipAddress, packet.source)) +// } +// } +// +// override fun doHandleItemStack(packet: ItemStackPacket): ItemStack { +// val inventory = getInventory() +// if (inventory != null) { +// val remaining = inventory.insert(packet.stack) +// // whatever could not be inserted will be sent back to the packet's source +// return remaining +// } else { +// return packet.stack +// } +// } +// +//} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlock.kt index 6103322..03ae002 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlock.kt @@ -10,14 +10,18 @@ import net.minecraft.util.math.Direction import net.minecraft.world.BlockView import net.minecraft.world.World import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.api.NetworkComponent +import net.shadowfacts.phycon.api.Interface +import net.shadowfacts.phycon.api.NetworkComponentBlock import net.shadowfacts.phycon.block.BlockWithEntity import java.util.* /** * @author shadowfacts */ -class SwitchBlock: BlockWithEntity(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider { +class SwitchBlock: BlockWithEntity(Settings.of(Material.METAL)), + NetworkComponentBlock, + AttributeProvider { + companion object { val ID = Identifier(PhysicalConnectivity.MODID, "switch") } @@ -26,6 +30,10 @@ class SwitchBlock: BlockWithEntity(Settings.of(Material.METAL return EnumSet.allOf(Direction::class.java) } + override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { + return getBlockEntity(world, pos)?.interfaces?.find { it.side == side } + } + override fun createBlockEntity(world: BlockView) = SwitchBlockEntity() override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt index 0352b2f..8b391b5 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/netswitch/SwitchBlockEntity.kt @@ -1,82 +1,129 @@ package net.shadowfacts.phycon.network.block.netswitch -import net.minecraft.entity.ItemEntity +import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable +import net.minecraft.block.BlockState +import net.minecraft.block.entity.BlockEntity +import net.minecraft.nbt.CompoundTag import net.minecraft.util.Tickable import net.minecraft.util.math.Direction -import net.shadowfacts.phycon.api.PacketSink +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.util.IPAddress import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.init.PhyBlockEntities -import net.shadowfacts.phycon.network.DeviceBlockEntity +import net.shadowfacts.phycon.network.BaseInterface +import net.shadowfacts.phycon.network.InterfaceDelegate import net.shadowfacts.phycon.network.NetworkUtil -import net.shadowfacts.phycon.network.packet.ItemStackPacket -import java.lang.RuntimeException /** * @author shadowfacts */ -class SwitchBlockEntity: DeviceBlockEntity(PhyBlockEntities.SWITCH), Tickable { +class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH), + BlockEntityClientSerializable, + InterfaceDelegate, + Tickable { companion object { var SWITCHING_CAPACITY = 256 } + val interfaces = Direction.values().map { SwitchInterface(it, this) } + private val macTable = mutableMapOf() private var packetsHandledThisTick = 0 - override fun acceptsPacket(packet: Packet) = true +// override fun handle(packet: Packet, itf: Interface) { +// if (packetsHandledThisTick >= SWITCHING_CAPACITY) { +// if (packet is ItemStackPacket) { +// // todo: calculate entity spawn point by finding non-obstructed location +// val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack) +// world!!.spawnEntity(entity) +// } +// return +// } +// +// packetsHandledThisTick++ +// +// if (packet.destination.isBroadcast) { +//// for (other in interfaces) { +//// if (other == itf) continue +//// sendPacket(packet, other) +//// } +// flood(packet, itf) +// } else { +// val direction = ipTable[packet.destination] +// if (direction != null) { +// sendPacket() +//// val dest = findDestination(direction) +//// if (dest != null && packet.destination == dest.macAddress) { +//// sendPacke(packet, dest) +//// return +//// } +// } +// flood(packet, itf) +// } +// } - override fun handlePacket(packet: Packet) { - if (packetsHandledThisTick >= SWITCHING_CAPACITY) { - if (packet is ItemStackPacket) { - // todo: calculate entity spawn point by finding non-obstructed location - val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack) - world!!.spawnEntity(entity) - } - return - } + fun interfaceForSide(side: Direction): SwitchInterface { + return interfaces.find { it.side == side }!! + } - packetsHandledThisTick++ + override fun handle(frame: EthernetFrame, fromItf: Interface) { + val itfSide = (fromItf as SwitchInterface).side + macTable[frame.source] = itfSide - if (packet.destination == MACAddress.BROADCAST) { - val allDestinations = NetworkUtil.findDestinations(world!!, pos).filter { it.macAddress != packet.source } - sendToAll(packet, allDestinations) + val knownDir = macTable[frame.destination] + if (knownDir != null) { + println("$this ($itfSide, ${fromItf.macAddress}) forwarding $frame to side $knownDir") + interfaceForSide(knownDir).send(frame) } else { - val direction = macTable[packet.destination] - if (direction != null) { - val dest = findDestination(direction) - if (dest != null && packet.destination == dest.macAddress) { - send(packet, dest) - return - } - } - flood(packet) + println("$this ($itfSide, ${fromItf.macAddress}) flooding $frame") + flood(frame, fromItf) } } - 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 + private fun flood(frame: EthernetFrame, source: Interface) { + for (itf in interfaces) { + if (source == itf) continue + itf.send(frame) } - 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 - send(packet, dest) - break - } - } + override fun findDestination(fromItf: Interface): Interface? { + val side = (fromItf as SwitchInterface).side + return NetworkUtil.findConnectedInterface(world!!, pos, side) } override fun tick() { packetsHandledThisTick = 0 } + override fun toTag(tag: CompoundTag): CompoundTag { + tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) + return super.toTag(tag) + } + + override fun fromTag(state: BlockState, tag: CompoundTag) { + super.fromTag(state, tag) + tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> + interfaces[i].macAddress = MACAddress(l) + } + } + + override fun toClientTag(tag: CompoundTag): CompoundTag { + tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address }) + return tag + } + + override fun fromClientTag(tag: CompoundTag) { + tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l -> + interfaces[i].macAddress = MACAddress(l) + } + } + + class SwitchInterface(val side: Direction, delegate: InterfaceDelegate): BaseInterface(delegate) { + + } + } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt index 90b42e4..2b3e513 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt @@ -1,43 +1,44 @@ package net.shadowfacts.phycon.network.block.terminal - -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.entity.player.PlayerEntity -import net.minecraft.util.ActionResult -import net.minecraft.util.Hand -import net.minecraft.util.Identifier -import net.minecraft.util.hit.BlockHitResult -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Direction -import net.minecraft.world.BlockView -import net.minecraft.world.World -import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.api.NetworkComponent -import net.shadowfacts.phycon.block.BlockWithEntity -import java.util.* - -/** - * @author shadowfacts - */ -class TerminalBlock: BlockWithEntity(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider { - companion object { - val ID = Identifier(PhysicalConnectivity.MODID, "terminal") - } - - override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection { - return EnumSet.allOf(Direction::class.java) - } - - override fun createBlockEntity(world: BlockView) = TerminalBlockEntity() - - override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult { - getBlockEntity(world, pos)!!.onActivate(player) - return ActionResult.SUCCESS - } - - override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { - to.offer(getBlockEntity(world, pos)) - } -} +// +//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.entity.player.PlayerEntity +//import net.minecraft.util.ActionResult +//import net.minecraft.util.Hand +//import net.minecraft.util.Identifier +//import net.minecraft.util.hit.BlockHitResult +//import net.minecraft.util.math.BlockPos +//import net.minecraft.util.math.Direction +//import net.minecraft.world.BlockView +//import net.minecraft.world.World +//import net.shadowfacts.phycon.PhysicalConnectivity +//import net.shadowfacts.phycon.api.NetworkComponentBlock +//import net.shadowfacts.phycon.block.BlockWithEntity +//import java.util.* +// +///** +// * @author shadowfacts +// */ +//class TerminalBlock: BlockWithEntity(Settings.of(Material.METAL)), +// NetworkComponentBlock, AttributeProvider { +// companion object { +// val ID = Identifier(PhysicalConnectivity.MODID, "terminal") +// } +// +// override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection { +// return EnumSet.allOf(Direction::class.java) +// } +// +// override fun createBlockEntity(world: BlockView) = TerminalBlockEntity() +// +// override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult { +// getBlockEntity(world, pos)!!.onActivate(player) +// return ActionResult.SUCCESS +// } +// +// override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { +// to.offer(getBlockEntity(world, pos)) +// } +//} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt index 4aad945..c9db65f 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt @@ -1,330 +1,330 @@ package net.shadowfacts.phycon.network.block.terminal - -import alexiil.mc.lib.attributes.item.GroupedItemInv -import alexiil.mc.lib.attributes.item.ItemStackCollections -import alexiil.mc.lib.attributes.item.ItemStackUtil -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap -import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable -import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory -import net.minecraft.block.BlockState -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.entity.player.PlayerInventory -import net.minecraft.inventory.Inventory -import net.minecraft.inventory.InventoryChangedListener -import net.minecraft.item.ItemStack -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.ListTag -import net.minecraft.network.PacketByteBuf -import net.minecraft.screen.ScreenHandler -import net.minecraft.server.network.ServerPlayerEntity -import net.minecraft.text.LiteralText -import net.minecraft.util.Tickable -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.block.netinterface.InterfaceBlockEntity -import net.shadowfacts.phycon.network.component.ItemStackPacketHandler -import net.shadowfacts.phycon.network.component.handleItemStack -import net.shadowfacts.phycon.network.packet.* -import java.util.* -import kotlin.math.min - -/** - * @author shadowfacts - */ -class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable, ItemStackPacketHandler { - - companion object { - val LOCATE_REQUEST_TIMEOUT = 40 // ticks - val INSERTION_TIMEOUT = 40 - } - - private val inventoryCache = mutableMapOf() - val internalBuffer = TerminalBufferInventory(18) - - private val locateRequestQueue = LinkedList() - private val pendingRequests = LinkedList() - private val pendingInsertions = Int2ObjectArrayMap() - - private var observers = 0 - val cachedNetItems = ItemStackCollections.intMap() - var cachedSortedNetItems = listOf() - var counter = 0 - - init { - internalBuffer.addListener(this) - } - - override fun handlePacket(packet: Packet) { - when (packet) { - is ReadInventoryPacket -> handleReadInventory(packet) - is DeviceRemovedPacket -> handleDeviceRemoved(packet) - is StackLocationPacket -> handleStackLocation(packet) - is ItemStackPacket -> handleItemStack(packet) - is CapacityPacket -> handleCapacity(packet) - } - } - - private fun handleReadInventory(packet: ReadInventoryPacket) { - inventoryCache[packet.source] = packet.inventory - updateNetItems() - sync() - } - - private fun handleDeviceRemoved(packet: DeviceRemovedPacket) { - inventoryCache.remove(packet.source) - updateNetItems() - sync() - } - - private fun handleStackLocation(packet: StackLocationPacket) { - val request = pendingRequests.firstOrNull { - ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack) - } - if (request != null) { - request.results.add(packet.amount to packet.sourceInterface) - if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) { - stackLocateRequestCompleted(request) - } - } - } - - override fun doHandleItemStack(packet: ItemStackPacket): ItemStack { - val remaining = internalBuffer.insertFromNetwork(packet.stack) - - // this happens outside the normal update loop because by receiving the item stack packet - // we "know" how much the count in the source inventory has changed - updateNetItems() - sync() - - return remaining - } - - private fun handleCapacity(packet: CapacityPacket) { - val insertion = pendingInsertions.values.firstOrNull { - ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack) - } - if (insertion != null) { - insertion.results.add(packet.capacity to packet.receivingInterface) - if (insertion.isFinishable(counter)) { - finishInsertion(insertion) - } - } - } - - private fun updateNetItems() { - cachedNetItems.clear() - for (inventory in inventoryCache.values) { - for (stack in inventory.storedStacks) { - val amount = inventory.getAmount(stack) - cachedNetItems.mergeInt(stack, amount) { a, b -> a + b } - } - } - // todo: is the map necessary or is just the sorted list enough? - cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map { - val stack = it.key.copy() - stack.count = it.intValue - stack - } - } - - private fun beginInsertions() { - if (world!!.isClient) return - - for (slot in 0 until internalBuffer.size()) { - if (internalBuffer.getMode(slot) != TerminalBufferInventory.Mode.TO_NETWORK) continue - if (slot in pendingInsertions) continue - val stack = internalBuffer.getStack(slot) - pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter) - sendToSingle(CheckCapacityPacket(stack, macAddress, MACAddress.BROADCAST)) - } - } - - private fun finishPendingInsertions() { - if (world!!.isClient) return - - for (insertion in pendingInsertions.values) { - if (!insertion.isFinishable(counter)) continue - finishInsertion(insertion) - } - } - - private fun sendEnqueuedLocateRequests() { - if (world!!.isClient) return - - for (request in locateRequestQueue) { - pendingRequests.add(request) - sendToSingle(LocateStackPacket(request.stack, macAddress)) - } - locateRequestQueue.clear() - } - - private fun finishPendingRequests() { - if (world!!.isClient) return - - for (request in pendingRequests) { - if (request.isFinishable(counter)) { - stackLocateRequestCompleted(request) - } - } - } - - fun addObserver() { - observers++ - } - - fun removeObserver() { - observers-- - } - - override fun tick() { - if (observers > 0 && (++counter % 10) == 0) { - if (world!!.isClient) { - println(cachedNetItems) - } else { - updateNetItems() - sendEnqueuedLocateRequests() - finishPendingRequests() - beginInsertions() - finishPendingInsertions() - sync() - } - } - } - - fun onActivate(player: PlayerEntity) { - if (!world!!.isClient) { - updateNetItems() - sync() - - inventoryCache.clear() - sendToSingle(RequestInventoryPacket(macAddress)) - val factory = object: ExtendedScreenHandlerFactory { - override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? { - return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity) - } - - override fun getDisplayName() = LiteralText("Terminal") - - override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) { - buf.writeBlockPos(this@TerminalBlockEntity.pos) - } - } - player.openHandledScreen(factory) - } - addObserver() - } - - fun requestItem(stack: ItemStack, amount: Int = stack.count) { - locateRequestQueue.add(StackLocateRequest(stack, amount, counter)) - } - - private fun stackLocateRequestCompleted(request: StackLocateRequest) { - pendingRequests.remove(request) - - // todo: also sort results by interface priority - val sortedResults = request.results.sortedByDescending { it.first }.toMutableList() - var amountRequested = 0 - while (amountRequested < request.amount && sortedResults.isNotEmpty()) { - val (sourceAmount, sourceInterface) = sortedResults.removeAt(0) - val amountToRequest = min(sourceAmount, request.amount - amountRequested) - amountRequested += amountToRequest - sendToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress)) - } - } - - private fun finishInsertion(insertion: PendingStackInsertion) { - pendingInsertions.remove(insertion.bufferSlot) - - // todo: also sort results by interface priority - val sortedResults = insertion.results.sortedBy { it.first }.toMutableList() - val remaining = insertion.stack - while (!remaining.isEmpty && sortedResults.isNotEmpty()) { - val (capacity, receivingInterface) = sortedResults.removeAt(0) - if (capacity <= 0) continue - sendToSingle(ItemStackPacket(remaining.copy(), macAddress, receivingInterface.macAddress)) - // todo: the interface should confirm how much was actually inserted, in case of race condition - remaining.count -= capacity - } - internalBuffer.setStack(insertion.bufferSlot, remaining) - - // as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets - updateNetItems() - sync() - } - - override fun onInventoryChanged(inv: Inventory) { - if (inv == internalBuffer && world != null && !world!!.isClient) { - markDirty() - sync() - } - } - - override fun toTag(tag: CompoundTag): CompoundTag { - tag.put("InternalBuffer", internalBuffer.toTag()) - return super.toTag(tag) - } - - override fun fromTag(state: BlockState, tag: CompoundTag) { - super.fromTag(state, tag) - internalBuffer.fromTag(tag.getCompound("InternalBuffer")) - } - - override fun toClientTag(tag: CompoundTag): CompoundTag { - tag.put("InternalBuffer", internalBuffer.toTag()) - val list = ListTag() - tag.put("CachedNetItems", list) - for ((stack, amount) in cachedNetItems) { - val entryTag = stack.toTag(CompoundTag()) - entryTag.putInt("NetAmount", amount) - list.add(entryTag) - } - return tag - } - - override fun fromClientTag(tag: CompoundTag) { - internalBuffer.fromTag(tag.getCompound("InternalBuffer")) - val list = tag.getList("CachedNetItems", 10) - cachedNetItems.clear() - for (entryTag in list) { - val stack = ItemStack.fromTag(entryTag as CompoundTag) - val netAmount = entryTag.getInt("NetAmount") - cachedNetItems[stack] = netAmount - } - cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map { - val stack = it.key.copy() - stack.count = it.intValue - stack - } - } - -} - -data class StackLocateRequest( - val stack: ItemStack, - val amount: Int, - val timestamp: Int, - var results: MutableSet> = mutableSetOf() -) { - val totalResultAmount: Int - get() = results.fold(0) { acc, (amount, _) -> acc + amount } - - fun isFinishable(currentTimestamp: Int): Boolean { - return totalResultAmount > amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT - } -} - -data class PendingStackInsertion( - val bufferSlot: Int, - val stack: ItemStack, - val timestamp: Int, - val results: MutableSet> = mutableSetOf(), -) { - val totalCapacity: Int - get() = results.fold(0) { acc, (amount, _) -> acc + amount } - - fun isFinishable(currentTimestamp: Int): Boolean { - return totalCapacity > stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT - } -} +// +//import alexiil.mc.lib.attributes.item.GroupedItemInv +//import alexiil.mc.lib.attributes.item.ItemStackCollections +//import alexiil.mc.lib.attributes.item.ItemStackUtil +//import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap +//import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable +//import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory +//import net.minecraft.block.BlockState +//import net.minecraft.entity.player.PlayerEntity +//import net.minecraft.entity.player.PlayerInventory +//import net.minecraft.inventory.Inventory +//import net.minecraft.inventory.InventoryChangedListener +//import net.minecraft.item.ItemStack +//import net.minecraft.nbt.CompoundTag +//import net.minecraft.nbt.ListTag +//import net.minecraft.network.PacketByteBuf +//import net.minecraft.screen.ScreenHandler +//import net.minecraft.server.network.ServerPlayerEntity +//import net.minecraft.text.LiteralText +//import net.minecraft.util.Tickable +//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.block.netinterface.InterfaceBlockEntity +//import net.shadowfacts.phycon.network.component.ItemStackPacketHandler +//import net.shadowfacts.phycon.network.component.handleItemStack +//import net.shadowfacts.phycon.network.packet.* +//import java.util.* +//import kotlin.math.min +// +///** +// * @author shadowfacts +// */ +//class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable, ItemStackPacketHandler { +// +// companion object { +// val LOCATE_REQUEST_TIMEOUT = 40 // ticks +// val INSERTION_TIMEOUT = 40 +// } +// +// private val inventoryCache = mutableMapOf() +// val internalBuffer = TerminalBufferInventory(18) +// +// private val locateRequestQueue = LinkedList() +// private val pendingRequests = LinkedList() +// private val pendingInsertions = Int2ObjectArrayMap() +// +// private var observers = 0 +// val cachedNetItems = ItemStackCollections.intMap() +// var cachedSortedNetItems = listOf() +// var counter = 0 +// +// init { +// internalBuffer.addListener(this) +// } +// +// override fun handlePacket(packet: Packet) { +// when (packet) { +// is ReadInventoryPacket -> handleReadInventory(packet) +// is DeviceRemovedPacket -> handleDeviceRemoved(packet) +// is StackLocationPacket -> handleStackLocation(packet) +// is ItemStackPacket -> handleItemStack(packet) +// is CapacityPacket -> handleCapacity(packet) +// } +// } +// +// private fun handleReadInventory(packet: ReadInventoryPacket) { +// inventoryCache[packet.source] = packet.inventory +// updateNetItems() +// sync() +// } +// +// private fun handleDeviceRemoved(packet: DeviceRemovedPacket) { +// inventoryCache.remove(packet.source) +// updateNetItems() +// sync() +// } +// +// private fun handleStackLocation(packet: StackLocationPacket) { +// val request = pendingRequests.firstOrNull { +// ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack) +// } +// if (request != null) { +// request.results.add(packet.amount to packet.sourceInterface) +// if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) { +// stackLocateRequestCompleted(request) +// } +// } +// } +// +// override fun doHandleItemStack(packet: ItemStackPacket): ItemStack { +// val remaining = internalBuffer.insertFromNetwork(packet.stack) +// +// // this happens outside the normal update loop because by receiving the item stack packet +// // we "know" how much the count in the source inventory has changed +// updateNetItems() +// sync() +// +// return remaining +// } +// +// private fun handleCapacity(packet: CapacityPacket) { +// val insertion = pendingInsertions.values.firstOrNull { +// ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack) +// } +// if (insertion != null) { +// insertion.results.add(packet.capacity to packet.receivingInterface) +// if (insertion.isFinishable(counter)) { +// finishInsertion(insertion) +// } +// } +// } +// +// private fun updateNetItems() { +// cachedNetItems.clear() +// for (inventory in inventoryCache.values) { +// for (stack in inventory.storedStacks) { +// val amount = inventory.getAmount(stack) +// cachedNetItems.mergeInt(stack, amount) { a, b -> a + b } +// } +// } +// // todo: is the map necessary or is just the sorted list enough? +// cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map { +// val stack = it.key.copy() +// stack.count = it.intValue +// stack +// } +// } +// +// private fun beginInsertions() { +// if (world!!.isClient) return +// +// for (slot in 0 until internalBuffer.size()) { +// if (internalBuffer.getMode(slot) != TerminalBufferInventory.Mode.TO_NETWORK) continue +// if (slot in pendingInsertions) continue +// val stack = internalBuffer.getStack(slot) +// pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter) +// sendToSingle(CheckCapacityPacket(stack, macAddress, MACAddress.BROADCAST)) +// } +// } +// +// private fun finishPendingInsertions() { +// if (world!!.isClient) return +// +// for (insertion in pendingInsertions.values) { +// if (!insertion.isFinishable(counter)) continue +// finishInsertion(insertion) +// } +// } +// +// private fun sendEnqueuedLocateRequests() { +// if (world!!.isClient) return +// +// for (request in locateRequestQueue) { +// pendingRequests.add(request) +// sendToSingle(LocateStackPacket(request.stack, macAddress)) +// } +// locateRequestQueue.clear() +// } +// +// private fun finishPendingRequests() { +// if (world!!.isClient) return +// +// for (request in pendingRequests) { +// if (request.isFinishable(counter)) { +// stackLocateRequestCompleted(request) +// } +// } +// } +// +// fun addObserver() { +// observers++ +// } +// +// fun removeObserver() { +// observers-- +// } +// +// override fun tick() { +// if (observers > 0 && (++counter % 10) == 0) { +// if (world!!.isClient) { +// println(cachedNetItems) +// } else { +// updateNetItems() +// sendEnqueuedLocateRequests() +// finishPendingRequests() +// beginInsertions() +// finishPendingInsertions() +// sync() +// } +// } +// } +// +// fun onActivate(player: PlayerEntity) { +// if (!world!!.isClient) { +// updateNetItems() +// sync() +// +// inventoryCache.clear() +// sendToSingle(RequestInventoryPacket(macAddress)) +// val factory = object: ExtendedScreenHandlerFactory { +// override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? { +// return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity) +// } +// +// override fun getDisplayName() = LiteralText("Terminal") +// +// override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) { +// buf.writeBlockPos(this@TerminalBlockEntity.pos) +// } +// } +// player.openHandledScreen(factory) +// } +// addObserver() +// } +// +// fun requestItem(stack: ItemStack, amount: Int = stack.count) { +// locateRequestQueue.add(StackLocateRequest(stack, amount, counter)) +// } +// +// private fun stackLocateRequestCompleted(request: StackLocateRequest) { +// pendingRequests.remove(request) +// +// // todo: also sort results by interface priority +// val sortedResults = request.results.sortedByDescending { it.first }.toMutableList() +// var amountRequested = 0 +// while (amountRequested < request.amount && sortedResults.isNotEmpty()) { +// val (sourceAmount, sourceInterface) = sortedResults.removeAt(0) +// val amountToRequest = min(sourceAmount, request.amount - amountRequested) +// amountRequested += amountToRequest +// sendToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress)) +// } +// } +// +// private fun finishInsertion(insertion: PendingStackInsertion) { +// pendingInsertions.remove(insertion.bufferSlot) +// +// // todo: also sort results by interface priority +// val sortedResults = insertion.results.sortedBy { it.first }.toMutableList() +// val remaining = insertion.stack +// while (!remaining.isEmpty && sortedResults.isNotEmpty()) { +// val (capacity, receivingInterface) = sortedResults.removeAt(0) +// if (capacity <= 0) continue +// sendToSingle(ItemStackPacket(remaining.copy(), macAddress, receivingInterface.macAddress)) +// // todo: the interface should confirm how much was actually inserted, in case of race condition +// remaining.count -= capacity +// } +// internalBuffer.setStack(insertion.bufferSlot, remaining) +// +// // as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets +// updateNetItems() +// sync() +// } +// +// override fun onInventoryChanged(inv: Inventory) { +// if (inv == internalBuffer && world != null && !world!!.isClient) { +// markDirty() +// sync() +// } +// } +// +// override fun toTag(tag: CompoundTag): CompoundTag { +// tag.put("InternalBuffer", internalBuffer.toTag()) +// return super.toTag(tag) +// } +// +// override fun fromTag(state: BlockState, tag: CompoundTag) { +// super.fromTag(state, tag) +// internalBuffer.fromTag(tag.getCompound("InternalBuffer")) +// } +// +// override fun toClientTag(tag: CompoundTag): CompoundTag { +// tag.put("InternalBuffer", internalBuffer.toTag()) +// val list = ListTag() +// tag.put("CachedNetItems", list) +// for ((stack, amount) in cachedNetItems) { +// val entryTag = stack.toTag(CompoundTag()) +// entryTag.putInt("NetAmount", amount) +// list.add(entryTag) +// } +// return tag +// } +// +// override fun fromClientTag(tag: CompoundTag) { +// internalBuffer.fromTag(tag.getCompound("InternalBuffer")) +// val list = tag.getList("CachedNetItems", 10) +// cachedNetItems.clear() +// for (entryTag in list) { +// val stack = ItemStack.fromTag(entryTag as CompoundTag) +// val netAmount = entryTag.getInt("NetAmount") +// cachedNetItems[stack] = netAmount +// } +// cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map { +// val stack = it.key.copy() +// stack.count = it.intValue +// stack +// } +// } +// +//} +// +//data class StackLocateRequest( +// val stack: ItemStack, +// val amount: Int, +// val timestamp: Int, +// var results: MutableSet> = mutableSetOf() +//) { +// val totalResultAmount: Int +// get() = results.fold(0) { acc, (amount, _) -> acc + amount } +// +// fun isFinishable(currentTimestamp: Int): Boolean { +// return totalResultAmount > amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT +// } +//} +// +//data class PendingStackInsertion( +// val bufferSlot: Int, +// val stack: ItemStack, +// val timestamp: Int, +// val results: MutableSet> = mutableSetOf(), +//) { +// val totalCapacity: Int +// get() = results.fold(0) { acc, (amount, _) -> acc + amount } +// +// fun isFinishable(currentTimestamp: Int): Boolean { +// return totalCapacity > stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT +// } +//} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalFakeSlot.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalFakeSlot.kt index d30593c..d8f7e55 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalFakeSlot.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalFakeSlot.kt @@ -1,61 +1,61 @@ package net.shadowfacts.phycon.network.block.terminal -import net.minecraft.screen.slot.Slot -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.inventory.Inventory -import net.minecraft.item.ItemStack - -/** - * @author shadowfacts - */ -class TerminalFakeSlot(val terminal: TerminalBlockEntity, slot: Int, x: Int, y: Int): Slot(FakeInventory(terminal, slot), slot, x, y) { - - override fun canInsert(stack: ItemStack): Boolean { - return false - } - - override fun setStack(stack: ItemStack) { - } - - override fun canTakeItems(player: PlayerEntity): Boolean { - return false - } - -} - -class FakeInventory(val terminal: TerminalBlockEntity, val slot: Int): Inventory { - override fun getStack(_slot: Int): ItemStack { - if (slot >= terminal.cachedSortedNetItems.size) return ItemStack.EMPTY - return terminal.cachedSortedNetItems[slot] - } - - override fun markDirty() { - } - - override fun clear() { - } - - override fun setStack(p0: Int, p1: ItemStack?) { - } - - override fun removeStack(p0: Int): ItemStack { - return ItemStack.EMPTY - } - - override fun canPlayerUse(p0: PlayerEntity?): Boolean { - return false - } - - override fun size(): Int { - return 1 - } - - override fun removeStack(p0: Int, p1: Int): ItemStack { - return ItemStack.EMPTY - } - - override fun isEmpty(): Boolean { - return false - } - -} +//import net.minecraft.screen.slot.Slot +//import net.minecraft.entity.player.PlayerEntity +//import net.minecraft.inventory.Inventory +//import net.minecraft.item.ItemStack +// +///** +// * @author shadowfacts +// */ +//class TerminalFakeSlot(val terminal: TerminalBlockEntity, slot: Int, x: Int, y: Int): Slot(FakeInventory(terminal, slot), slot, x, y) { +// +// override fun canInsert(stack: ItemStack): Boolean { +// return false +// } +// +// override fun setStack(stack: ItemStack) { +// } +// +// override fun canTakeItems(player: PlayerEntity): Boolean { +// return false +// } +// +//} +// +//class FakeInventory(val terminal: TerminalBlockEntity, val slot: Int): Inventory { +// override fun getStack(_slot: Int): ItemStack { +// if (slot >= terminal.cachedSortedNetItems.size) return ItemStack.EMPTY +// return terminal.cachedSortedNetItems[slot] +// } +// +// override fun markDirty() { +// } +// +// override fun clear() { +// } +// +// override fun setStack(p0: Int, p1: ItemStack?) { +// } +// +// override fun removeStack(p0: Int): ItemStack { +// return ItemStack.EMPTY +// } +// +// override fun canPlayerUse(p0: PlayerEntity?): Boolean { +// return false +// } +// +// override fun size(): Int { +// return 1 +// } +// +// override fun removeStack(p0: Int, p1: Int): ItemStack { +// return ItemStack.EMPTY +// } +// +// override fun isEmpty(): Boolean { +// return false +// } +// +//} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreen.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreen.kt index 6482505..75bdaa3 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreen.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreen.kt @@ -1,58 +1,58 @@ package net.shadowfacts.phycon.network.block.terminal - -import com.mojang.blaze3d.platform.GlStateManager -import net.minecraft.client.gui.DrawableHelper -import net.minecraft.client.gui.screen.ingame.HandledScreen -import net.minecraft.client.util.math.MatrixStack -import net.minecraft.entity.player.PlayerInventory -import net.minecraft.screen.slot.Slot -import net.minecraft.text.LiteralText -import net.minecraft.text.Text -import net.minecraft.util.Identifier -import net.shadowfacts.phycon.PhysicalConnectivity - -/** - * @author shadowfacts - */ -// todo: translate title -class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen(handler, playerInv, title) { - companion object { - val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png") - } - - init { - backgroundWidth = 252 - backgroundHeight = 222 - } - - override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) { - textRenderer.draw(matrixStack, title, 65f, 6f, 0x404040) - textRenderer.draw(matrixStack, playerInventory.displayName, 65f, backgroundHeight - 94f, 0x404040) - // todo: translate this - textRenderer.draw(matrixStack, "Buffer", 7f, 6f, 0x404040) - } - - override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) { - GlStateManager.color4f(1f, 1f, 1f, 1f) - client!!.textureManager.bindTexture(BACKGROUND) - val x = (width - backgroundWidth) / 2 - val y = (height - backgroundHeight) / 2 - drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight) - } - - @ExperimentalUnsignedTypes - fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) { - if (!handler.isBufferSlot(slot.id)) { - return - } - - val mode = handler.terminal.internalBuffer.getMode(slot.id - handler.bufferSlotsStart) - val color: UInt = when (mode) { - TerminalBufferInventory.Mode.TO_NETWORK -> 0xFFFF0000u - TerminalBufferInventory.Mode.FROM_NETWORK -> 0xFF00FF00u - else -> return - } - DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt()) - } - -} +// +//import com.mojang.blaze3d.platform.GlStateManager +//import net.minecraft.client.gui.DrawableHelper +//import net.minecraft.client.gui.screen.ingame.HandledScreen +//import net.minecraft.client.util.math.MatrixStack +//import net.minecraft.entity.player.PlayerInventory +//import net.minecraft.screen.slot.Slot +//import net.minecraft.text.LiteralText +//import net.minecraft.text.Text +//import net.minecraft.util.Identifier +//import net.shadowfacts.phycon.PhysicalConnectivity +// +///** +// * @author shadowfacts +// */ +//// todo: translate title +//class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen(handler, playerInv, title) { +// companion object { +// val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png") +// } +// +// init { +// backgroundWidth = 252 +// backgroundHeight = 222 +// } +// +// override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) { +// textRenderer.draw(matrixStack, title, 65f, 6f, 0x404040) +// textRenderer.draw(matrixStack, playerInventory.displayName, 65f, backgroundHeight - 94f, 0x404040) +// // todo: translate this +// textRenderer.draw(matrixStack, "Buffer", 7f, 6f, 0x404040) +// } +// +// override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) { +// GlStateManager.color4f(1f, 1f, 1f, 1f) +// client!!.textureManager.bindTexture(BACKGROUND) +// val x = (width - backgroundWidth) / 2 +// val y = (height - backgroundHeight) / 2 +// drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight) +// } +// +// @ExperimentalUnsignedTypes +// fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) { +// if (!handler.isBufferSlot(slot.id)) { +// return +// } +// +// val mode = handler.terminal.internalBuffer.getMode(slot.id - handler.bufferSlotsStart) +// val color: UInt = when (mode) { +// TerminalBufferInventory.Mode.TO_NETWORK -> 0xFFFF0000u +// TerminalBufferInventory.Mode.FROM_NETWORK -> 0xFF00FF00u +// else -> return +// } +// DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt()) +// } +// +//} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreenHandler.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreenHandler.kt index 76af6ee..d33b4f0 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreenHandler.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreenHandler.kt @@ -1,161 +1,161 @@ package net.shadowfacts.phycon.network.block.terminal - -import net.minecraft.screen.slot.Slot -import net.minecraft.screen.slot.SlotActionType -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.entity.player.PlayerInventory -import net.minecraft.item.ItemStack -import net.minecraft.network.PacketByteBuf -import net.minecraft.screen.ScreenHandler -import net.minecraft.util.Identifier -import net.shadowfacts.phycon.PhysicalConnectivity -import net.shadowfacts.phycon.init.PhyBlocks -import net.shadowfacts.phycon.init.PhyScreens -import kotlin.math.ceil -import kotlin.math.min - -/** - * @author shadowfacts - */ -class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL_SCREEN_HANDLER, syncId) { - - companion object { - val ID = Identifier(PhysicalConnectivity.MODID, "terminal") - } - - constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf): - this(syncId, playerInv, PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!) - - init { - // network - for (y in 0 until 6) { - for (x in 0 until 9) { - addSlot(TerminalFakeSlot(terminal, y * 9 + x, 66 + x * 18, 18 + y * 18)) - } - } - - // internal buffer - for (y in 0 until 6) { - for (x in 0 until 3) { - addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18)) - } - } - - // player inv - for (y in 0 until 3) { - for (x in 0 until 9) { - addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18)) - } - } - // hotbar - for (x in 0 until 9) { - addSlot(Slot(playerInv, x, 66 + x * 18, 198)) - } - } - - override fun canUse(player: PlayerEntity): Boolean { - return true - } - - override fun close(player: PlayerEntity) { - super.close(player) - - terminal.removeObserver() - } - - override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack { - if (isNetworkSlot(slotId)) { - // the slot clicked was one of the network stacks - if (actionType == SlotActionType.QUICK_MOVE) { - val stack = slots[slotId].stack - if (!stack.isEmpty && !player.world.isClient) { - terminal.requestItem(stack, min(stack.count, stack.maxCount)) - } - } else if (actionType == SlotActionType.PICKUP && clickData == 1) { - if (clickData == 1) { - // right click, request half stack - val stack = slots[slotId].stack - if (!stack.isEmpty && !player.world.isClient) { - terminal.requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt()) - } - } else { - // todo: left click, show amount dialog - } - } - return ItemStack.EMPTY - } else if (isBufferSlot(slotId)) { - // internal buffer - // todo: why does this think it's quick_craft sometimes? - if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) { - // placing cursor stack into buffer - val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index - terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK) - } - } - return super.onSlotClick(slotId, clickData, actionType, player) - } - - override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack { - if (isNetworkSlot(slotId)) { - return ItemStack.EMPTY; - } - - val slot = slots[slotId] - if (!slot.hasStack()) { - return ItemStack.EMPTY - } - - val result = slot.stack.copy() - - if (isBufferSlot(slotId)) { - if (!insertItem(slot.stack, playerSlotsStart, playerSlotsEnd, false)) { - return ItemStack.EMPTY - } - if (slot.stack.isEmpty) { - terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED) - } - } else if (isPlayerSlot(slotId)) { - val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK } - slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) } - if (slot.stack.isEmpty) { - return ItemStack.EMPTY - } - } - - return result - } - - private fun tryInsertItem(stack: ItemStack, slots: IntRange, slotPredicate: (Int) -> Boolean): Collection { - val slotsInsertedInto = mutableListOf() - for (index in slots) { - if (stack.isEmpty) break - if (!slotPredicate(index)) continue - - val slot = this.slots[index] - val slotStack = slot.stack - if (slotStack.isEmpty) { - slot.stack = stack.copy() - stack.count = 0 - - slot.markDirty() - slotsInsertedInto.add(index) - } else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) { - val maxToMove = slotStack.maxCount - slotStack.count - val toMove = min(maxToMove, stack.count) - slotStack.increment(toMove) - stack.decrement(toMove) - - slot.markDirty() - slotsInsertedInto.add(index) - } - } - return slotsInsertedInto - } - - val bufferSlotsStart = 54 - val playerSlotsStart = 72 - val playerSlotsEnd = 72 + 36 - fun isNetworkSlot(id: Int) = id in 0 until bufferSlotsStart - fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart - fun isPlayerSlot(id: Int) = id >= playerSlotsStart -} +// +//import net.minecraft.screen.slot.Slot +//import net.minecraft.screen.slot.SlotActionType +//import net.minecraft.entity.player.PlayerEntity +//import net.minecraft.entity.player.PlayerInventory +//import net.minecraft.item.ItemStack +//import net.minecraft.network.PacketByteBuf +//import net.minecraft.screen.ScreenHandler +//import net.minecraft.util.Identifier +//import net.shadowfacts.phycon.PhysicalConnectivity +//import net.shadowfacts.phycon.init.PhyBlocks +//import net.shadowfacts.phycon.init.PhyScreens +//import kotlin.math.ceil +//import kotlin.math.min +// +///** +// * @author shadowfacts +// */ +//class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL_SCREEN_HANDLER, syncId) { +// +// companion object { +// val ID = Identifier(PhysicalConnectivity.MODID, "terminal") +// } +// +// constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf): +// this(syncId, playerInv, PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!) +// +// init { +// // network +// for (y in 0 until 6) { +// for (x in 0 until 9) { +// addSlot(TerminalFakeSlot(terminal, y * 9 + x, 66 + x * 18, 18 + y * 18)) +// } +// } +// +// // internal buffer +// for (y in 0 until 6) { +// for (x in 0 until 3) { +// addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18)) +// } +// } +// +// // player inv +// for (y in 0 until 3) { +// for (x in 0 until 9) { +// addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18)) +// } +// } +// // hotbar +// for (x in 0 until 9) { +// addSlot(Slot(playerInv, x, 66 + x * 18, 198)) +// } +// } +// +// override fun canUse(player: PlayerEntity): Boolean { +// return true +// } +// +// override fun close(player: PlayerEntity) { +// super.close(player) +// +// terminal.removeObserver() +// } +// +// override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack { +// if (isNetworkSlot(slotId)) { +// // the slot clicked was one of the network stacks +// if (actionType == SlotActionType.QUICK_MOVE) { +// val stack = slots[slotId].stack +// if (!stack.isEmpty && !player.world.isClient) { +// terminal.requestItem(stack, min(stack.count, stack.maxCount)) +// } +// } else if (actionType == SlotActionType.PICKUP && clickData == 1) { +// if (clickData == 1) { +// // right click, request half stack +// val stack = slots[slotId].stack +// if (!stack.isEmpty && !player.world.isClient) { +// terminal.requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt()) +// } +// } else { +// // todo: left click, show amount dialog +// } +// } +// return ItemStack.EMPTY +// } else if (isBufferSlot(slotId)) { +// // internal buffer +// // todo: why does this think it's quick_craft sometimes? +// if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) { +// // placing cursor stack into buffer +// val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index +// terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK) +// } +// } +// return super.onSlotClick(slotId, clickData, actionType, player) +// } +// +// override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack { +// if (isNetworkSlot(slotId)) { +// return ItemStack.EMPTY; +// } +// +// val slot = slots[slotId] +// if (!slot.hasStack()) { +// return ItemStack.EMPTY +// } +// +// val result = slot.stack.copy() +// +// if (isBufferSlot(slotId)) { +// if (!insertItem(slot.stack, playerSlotsStart, playerSlotsEnd, false)) { +// return ItemStack.EMPTY +// } +// if (slot.stack.isEmpty) { +// terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED) +// } +// } else if (isPlayerSlot(slotId)) { +// val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK } +// slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) } +// if (slot.stack.isEmpty) { +// return ItemStack.EMPTY +// } +// } +// +// return result +// } +// +// private fun tryInsertItem(stack: ItemStack, slots: IntRange, slotPredicate: (Int) -> Boolean): Collection { +// val slotsInsertedInto = mutableListOf() +// for (index in slots) { +// if (stack.isEmpty) break +// if (!slotPredicate(index)) continue +// +// val slot = this.slots[index] +// val slotStack = slot.stack +// if (slotStack.isEmpty) { +// slot.stack = stack.copy() +// stack.count = 0 +// +// slot.markDirty() +// slotsInsertedInto.add(index) +// } else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) { +// val maxToMove = slotStack.maxCount - slotStack.count +// val toMove = min(maxToMove, stack.count) +// slotStack.increment(toMove) +// stack.decrement(toMove) +// +// slot.markDirty() +// slotsInsertedInto.add(index) +// } +// } +// return slotsInsertedInto +// } +// +// val bufferSlotsStart = 54 +// val playerSlotsStart = 72 +// val playerSlotsEnd = 72 + 36 +// fun isNetworkSlot(id: Int) = id in 0 until bufferSlotsStart +// fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart +// fun isPlayerSlot(id: Int) = id >= playerSlotsStart +//} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlock.kt new file mode 100644 index 0000000..66e1a81 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlock.kt @@ -0,0 +1,51 @@ +package net.shadowfacts.phycon.network.block.test + +import net.minecraft.block.BlockState +import net.minecraft.block.Material +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import net.minecraft.util.Identifier +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import net.minecraft.world.BlockView +import net.minecraft.world.World +import net.shadowfacts.phycon.PhysicalConnectivity +import net.shadowfacts.phycon.api.Interface +import net.shadowfacts.phycon.network.DeviceBlock +import java.util.* + +/** + * @author shadowfacts + */ +class DestBlock: DeviceBlock(Settings.of(Material.METAL)) { + + companion object { + val ID = Identifier(PhysicalConnectivity.MODID, "dest") + } + + override fun createBlockEntity(world: BlockView): DestBlockEntity { + return DestBlockEntity() + } + + override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): MutableCollection { + 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( + blockState: BlockState?, + world: World, + pos: BlockPos, + playerEntity: PlayerEntity?, + hand: Hand?, + blockHitResult: BlockHitResult? + ): ActionResult { + println("dest IP: ${getBlockEntity(world, pos)!!.ipAddress}") + return ActionResult.SUCCESS + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlockEntity.kt new file mode 100644 index 0000000..b60feb8 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/DestBlockEntity.kt @@ -0,0 +1,38 @@ +package net.shadowfacts.phycon.network.block.test + +import net.minecraft.util.math.Direction +import net.shadowfacts.phycon.api.Interface +import net.shadowfacts.phycon.api.frame.EthernetFrame +import net.shadowfacts.phycon.api.packet.Packet +import net.shadowfacts.phycon.init.PhyBlockEntities +import net.shadowfacts.phycon.network.BaseInterface +import net.shadowfacts.phycon.network.DeviceBlockEntity +import net.shadowfacts.phycon.network.NetworkUtil + +/** + * @author shadowfacts + */ +class DestBlockEntity: DeviceBlockEntity(PhyBlockEntities.DEST) { + + override val interfaces = listOf(BaseInterface(this)) + + override fun handle(packet: Packet, itf: Interface) { + println("$this ($ipAddress) received packet: $packet") + } + + override fun handle(frame: EthernetFrame, fromItf: 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()) { + val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir) + if (itf != null) { + return itf + } + } + return null + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlock.kt new file mode 100644 index 0000000..21f0f82 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlock.kt @@ -0,0 +1,36 @@ +package net.shadowfacts.phycon.network.block.test + +import net.minecraft.block.BlockState +import net.minecraft.block.Material +import net.minecraft.util.Identifier +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction +import net.minecraft.world.BlockView +import net.minecraft.world.World +import net.shadowfacts.phycon.PhysicalConnectivity +import net.shadowfacts.phycon.api.Interface +import net.shadowfacts.phycon.network.DeviceBlock +import java.util.* + +/** + * @author shadowfacts + */ +class SourceBlock: DeviceBlock(Settings.of(Material.METAL)) { + + companion object { + val ID = Identifier(PhysicalConnectivity.MODID, "source") + } + + override fun createBlockEntity(world: BlockView): SourceBlockEntity { + return SourceBlockEntity() + } + + override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): MutableCollection { + return EnumSet.allOf(Direction::class.java) + } + + override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? { + return getBlockEntity(world, pos)!!.interfaces.first() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlockEntity.kt new file mode 100644 index 0000000..2aaeb29 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/SourceBlockEntity.kt @@ -0,0 +1,50 @@ +package net.shadowfacts.phycon.network.block.test + +import net.minecraft.util.Tickable +import net.minecraft.util.math.Direction +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.util.IPAddress +import net.shadowfacts.phycon.init.PhyBlockEntities +import net.shadowfacts.phycon.network.BaseInterface +import net.shadowfacts.phycon.network.DeviceBlockEntity +import net.shadowfacts.phycon.network.NetworkUtil +import net.shadowfacts.phycon.network.frame.BaseFrame + +/** + * @author shadowfacts + */ +class SourceBlockEntity: DeviceBlockEntity(PhyBlockEntities.SOURCE), Tickable { + + override val interfaces = listOf(BaseInterface(this)) + + override fun handle(packet: Packet, itf: Interface) { + 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() { + super.tick() + if (!world!!.isClient && counter % 40 == 0L) { + sendPacket(TestPacket(ipAddress, IPAddress(67, 237, 255, 168))) + } + } + + override fun findDestination(fromItf: Interface): Interface? { + for (dir in Direction.values()) { + val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir) + if (itf != null) { + return itf + } + } + return null + } + +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/test/TestPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/TestPacket.kt new file mode 100644 index 0000000..dab1800 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/test/TestPacket.kt @@ -0,0 +1,10 @@ +package net.shadowfacts.phycon.network.block.test + +import net.shadowfacts.phycon.api.util.IPAddress +import net.shadowfacts.phycon.network.packet.BasePacket + +/** + * @author shadowfacts + */ +class TestPacket(source: IPAddress, destination: IPAddress): BasePacket(source, destination) { +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/component/ItemStackPacketHandler.kt b/src/main/kotlin/net/shadowfacts/phycon/network/component/ItemStackPacketHandler.kt index 7ea9fe9..dbff04d 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/component/ItemStackPacketHandler.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/component/ItemStackPacketHandler.kt @@ -26,6 +26,6 @@ fun BE.handleItemStack(packet: ItemStackPacket) where BE: BlockEntity, BE: val remainder = doHandleItemStack(packet) // if there are any items remaining, send them back to the source with incremented bounce count if (!remainder.isEmpty) { - sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source)) +// sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source)) } } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/frame/ARPFrame.kt b/src/main/kotlin/net/shadowfacts/phycon/network/frame/ARPFrame.kt new file mode 100644 index 0000000..f87c161 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/frame/ARPFrame.kt @@ -0,0 +1,22 @@ +package net.shadowfacts.phycon.network.frame + +import net.shadowfacts.phycon.api.util.IPAddress +import net.shadowfacts.phycon.api.util.MACAddress + +/** + * @author shadowfacts + */ +class ARPQueryFrame( + val queryIP: IPAddress, + val sourceIP: IPAddress, + source: MACAddress, +): BaseFrame(source, MACAddress.BROADCAST) { +} + + +class ARPResponseFrame( + val query: IPAddress, + source: MACAddress, + destination: MACAddress, +): BaseFrame(source, destination) { +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/frame/BaseFrame.kt b/src/main/kotlin/net/shadowfacts/phycon/network/frame/BaseFrame.kt new file mode 100644 index 0000000..e5948af --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/frame/BaseFrame.kt @@ -0,0 +1,17 @@ +package net.shadowfacts.phycon.network.frame + +import net.shadowfacts.phycon.api.frame.EthernetFrame +import net.shadowfacts.phycon.api.frame.PacketFrame +import net.shadowfacts.phycon.api.packet.Packet +import net.shadowfacts.phycon.api.util.MACAddress + +/** + * @author shadowfacts + */ +open class BaseFrame( + @JvmField private val source: MACAddress, + @JvmField private val destination: MACAddress +): EthernetFrame { + override fun getSource() = source + override fun getDestination() = destination +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/frame/BasePacketFrame.kt b/src/main/kotlin/net/shadowfacts/phycon/network/frame/BasePacketFrame.kt new file mode 100644 index 0000000..c7f6458 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/frame/BasePacketFrame.kt @@ -0,0 +1,16 @@ +package net.shadowfacts.phycon.network.frame + +import net.shadowfacts.phycon.api.frame.PacketFrame +import net.shadowfacts.phycon.api.packet.Packet +import net.shadowfacts.phycon.api.util.MACAddress + +/** + * @author shadowfacts + */ +class BasePacketFrame( + @JvmField private val packet: Packet, + source: MACAddress, + destination: MACAddress, +): BaseFrame(source, destination), PacketFrame { + override fun getPacket() = packet +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/BasePacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/BasePacket.kt index d0a0715..04147c4 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/BasePacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/BasePacket.kt @@ -1,14 +1,14 @@ package net.shadowfacts.phycon.network.packet import net.shadowfacts.phycon.api.packet.Packet -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ abstract class BasePacket( - @JvmField private val source: MACAddress, - @JvmField private val destination: MACAddress + @JvmField private val source: IPAddress, + @JvmField private val destination: IPAddress ): Packet { override fun getSource() = source diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/CapacityPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/CapacityPacket.kt index f190743..4f0f5f2 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/CapacityPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/CapacityPacket.kt @@ -1,11 +1,11 @@ package net.shadowfacts.phycon.network.packet import net.minecraft.item.ItemStack -import net.shadowfacts.phycon.api.util.MACAddress -import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity +import net.shadowfacts.phycon.api.util.IPAddress +//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity /** * @author shadowfacts */ -class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: MACAddress, destination: MACAddress): BasePacket(source, destination) { -} \ No newline at end of file +//class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: IPAddress, destination: IPAddress): BasePacket(source, destination) { +//} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/CheckCapacityPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/CheckCapacityPacket.kt index 3c14bd0..924c130 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/CheckCapacityPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/CheckCapacityPacket.kt @@ -1,10 +1,10 @@ package net.shadowfacts.phycon.network.packet import net.minecraft.item.ItemStack -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ -class CheckCapacityPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress): BasePacket(source, destination) { +class CheckCapacityPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress): BasePacket(source, destination) { } \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/DeviceRemovedPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/DeviceRemovedPacket.kt index fa576c6..8a5f61d 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/DeviceRemovedPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/DeviceRemovedPacket.kt @@ -1,11 +1,11 @@ package net.shadowfacts.phycon.network.packet -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress import net.shadowfacts.phycon.network.DeviceBlockEntity /** * @author shadowfacts */ -class DeviceRemovedPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) { - constructor(device: DeviceBlockEntity): this(device.macAddress) +class DeviceRemovedPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) { + constructor(device: DeviceBlockEntity): this(device.ipAddress) } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ExtractStackPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ExtractStackPacket.kt index 96d678a..8b8e748 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ExtractStackPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ExtractStackPacket.kt @@ -1,10 +1,10 @@ package net.shadowfacts.phycon.network.packet import net.minecraft.item.ItemStack -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ -class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) { +class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) { } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ItemStackPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ItemStackPacket.kt index a65ca2c..67f03dd 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ItemStackPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ItemStackPacket.kt @@ -1,11 +1,11 @@ package net.shadowfacts.phycon.network.packet import net.minecraft.item.ItemStack -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ -class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) { - constructor(stack: ItemStack, source: MACAddress, destination: MACAddress): this(stack, 0, source, destination) +class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) { + constructor(stack: ItemStack, source: IPAddress, destination: IPAddress): this(stack, 0, source, destination) } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/LocateStackPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/LocateStackPacket.kt index e6c77a7..69bdeae 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/LocateStackPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/LocateStackPacket.kt @@ -1,10 +1,10 @@ package net.shadowfacts.phycon.network.packet import net.minecraft.item.ItemStack -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ -class LocateStackPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) { +class LocateStackPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) { } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt index 7423ab6..ee59f44 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/ReadInventoryPacket.kt @@ -1,13 +1,13 @@ package net.shadowfacts.phycon.network.packet import alexiil.mc.lib.attributes.item.GroupedItemInv -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ class ReadInventoryPacket( val inventory: GroupedItemInv, - source: MACAddress, - destination: MACAddress + source: IPAddress, + destination: IPAddress ): BasePacket(source, destination) diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/RequestInventoryPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/RequestInventoryPacket.kt index 654f74e..64b3a3a 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/RequestInventoryPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/RequestInventoryPacket.kt @@ -1,8 +1,8 @@ package net.shadowfacts.phycon.network.packet -import net.shadowfacts.phycon.api.util.MACAddress +import net.shadowfacts.phycon.api.util.IPAddress /** * @author shadowfacts */ -class RequestInventoryPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) +class RequestInventoryPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/packet/StackLocationPacket.kt b/src/main/kotlin/net/shadowfacts/phycon/network/packet/StackLocationPacket.kt index 7aff100..710446a 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/packet/StackLocationPacket.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/packet/StackLocationPacket.kt @@ -1,18 +1,18 @@ package net.shadowfacts.phycon.network.packet import net.minecraft.item.ItemStack -import net.shadowfacts.phycon.api.util.MACAddress -import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity +import net.shadowfacts.phycon.api.util.IPAddress +//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity /** * @author shadowfacts */ // todo: better name with LocateStackPacket -class StackLocationPacket( - val stack: ItemStack, - val amount: Int, - val sourceInterface: InterfaceBlockEntity, - source: MACAddress, - destination: MACAddress -): BasePacket(source, destination) { -} +//class StackLocationPacket( +// val stack: ItemStack, +// val amount: Int, +// val sourceInterface: InterfaceBlockEntity, +// source: IPAddress, +// destination: IPAddress +//): BasePacket(source, destination) { +//}