Implement layer 3 networking

This commit is contained in:
Shadowfacts 2021-02-13 18:24:36 -05:00
parent 26134cea9d
commit e8425b80fd
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
53 changed files with 1764 additions and 1059 deletions

View File

@ -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);
}

View File

@ -3,6 +3,6 @@ package net.shadowfacts.phycon.api;
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
public interface NetworkCable extends NetworkComponent { public interface NetworkCableBlock extends NetworkComponentBlock {
} }

View File

@ -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<Direction> getNetworkConnectedSides(BlockState state, World world, BlockPos pos);
}

View File

@ -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<Direction> 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);
}

View File

@ -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();
}

View File

@ -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<ItemStack, Integer> readAll();
}

View File

@ -1,17 +1,16 @@
package net.shadowfacts.phycon.api; package net.shadowfacts.phycon.api;
import net.shadowfacts.phycon.api.packet.Packet; import net.shadowfacts.phycon.api.packet.Packet;
import net.shadowfacts.phycon.api.util.MACAddress;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
public interface PacketSink { public interface PacketSink extends NetworkDevice {
@NotNull @NotNull
MACAddress getMACAddress(); Iterable<Interface> getDeviceInterfaces();
void handle(@NotNull Packet packet); void handle(@NotNull Packet packet, @NotNull Interface itf);
} }

View File

@ -1,15 +1,18 @@
package net.shadowfacts.phycon.api; package net.shadowfacts.phycon.api;
import net.shadowfacts.phycon.api.packet.Packet; import net.shadowfacts.phycon.api.packet.Packet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
public interface PacketSource { // todo: does PacketSource actually need to extend NetworkDevice?
public interface PacketSource extends NetworkDevice {
// todo: better name for this // todo: better name for this
void sendToSingle(Packet packet); void sendPacket(@NotNull Packet packet, @Nullable Interface itf);
void sendToAll(Packet packet); // void sendToAll(@NotNull Packet packet);
//
void sendToAll(Packet packet, Iterable<PacketSink> destinations); // void sendToAll(@NotNull Packet packet, @NotNull Iterable<PacketSink> destinations);
} }

View File

@ -9,6 +9,5 @@ import alexiil.mc.lib.attributes.Attributes;
public class PhyAttributes { public class PhyAttributes {
public static final Attribute<PacketSink> PACKET_SINK = Attributes.create(PacketSink.class); public static final Attribute<PacketSink> PACKET_SINK = Attributes.create(PacketSink.class);
public static final Attribute<NetworkInterface> NETWORK_INTERFACE = Attributes.create(NetworkInterface.class);
} }

View File

@ -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();
}

View File

@ -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();
}

View File

@ -1,6 +1,6 @@
package net.shadowfacts.phycon.api.packet; 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; import org.jetbrains.annotations.NotNull;
/** /**
@ -9,9 +9,9 @@ import org.jetbrains.annotations.NotNull;
public interface Packet { public interface Packet {
@NotNull @NotNull
MACAddress getSource(); IPAddress getSource();
@NotNull @NotNull
MACAddress getDestination(); IPAddress getDestination();
} }

View File

@ -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();
}
}

View File

@ -15,12 +15,14 @@ public final class MACAddress {
public static final MACAddress BROADCAST = new MACAddress(0xffffffffffffL); public static final MACAddress BROADCAST = new MACAddress(0xffffffffffffL);
@NotNull
public static MACAddress random(Random random) { public static MACAddress random(Random random) {
long value = random.nextLong() & 0xfeffffffffffL; long value = random.nextLong() & 0xfeffffffffffL;
return new MACAddress(value); return new MACAddress(value);
} }
private static final Random macAddressRandom = new Random(); private static final Random macAddressRandom = new Random();
@NotNull
public static MACAddress random() { public static MACAddress random() {
return random(macAddressRandom); return random(macAddressRandom);
} }

View File

@ -3,7 +3,7 @@ package net.shadowfacts.phycon.mixin.client;
import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot; 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.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; 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")) @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) { private void drawSlot(MatrixStack matrixStack, Slot slot, CallbackInfo ci) {
if ((Object)this instanceof TerminalScreen) { // if ((Object)this instanceof TerminalScreen) {
TerminalScreen self = (TerminalScreen)(Object)this; // TerminalScreen self = (TerminalScreen)(Object)this;
self.drawSlotUnderlay(matrixStack, slot); // self.drawSlotUnderlay(matrixStack, slot);
} // }
} }
} }

View File

@ -6,7 +6,7 @@ import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
import net.minecraft.client.render.RenderLayer import net.minecraft.client.render.RenderLayer
import net.shadowfacts.phycon.init.PhyBlocks import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyScreens import net.shadowfacts.phycon.init.PhyScreens
import net.shadowfacts.phycon.network.block.terminal.TerminalScreen //import net.shadowfacts.phycon.network.block.terminal.TerminalScreen
/** /**
* @author shadowfacts * @author shadowfacts
@ -15,6 +15,6 @@ object PhysicalConnectivityClient: ClientModInitializer {
override fun onInitializeClient() { override fun onInitializeClient() {
BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent()) BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent())
ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen) // ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen)
} }
} }

View File

@ -5,30 +5,39 @@ import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType import net.minecraft.block.entity.BlockEntityType
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock import net.shadowfacts.phycon.network.block.test.DestBlock
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity 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 * @author shadowfacts
*/ */
object PhyBlockEntities { object PhyBlockEntities {
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE) // val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL) // val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH) val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE)
val DEST = create(::DestBlockEntity, PhyBlocks.DEST)
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> { private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
return BlockEntityType.Builder.create(builder, arrayOf(block)).build(null) return BlockEntityType.Builder.create(builder, block).build(null)
} }
fun init() { fun init() {
register(InterfaceBlock.ID, INTERFACE) // register(InterfaceBlock.ID, INTERFACE)
register(TerminalBlock.ID, TERMINAL) // register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH) register(SwitchBlock.ID, SWITCH)
register(SourceBlock.ID, SOURCE)
register(DestBlock.ID, DEST)
} }
private fun register(id: Identifier, type: BlockEntityType<*>) { private fun register(id: Identifier, type: BlockEntityType<*>) {

View File

@ -4,25 +4,29 @@ import net.minecraft.block.Block
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.network.block.cable.CableBlock 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.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 * @author shadowfacts
*/ */
object PhyBlocks { object PhyBlocks {
val INTERFACE = InterfaceBlock() // val INTERFACE = InterfaceBlock()
val TERMINAL = TerminalBlock() // val TERMINAL = TerminalBlock()
val SWITCH = SwitchBlock() val SWITCH = SwitchBlock()
val CABLE = CableBlock() val CABLE = CableBlock()
val SOURCE = SourceBlock()
val DEST = DestBlock()
fun init() { fun init() {
register(InterfaceBlock.ID, INTERFACE) // register(InterfaceBlock.ID, INTERFACE)
register(TerminalBlock.ID, TERMINAL) // register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH) register(SwitchBlock.ID, SWITCH)
register(CableBlock.ID, CABLE) register(CableBlock.ID, CABLE)
register(SourceBlock.ID, SOURCE)
register(DestBlock.ID, DEST)
} }
private fun register(id: Identifier, block: Block) { private fun register(id: Identifier, block: Block) {

View File

@ -6,27 +6,34 @@ import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.item.ScrewdriverItem import net.shadowfacts.phycon.item.ScrewdriverItem
import net.shadowfacts.phycon.network.block.cable.CableBlock 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.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 * @author shadowfacts
*/ */
object PhyItems { object PhyItems {
val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings()) // val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings())
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings()) // val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings()) val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
val CABLE = BlockItem(PhyBlocks.CABLE, 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() val SCREWDRIVER = ScrewdriverItem()
fun init() { fun init() {
register(InterfaceBlock.ID, INTERFACE) // register(InterfaceBlock.ID, INTERFACE)
register(TerminalBlock.ID, TERMINAL) // register(TerminalBlock.ID, TERMINAL)
register(SwitchBlock.ID, SWITCH) register(SwitchBlock.ID, SWITCH)
register(CableBlock.ID, CABLE) register(CableBlock.ID, CABLE)
register(SourceBlock.ID, SOURCE)
register(DestBlock.ID, DEST)
register(ScrewdriverItem.ID, SCREWDRIVER) register(ScrewdriverItem.ID, SCREWDRIVER)
} }

View File

@ -3,10 +3,10 @@ package net.shadowfacts.phycon.init
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler //import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
object PhyScreens { object PhyScreens {
val TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler) // val TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler)
} }

View File

@ -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<InterfaceDelegate>
): Interface {
constructor(delegate: InterfaceDelegate): this(MACAddress.random(), WeakReference(delegate))
override fun getMACAddress(): MACAddress {
return macAddress
}
override fun receive(frame: EthernetFrame) {
delegate.get()?.handle(frame, this)
}
override fun send(frame: EthernetFrame) {
delegate.get()?.findDestination(this)?.receive(frame)
}
// override fun send(packet: Packet) {
// delegate.get()?.findDestination(this)?.also {
// it.receive(BaseFrame(packet, this.macAddress, it.macAddress))
// }
// }
override fun equals(other: Any?): Boolean {
return (other as? BaseInterface)?.macAddress == macAddress
}
override fun hashCode(): Int {
return macAddress.hashCode()
}
}
interface InterfaceDelegate {
fun findDestination(fromItf: Interface): Interface?
fun handle(frame: EthernetFrame, fromItf: Interface)
}

View File

@ -4,12 +4,13 @@ import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.World import net.minecraft.world.World
import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.block.BlockWithEntity import net.shadowfacts.phycon.block.BlockWithEntity
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithEntity<T>(settings) { abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithEntity<T>(settings), NetworkComponentBlock {
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) { override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
super.onBreak(world, pos, state, player) super.onBreak(world, pos, state, player)

View File

@ -1,83 +1,235 @@
package net.shadowfacts.phycon.network package net.shadowfacts.phycon.network
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType import net.minecraft.block.entity.BlockEntityType
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.util.Tickable
import net.shadowfacts.phycon.api.PacketSink import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.PacketSource 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.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.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 net.shadowfacts.phycon.network.packet.DeviceRemovedPacket
import java.lang.RuntimeException
import java.util.*
/** /**
* @author shadowfacts * @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 protected set
override fun getMACAddress(): MACAddress { open val interfaces: List<BaseInterface> = listOf()
return macAddress // abstract val itf: BaseInterface
}
override fun handle(packet: Packet) { private val arpTable = mutableMapOf<IPAddress, MACAddress>()
if (acceptsPacket(packet)) { private val packetQueue = LinkedList<PendingPacket>()
handlePacket(packet)
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) private fun handleARPQuery(frame: ARPQueryFrame, fromItf: Interface) {
println("$this ($ipAddress) received ARP query for ${frame.queryIP}")
protected open fun acceptsPacket(packet: Packet): Boolean { arpTable[frame.sourceIP] = frame.source
return when (packet.destination.type) { if (frame.queryIP == ipAddress) {
MACAddress.Type.BROADCAST -> true println("$this ($ipAddress) sending ARP response to ${frame.source} with ${fromItf.macAddress}")
MACAddress.Type.UNICAST -> macAddress == packet.destination fromItf.send(ARPResponseFrame(ipAddress, fromItf.macAddress, frame.source))
MACAddress.Type.MULTICAST -> acceptsMulticastPacket(packet)
} }
} }
open fun acceptsMulticastPacket(packet: Packet): Boolean { private fun handleARPResponse(frame: ARPResponseFrame, fromItf: Interface) {
return false arpTable[frame.query] = frame.source
} println("$this ($ipAddress) received ARP response for ${frame.query} with ${frame.source}")
fun send(packet: Packet, destination: PacketSink) { packetQueue.removeIf { (packet, itf, _) ->
destination.handle(packet) if (packet.destination == frame.query) {
} itf.send(BasePacketFrame(packet, itf.macAddress, frame.source))
true
override fun sendToSingle(packet: Packet) { } else {
val destinations = NetworkUtil.findDestinations(world!!, pos) false
if (destinations.size != 1) { }
// todo: handle this better
println("Can't send packet, multiple destinations available: $destinations")
return
} }
send(packet, destinations.first())
} }
override fun sendToAll(packet: Packet) { // protected abstract fun handlePacket(packet: Packet, itf: Interface)
sendToAll(packet, NetworkUtil.findDestinations(world!!, pos)) //
// 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<PacketSink>) { override fun sendPacket(packet: Packet, itf: Interface?) {
destinations.forEach { @Suppress("NAME_SHADOWING") var itf = itf
it.handle(packet) 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<PacketSink>) {
// 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 { 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) return super.toTag(tag)
} }
override fun fromTag(state: BlockState, tag: CompoundTag) { override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag) super.fromTag(state, tag)
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() { fun onBreak() {
sendToAll(DeviceRemovedPacket(this)) sendPacket(DeviceRemovedPacket(this))
} }
data class PendingPacket(
val packet: Packet,
val sourceItf: Interface,
var timestamp: Long,
)
} }

View File

@ -3,10 +3,7 @@ package net.shadowfacts.phycon.network
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction import net.minecraft.util.math.Direction
import net.minecraft.world.World import net.minecraft.world.World
import net.shadowfacts.phycon.api.NetworkCable import net.shadowfacts.phycon.api.*
import net.shadowfacts.phycon.api.NetworkComponent
import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.PhyAttributes
import java.util.* import java.util.*
/** /**
@ -14,6 +11,28 @@ import java.util.*
*/ */
object NetworkUtil { 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<PacketSink> { fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List<PacketSink> {
val results = LinkedList<PacketSink>() val results = LinkedList<PacketSink>()
val visited = hashSetOf(startPos) val visited = hashSetOf(startPos)
@ -43,7 +62,7 @@ object NetworkUtil {
private fun findEdges(queue: MutableList<BlockPos>, visited: Set<BlockPos>, world: World, pos: BlockPos, includeNonCables: Boolean = false) { private fun findEdges(queue: MutableList<BlockPos>, visited: Set<BlockPos>, world: World, pos: BlockPos, includeNonCables: Boolean = false) {
val state = world.getBlockState(pos) val state = world.getBlockState(pos)
val block = state.block 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) val connections = block.getNetworkConnectedSides(state, world, pos)
for (side in connections) { for (side in connections) {
val newPos = pos.offset(side) val newPos = pos.offset(side)

View File

@ -19,8 +19,9 @@ import net.minecraft.world.BlockView
import net.minecraft.world.World import net.minecraft.world.World
import net.minecraft.world.WorldAccess import net.minecraft.world.WorldAccess
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.NetworkCable import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkComponent import net.shadowfacts.phycon.api.NetworkCableBlock
import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.init.PhyItems import net.shadowfacts.phycon.init.PhyItems
import net.shadowfacts.phycon.util.CableConnection import net.shadowfacts.phycon.util.CableConnection
import java.util.* import java.util.*
@ -31,7 +32,7 @@ import java.util.*
class CableBlock: Block( class CableBlock: Block(
Settings.of(CABLE_MATERIAL) Settings.of(CABLE_MATERIAL)
.nonOpaque() .nonOpaque()
), NetworkCable { ), NetworkCableBlock {
companion object { companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "cable") val ID = Identifier(PhysicalConnectivity.MODID, "cable")
val CABLE_MATERIAL = Material(MaterialColor.IRON, false, false, true, false, true, false, PistonBehavior.NORMAL) val CABLE_MATERIAL = Material(MaterialColor.IRON, false, false, true, false, true, false, PistonBehavior.NORMAL)
@ -108,11 +109,16 @@ class CableBlock: Block(
else -> CableConnection.ON else -> CableConnection.ON
} }
} }
is NetworkComponent -> CableConnection.ON is NetworkComponentBlock -> CableConnection.ON
else -> CableConnection.OFF 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( override fun onUse(
state: BlockState, state: BlockState,
world: World, world: World,
@ -141,7 +147,7 @@ class CableBlock: Block(
world.setBlockState(connectedToPos, connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON)) 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) else -> state.with(prop, CableConnection.DISABLED)
} }

View File

@ -1,120 +1,128 @@
package net.shadowfacts.phycon.network.block.netinterface package net.shadowfacts.phycon.network.block.netinterface
//
import alexiil.mc.lib.attributes.AttributeList //import alexiil.mc.lib.attributes.AttributeList
import alexiil.mc.lib.attributes.AttributeProvider //import alexiil.mc.lib.attributes.AttributeProvider
import net.minecraft.block.Block //import net.minecraft.block.Block
import net.minecraft.block.BlockState //import net.minecraft.block.BlockState
import net.minecraft.block.Material //import net.minecraft.block.Material
import net.minecraft.block.ShapeContext //import net.minecraft.block.ShapeContext
import net.minecraft.entity.LivingEntity //import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemPlacementContext //import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack //import net.minecraft.item.ItemStack
import net.minecraft.state.StateManager //import net.minecraft.state.StateManager
import net.minecraft.state.property.EnumProperty //import net.minecraft.state.property.EnumProperty
import net.minecraft.state.property.Properties //import net.minecraft.state.property.Properties
import net.minecraft.util.Identifier //import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos //import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction //import net.minecraft.util.math.Direction
import net.minecraft.util.shape.VoxelShape //import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes //import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView //import net.minecraft.world.BlockView
import net.minecraft.world.World //import net.minecraft.world.World
import net.minecraft.world.WorldAccess //import net.minecraft.world.WorldAccess
import net.shadowfacts.phycon.PhysicalConnectivity //import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.NetworkComponent //import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.block.BlockWithEntity //import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.network.block.cable.CableBlock //import net.shadowfacts.phycon.block.BlockWithEntity
import java.util.* //import net.shadowfacts.phycon.network.block.cable.CableBlock
//import java.util.*
/** //
* @author shadowfacts ///**
*/ // * @author shadowfacts
class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider { // */
companion object { //class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material.METAL)),
val ID = Identifier(PhysicalConnectivity.MODID, "network_interface") // NetworkComponentBlock,
val FACING = Properties.FACING // AttributeProvider {
val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java) //
private val SIDE_SHAPES = mapOf<Direction, VoxelShape>( // companion object {
Direction.DOWN to createCuboidShape(2.0, 0.0, 2.0, 14.0, 2.0, 14.0), // val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
Direction.UP to createCuboidShape(2.0, 14.0, 2.0, 14.0, 16.0, 14.0), // val FACING = Properties.FACING
Direction.NORTH to createCuboidShape(2.0, 2.0, 0.0, 14.0, 14.0, 2.0), // val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java)
Direction.SOUTH to createCuboidShape(2.0, 2.0, 14.0, 14.0, 14.0, 16.0), // private val SIDE_SHAPES = mapOf<Direction, VoxelShape>(
Direction.WEST to createCuboidShape(0.0, 2.0, 2.0, 2.0, 14.0, 14.0), // Direction.DOWN to createCuboidShape(2.0, 0.0, 2.0, 14.0, 2.0, 14.0),
Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.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),
private val CENTER_SHAPES = mapOf<Direction, VoxelShape>( // Direction.SOUTH to createCuboidShape(2.0, 2.0, 14.0, 14.0, 14.0, 16.0),
Direction.DOWN to createCuboidShape(6.0, 2.0, 6.0, 10.0, 10.0, 10.0), // Direction.WEST to createCuboidShape(0.0, 2.0, 2.0, 2.0, 14.0, 14.0),
Direction.UP to createCuboidShape(6.0, 6.0, 6.0, 10.0, 14.0, 10.0), // Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.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), // private val CENTER_SHAPES = mapOf<Direction, VoxelShape>(
Direction.WEST to createCuboidShape(2.0, 6.0, 6.0, 10.0, 10.0, 10.0), // Direction.DOWN to createCuboidShape(6.0, 2.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) // 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),
private val shapeCache = mutableMapOf<Pair<Direction, Direction>, VoxelShape>() // Direction.WEST to createCuboidShape(2.0, 6.0, 6.0, 10.0, 10.0, 10.0),
fun getShape(facing: Direction, cableConnection: Direction): VoxelShape { // Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 14.0, 10.0, 10.0)
return shapeCache.getOrPut(facing to cableConnection) { // )
VoxelShapes.union( //
VoxelShapes.union(SIDE_SHAPES[facing], CENTER_SHAPES[facing]), // private val shapeCache = mutableMapOf<Pair<Direction, Direction>, VoxelShape>()
CableBlock.SIDE_SHAPES[cableConnection] // 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<Direction> { // }
return EnumSet.of(state[CABLE_CONNECTION]) // }
} // }
//
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) { // override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
super.appendProperties(builder) // return EnumSet.of(state[CABLE_CONNECTION])
builder.add(FACING) // }
builder.add(CABLE_CONNECTION) //
} // override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
// return getBlockEntity(world, pos)?.deviceInterfaces?.first()
override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity() // }
//
override fun getPlacementState(context: ItemPlacementContext): BlockState { // override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite // super.appendProperties(builder)
val cableConnection = getCableConnectionSide(context.world, context.blockPos) ?: facing.opposite // builder.add(FACING)
return defaultState.with(FACING, facing).with(CABLE_CONNECTION, cableConnection) // builder.add(CABLE_CONNECTION)
} // }
//
private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? { // override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity()
for (side in Direction.values()) { //
val offsetPos = pos.offset(side) // override fun getPlacementState(context: ItemPlacementContext): BlockState {
if (world.getBlockState(offsetPos).block is NetworkComponent) { // val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
return side // val cableConnection = getCableConnectionSide(context.world, context.blockPos) ?: facing.opposite
} // return defaultState.with(FACING, facing).with(CABLE_CONNECTION, cableConnection)
} // }
return null //
} // private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? {
// for (side in Direction.values()) {
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) { // val offsetPos = pos.offset(side)
if (!world.isClient) { // if (world.getBlockState(offsetPos).block is NetworkComponentBlock) {
getBlockEntity(world, pos)!!.updateInventory() // return side
} // }
} // }
// return null
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 onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
} // 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) // override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, boolean_1: Boolean) {
} // if (!world.isClient) {
return state // getBlockEntity(world, pos)!!.updateInventory()
} // }
// }
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { //
to.offer(getBlockEntity(world, pos)) // 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)
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape { // }
return getShape(state[FACING], state[CABLE_CONNECTION]) // 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])
// }
//
//}

View File

@ -1,89 +1,93 @@
package net.shadowfacts.phycon.network.block.netinterface package net.shadowfacts.phycon.network.block.netinterface
//
import alexiil.mc.lib.attributes.SearchOptions //import alexiil.mc.lib.attributes.SearchOptions
import alexiil.mc.lib.attributes.Simulation //import alexiil.mc.lib.attributes.Simulation
import alexiil.mc.lib.attributes.item.GroupedItemInv //import alexiil.mc.lib.attributes.item.GroupedItemInv
import alexiil.mc.lib.attributes.item.ItemAttributes //import alexiil.mc.lib.attributes.item.ItemAttributes
import net.minecraft.item.ItemStack //import net.minecraft.item.ItemStack
import net.minecraft.util.math.Direction //import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.packet.Packet //import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.init.PhyBlockEntities //import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.network.DeviceBlockEntity //import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler //import net.shadowfacts.phycon.network.BaseInterface
import net.shadowfacts.phycon.network.component.handleItemStack //import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.packet.* //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 { // * @author shadowfacts
// */
private val facing: Direction //class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler {
get() = world!!.getBlockState(pos)[InterfaceBlock.FACING] //
// override val interfaces = listOf(BaseInterface(this))
// todo: should this be a weak ref? //
private var inventory: GroupedItemInv? = null // private val facing: Direction
// get() = world!!.getBlockState(pos)[InterfaceBlock.FACING]
fun updateInventory() { //
val offsetPos = pos.offset(facing) // // todo: should this be a weak ref?
val option = SearchOptions.inDirection(facing) // private var inventory: GroupedItemInv? = null
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option) //
} // fun updateInventory() {
// val offsetPos = pos.offset(facing)
private fun getInventory(): GroupedItemInv? { // val option = SearchOptions.inDirection(facing)
// if we don't have an inventory, try to get one // inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option)
// this happens when readAll is called before a neighbor state changes, such as immediately after world load // }
if (inventory == null) updateInventory() //
return inventory // 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
override fun handlePacket(packet: Packet) { // if (inventory == null) updateInventory()
when (packet) { // return inventory
is RequestInventoryPacket -> handleRequestInventory(packet) // }
is LocateStackPacket -> handleLocateStack(packet) //
is ExtractStackPacket -> handleExtractStack(packet) // override fun handle(packet: Packet, itf: Interface) {
is CheckCapacityPacket -> handleCheckCapacity(packet) // when (packet) {
is ItemStackPacket -> handleItemStack(packet) // is RequestInventoryPacket -> handleRequestInventory(packet)
} // is LocateStackPacket -> handleLocateStack(packet)
} // is ExtractStackPacket -> handleExtractStack(packet)
// is CheckCapacityPacket -> handleCheckCapacity(packet)
private fun handleRequestInventory(packet: RequestInventoryPacket) { // is ItemStackPacket -> handleItemStack(packet)
getInventory()?.also { inv -> // }
sendToSingle(ReadInventoryPacket(inv, macAddress, packet.source)) // }
} //
} // private fun handleRequestInventory(packet: RequestInventoryPacket) {
// getInventory()?.also { inv ->
private fun handleLocateStack(packet: LocateStackPacket) { // sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source))
getInventory()?.also { inv -> // }
val amount = inv.getAmount(packet.stack) // }
sendToSingle(StackLocationPacket(packet.stack, amount, this, macAddress, packet.source)) //
} // private fun handleLocateStack(packet: LocateStackPacket) {
} // getInventory()?.also { inv ->
// val amount = inv.getAmount(packet.stack)
private fun handleExtractStack(packet: ExtractStackPacket) { // sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
getInventory()?.also { inv -> // }
val extracted = inv.extract(packet.stack, packet.amount) // }
sendToSingle(ItemStackPacket(extracted, macAddress, packet.source)) //
} // private fun handleExtractStack(packet: ExtractStackPacket) {
} // getInventory()?.also { inv ->
// val extracted = inv.extract(packet.stack, packet.amount)
private fun handleCheckCapacity(packet: CheckCapacityPacket) { // sendPacket(ItemStackPacket(extracted, ipAddress, packet.source))
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)) // private fun handleCheckCapacity(packet: CheckCapacityPacket) {
} // getInventory()?.also { inv ->
} // val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE)
// val couldAccept = packet.stack.count - remaining.count
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack { // sendPacket(CapacityPacket(packet.stack, couldAccept, this, ipAddress, packet.source))
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 // override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
return remaining // val inventory = getInventory()
} else { // if (inventory != null) {
return packet.stack // 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
// }
// }
//
//}

View File

@ -10,14 +10,18 @@ import net.minecraft.util.math.Direction
import net.minecraft.world.BlockView import net.minecraft.world.BlockView
import net.minecraft.world.World import net.minecraft.world.World
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.NetworkComponent import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.block.BlockWithEntity import net.shadowfacts.phycon.block.BlockWithEntity
import java.util.* import java.util.*
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider { class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)),
NetworkComponentBlock,
AttributeProvider {
companion object { companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "switch") val ID = Identifier(PhysicalConnectivity.MODID, "switch")
} }
@ -26,6 +30,10 @@ class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL
return EnumSet.allOf(Direction::class.java) return EnumSet.allOf(Direction::class.java)
} }
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
return getBlockEntity(world, pos)?.interfaces?.find { it.side == side }
}
override fun createBlockEntity(world: BlockView) = SwitchBlockEntity() override fun createBlockEntity(world: BlockView) = SwitchBlockEntity()
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {

View File

@ -1,82 +1,129 @@
package net.shadowfacts.phycon.network.block.netswitch 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.Tickable
import net.minecraft.util.math.Direction 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.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.BaseInterface
import net.shadowfacts.phycon.network.InterfaceDelegate
import net.shadowfacts.phycon.network.NetworkUtil import net.shadowfacts.phycon.network.NetworkUtil
import net.shadowfacts.phycon.network.packet.ItemStackPacket
import java.lang.RuntimeException
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class SwitchBlockEntity: DeviceBlockEntity(PhyBlockEntities.SWITCH), Tickable { class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
BlockEntityClientSerializable,
InterfaceDelegate,
Tickable {
companion object { companion object {
var SWITCHING_CAPACITY = 256 var SWITCHING_CAPACITY = 256
} }
val interfaces = Direction.values().map { SwitchInterface(it, this) }
private val macTable = mutableMapOf<MACAddress, Direction>() private val macTable = mutableMapOf<MACAddress, Direction>()
private var packetsHandledThisTick = 0 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) { fun interfaceForSide(side: Direction): SwitchInterface {
if (packetsHandledThisTick >= SWITCHING_CAPACITY) { return interfaces.find { it.side == side }!!
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++ override fun handle(frame: EthernetFrame, fromItf: Interface) {
val itfSide = (fromItf as SwitchInterface).side
macTable[frame.source] = itfSide
if (packet.destination == MACAddress.BROADCAST) { val knownDir = macTable[frame.destination]
val allDestinations = NetworkUtil.findDestinations(world!!, pos).filter { it.macAddress != packet.source } if (knownDir != null) {
sendToAll(packet, allDestinations) println("$this ($itfSide, ${fromItf.macAddress}) forwarding $frame to side $knownDir")
interfaceForSide(knownDir).send(frame)
} else { } else {
val direction = macTable[packet.destination] println("$this ($itfSide, ${fromItf.macAddress}) flooding $frame")
if (direction != null) { flood(frame, fromItf)
val dest = findDestination(direction)
if (dest != null && packet.destination == dest.macAddress) {
send(packet, dest)
return
}
}
flood(packet)
} }
} }
private fun findDestination(direction: Direction): PacketSink? { private fun flood(frame: EthernetFrame, source: Interface) {
val allDestinations = NetworkUtil.findDestinations(world!!, pos, direction) for (itf in interfaces) {
if (allDestinations.size > 1) { if (source == itf) continue
// todo: do this better itf.send(frame)
println("Can't send packet, multiple destinations: $allDestinations")
return null
} }
return allDestinations.firstOrNull()
} }
private fun flood(packet: Packet) { override fun findDestination(fromItf: Interface): Interface? {
for (dir in Direction.values()) { val side = (fromItf as SwitchInterface).side
val dest = findDestination(dir) return NetworkUtil.findConnectedInterface(world!!, pos, side)
if (dest != null && packet.destination == dest.macAddress) {
macTable[packet.destination] = dir
send(packet, dest)
break
}
}
} }
override fun tick() { override fun tick() {
packetsHandledThisTick = 0 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) {
}
} }

View File

@ -1,43 +1,44 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
//
import alexiil.mc.lib.attributes.AttributeList //import alexiil.mc.lib.attributes.AttributeList
import alexiil.mc.lib.attributes.AttributeProvider //import alexiil.mc.lib.attributes.AttributeProvider
import net.minecraft.block.BlockState //import net.minecraft.block.BlockState
import net.minecraft.block.Material //import net.minecraft.block.Material
import net.minecraft.entity.player.PlayerEntity //import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.ActionResult //import net.minecraft.util.ActionResult
import net.minecraft.util.Hand //import net.minecraft.util.Hand
import net.minecraft.util.Identifier //import net.minecraft.util.Identifier
import net.minecraft.util.hit.BlockHitResult //import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos //import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction //import net.minecraft.util.math.Direction
import net.minecraft.world.BlockView //import net.minecraft.world.BlockView
import net.minecraft.world.World //import net.minecraft.world.World
import net.shadowfacts.phycon.PhysicalConnectivity //import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.api.NetworkComponent //import net.shadowfacts.phycon.api.NetworkComponentBlock
import net.shadowfacts.phycon.block.BlockWithEntity //import net.shadowfacts.phycon.block.BlockWithEntity
import java.util.* //import java.util.*
//
/** ///**
* @author shadowfacts // * @author shadowfacts
*/ // */
class TerminalBlock: BlockWithEntity<TerminalBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider { //class TerminalBlock: BlockWithEntity<TerminalBlockEntity>(Settings.of(Material.METAL)),
companion object { // NetworkComponentBlock, AttributeProvider {
val ID = Identifier(PhysicalConnectivity.MODID, "terminal") // companion object {
} // val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
// }
override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> { //
return EnumSet.allOf(Direction::class.java) // override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
} // return EnumSet.allOf(Direction::class.java)
// }
override fun createBlockEntity(world: BlockView) = TerminalBlockEntity() //
// 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) // override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
return ActionResult.SUCCESS // getBlockEntity(world, pos)!!.onActivate(player)
} // return ActionResult.SUCCESS
// }
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { //
to.offer(getBlockEntity(world, pos)) // override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
} // to.offer(getBlockEntity(world, pos))
} // }
//}

View File

@ -1,330 +1,330 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
//
import alexiil.mc.lib.attributes.item.GroupedItemInv //import alexiil.mc.lib.attributes.item.GroupedItemInv
import alexiil.mc.lib.attributes.item.ItemStackCollections //import alexiil.mc.lib.attributes.item.ItemStackCollections
import alexiil.mc.lib.attributes.item.ItemStackUtil //import alexiil.mc.lib.attributes.item.ItemStackUtil
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap //import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable //import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory //import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
import net.minecraft.block.BlockState //import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity //import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory //import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.Inventory //import net.minecraft.inventory.Inventory
import net.minecraft.inventory.InventoryChangedListener //import net.minecraft.inventory.InventoryChangedListener
import net.minecraft.item.ItemStack //import net.minecraft.item.ItemStack
import net.minecraft.nbt.CompoundTag //import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag //import net.minecraft.nbt.ListTag
import net.minecraft.network.PacketByteBuf //import net.minecraft.network.PacketByteBuf
import net.minecraft.screen.ScreenHandler //import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity //import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.LiteralText //import net.minecraft.text.LiteralText
import net.minecraft.util.Tickable //import net.minecraft.util.Tickable
import net.shadowfacts.phycon.api.packet.Packet //import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.MACAddress //import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.init.PhyBlockEntities //import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity //import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity //import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler //import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
import net.shadowfacts.phycon.network.component.handleItemStack //import net.shadowfacts.phycon.network.component.handleItemStack
import net.shadowfacts.phycon.network.packet.* //import net.shadowfacts.phycon.network.packet.*
import java.util.* //import java.util.*
import kotlin.math.min //import kotlin.math.min
//
/** ///**
* @author shadowfacts // * @author shadowfacts
*/ // */
class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable, ItemStackPacketHandler { //class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable, ItemStackPacketHandler {
//
companion object { // companion object {
val LOCATE_REQUEST_TIMEOUT = 40 // ticks // val LOCATE_REQUEST_TIMEOUT = 40 // ticks
val INSERTION_TIMEOUT = 40 // val INSERTION_TIMEOUT = 40
} // }
//
private val inventoryCache = mutableMapOf<MACAddress, GroupedItemInv>() // private val inventoryCache = mutableMapOf<MACAddress, GroupedItemInv>()
val internalBuffer = TerminalBufferInventory(18) // val internalBuffer = TerminalBufferInventory(18)
//
private val locateRequestQueue = LinkedList<StackLocateRequest>() // private val locateRequestQueue = LinkedList<StackLocateRequest>()
private val pendingRequests = LinkedList<StackLocateRequest>() // private val pendingRequests = LinkedList<StackLocateRequest>()
private val pendingInsertions = Int2ObjectArrayMap<PendingStackInsertion>() // private val pendingInsertions = Int2ObjectArrayMap<PendingStackInsertion>()
//
private var observers = 0 // private var observers = 0
val cachedNetItems = ItemStackCollections.intMap() // val cachedNetItems = ItemStackCollections.intMap()
var cachedSortedNetItems = listOf<ItemStack>() // var cachedSortedNetItems = listOf<ItemStack>()
var counter = 0 // var counter = 0
//
init { // init {
internalBuffer.addListener(this) // internalBuffer.addListener(this)
} // }
//
override fun handlePacket(packet: Packet) { // override fun handlePacket(packet: Packet) {
when (packet) { // when (packet) {
is ReadInventoryPacket -> handleReadInventory(packet) // is ReadInventoryPacket -> handleReadInventory(packet)
is DeviceRemovedPacket -> handleDeviceRemoved(packet) // is DeviceRemovedPacket -> handleDeviceRemoved(packet)
is StackLocationPacket -> handleStackLocation(packet) // is StackLocationPacket -> handleStackLocation(packet)
is ItemStackPacket -> handleItemStack(packet) // is ItemStackPacket -> handleItemStack(packet)
is CapacityPacket -> handleCapacity(packet) // is CapacityPacket -> handleCapacity(packet)
} // }
} // }
//
private fun handleReadInventory(packet: ReadInventoryPacket) { // private fun handleReadInventory(packet: ReadInventoryPacket) {
inventoryCache[packet.source] = packet.inventory // inventoryCache[packet.source] = packet.inventory
updateNetItems() // updateNetItems()
sync() // sync()
} // }
//
private fun handleDeviceRemoved(packet: DeviceRemovedPacket) { // private fun handleDeviceRemoved(packet: DeviceRemovedPacket) {
inventoryCache.remove(packet.source) // inventoryCache.remove(packet.source)
updateNetItems() // updateNetItems()
sync() // sync()
} // }
//
private fun handleStackLocation(packet: StackLocationPacket) { // private fun handleStackLocation(packet: StackLocationPacket) {
val request = pendingRequests.firstOrNull { // val request = pendingRequests.firstOrNull {
ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack) // ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack)
} // }
if (request != null) { // if (request != null) {
request.results.add(packet.amount to packet.sourceInterface) // request.results.add(packet.amount to packet.sourceInterface)
if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) { // if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) {
stackLocateRequestCompleted(request) // stackLocateRequestCompleted(request)
} // }
} // }
} // }
//
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack { // override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
val remaining = internalBuffer.insertFromNetwork(packet.stack) // val remaining = internalBuffer.insertFromNetwork(packet.stack)
//
// this happens outside the normal update loop because by receiving the item stack packet // // 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 // // we "know" how much the count in the source inventory has changed
updateNetItems() // updateNetItems()
sync() // sync()
//
return remaining // return remaining
} // }
//
private fun handleCapacity(packet: CapacityPacket) { // private fun handleCapacity(packet: CapacityPacket) {
val insertion = pendingInsertions.values.firstOrNull { // val insertion = pendingInsertions.values.firstOrNull {
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack) // ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
} // }
if (insertion != null) { // if (insertion != null) {
insertion.results.add(packet.capacity to packet.receivingInterface) // insertion.results.add(packet.capacity to packet.receivingInterface)
if (insertion.isFinishable(counter)) { // if (insertion.isFinishable(counter)) {
finishInsertion(insertion) // finishInsertion(insertion)
} // }
} // }
} // }
//
private fun updateNetItems() { // private fun updateNetItems() {
cachedNetItems.clear() // cachedNetItems.clear()
for (inventory in inventoryCache.values) { // for (inventory in inventoryCache.values) {
for (stack in inventory.storedStacks) { // for (stack in inventory.storedStacks) {
val amount = inventory.getAmount(stack) // val amount = inventory.getAmount(stack)
cachedNetItems.mergeInt(stack, amount) { a, b -> a + b } // cachedNetItems.mergeInt(stack, amount) { a, b -> a + b }
} // }
} // }
// todo: is the map necessary or is just the sorted list enough? // // todo: is the map necessary or is just the sorted list enough?
cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map { // cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
val stack = it.key.copy() // val stack = it.key.copy()
stack.count = it.intValue // stack.count = it.intValue
stack // stack
} // }
} // }
//
private fun beginInsertions() { // private fun beginInsertions() {
if (world!!.isClient) return // if (world!!.isClient) return
//
for (slot in 0 until internalBuffer.size()) { // for (slot in 0 until internalBuffer.size()) {
if (internalBuffer.getMode(slot) != TerminalBufferInventory.Mode.TO_NETWORK) continue // if (internalBuffer.getMode(slot) != TerminalBufferInventory.Mode.TO_NETWORK) continue
if (slot in pendingInsertions) continue // if (slot in pendingInsertions) continue
val stack = internalBuffer.getStack(slot) // val stack = internalBuffer.getStack(slot)
pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter) // pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter)
sendToSingle(CheckCapacityPacket(stack, macAddress, MACAddress.BROADCAST)) // sendToSingle(CheckCapacityPacket(stack, macAddress, MACAddress.BROADCAST))
} // }
} // }
//
private fun finishPendingInsertions() { // private fun finishPendingInsertions() {
if (world!!.isClient) return // if (world!!.isClient) return
//
for (insertion in pendingInsertions.values) { // for (insertion in pendingInsertions.values) {
if (!insertion.isFinishable(counter)) continue // if (!insertion.isFinishable(counter)) continue
finishInsertion(insertion) // finishInsertion(insertion)
} // }
} // }
//
private fun sendEnqueuedLocateRequests() { // private fun sendEnqueuedLocateRequests() {
if (world!!.isClient) return // if (world!!.isClient) return
//
for (request in locateRequestQueue) { // for (request in locateRequestQueue) {
pendingRequests.add(request) // pendingRequests.add(request)
sendToSingle(LocateStackPacket(request.stack, macAddress)) // sendToSingle(LocateStackPacket(request.stack, macAddress))
} // }
locateRequestQueue.clear() // locateRequestQueue.clear()
} // }
//
private fun finishPendingRequests() { // private fun finishPendingRequests() {
if (world!!.isClient) return // if (world!!.isClient) return
//
for (request in pendingRequests) { // for (request in pendingRequests) {
if (request.isFinishable(counter)) { // if (request.isFinishable(counter)) {
stackLocateRequestCompleted(request) // stackLocateRequestCompleted(request)
} // }
} // }
} // }
//
fun addObserver() { // fun addObserver() {
observers++ // observers++
} // }
//
fun removeObserver() { // fun removeObserver() {
observers-- // observers--
} // }
//
override fun tick() { // override fun tick() {
if (observers > 0 && (++counter % 10) == 0) { // if (observers > 0 && (++counter % 10) == 0) {
if (world!!.isClient) { // if (world!!.isClient) {
println(cachedNetItems) // println(cachedNetItems)
} else { // } else {
updateNetItems() // updateNetItems()
sendEnqueuedLocateRequests() // sendEnqueuedLocateRequests()
finishPendingRequests() // finishPendingRequests()
beginInsertions() // beginInsertions()
finishPendingInsertions() // finishPendingInsertions()
sync() // sync()
} // }
} // }
} // }
//
fun onActivate(player: PlayerEntity) { // fun onActivate(player: PlayerEntity) {
if (!world!!.isClient) { // if (!world!!.isClient) {
updateNetItems() // updateNetItems()
sync() // sync()
//
inventoryCache.clear() // inventoryCache.clear()
sendToSingle(RequestInventoryPacket(macAddress)) // sendToSingle(RequestInventoryPacket(macAddress))
val factory = object: ExtendedScreenHandlerFactory { // val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? { // override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity) // return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
} // }
//
override fun getDisplayName() = LiteralText("Terminal") // override fun getDisplayName() = LiteralText("Terminal")
//
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) { // override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
buf.writeBlockPos(this@TerminalBlockEntity.pos) // buf.writeBlockPos(this@TerminalBlockEntity.pos)
} // }
} // }
player.openHandledScreen(factory) // player.openHandledScreen(factory)
} // }
addObserver() // addObserver()
} // }
//
fun requestItem(stack: ItemStack, amount: Int = stack.count) { // fun requestItem(stack: ItemStack, amount: Int = stack.count) {
locateRequestQueue.add(StackLocateRequest(stack, amount, counter)) // locateRequestQueue.add(StackLocateRequest(stack, amount, counter))
} // }
//
private fun stackLocateRequestCompleted(request: StackLocateRequest) { // private fun stackLocateRequestCompleted(request: StackLocateRequest) {
pendingRequests.remove(request) // pendingRequests.remove(request)
//
// todo: also sort results by interface priority // // todo: also sort results by interface priority
val sortedResults = request.results.sortedByDescending { it.first }.toMutableList() // val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
var amountRequested = 0 // var amountRequested = 0
while (amountRequested < request.amount && sortedResults.isNotEmpty()) { // while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0) // val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
val amountToRequest = min(sourceAmount, request.amount - amountRequested) // val amountToRequest = min(sourceAmount, request.amount - amountRequested)
amountRequested += amountToRequest // amountRequested += amountToRequest
sendToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress)) // sendToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress))
} // }
} // }
//
private fun finishInsertion(insertion: PendingStackInsertion) { // private fun finishInsertion(insertion: PendingStackInsertion) {
pendingInsertions.remove(insertion.bufferSlot) // pendingInsertions.remove(insertion.bufferSlot)
//
// todo: also sort results by interface priority // // todo: also sort results by interface priority
val sortedResults = insertion.results.sortedBy { it.first }.toMutableList() // val sortedResults = insertion.results.sortedBy { it.first }.toMutableList()
val remaining = insertion.stack // val remaining = insertion.stack
while (!remaining.isEmpty && sortedResults.isNotEmpty()) { // while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
val (capacity, receivingInterface) = sortedResults.removeAt(0) // val (capacity, receivingInterface) = sortedResults.removeAt(0)
if (capacity <= 0) continue // if (capacity <= 0) continue
sendToSingle(ItemStackPacket(remaining.copy(), macAddress, receivingInterface.macAddress)) // sendToSingle(ItemStackPacket(remaining.copy(), macAddress, receivingInterface.macAddress))
// todo: the interface should confirm how much was actually inserted, in case of race condition // // todo: the interface should confirm how much was actually inserted, in case of race condition
remaining.count -= capacity // remaining.count -= capacity
} // }
internalBuffer.setStack(insertion.bufferSlot, remaining) // internalBuffer.setStack(insertion.bufferSlot, remaining)
//
// as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets // // as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets
updateNetItems() // updateNetItems()
sync() // sync()
} // }
//
override fun onInventoryChanged(inv: Inventory) { // override fun onInventoryChanged(inv: Inventory) {
if (inv == internalBuffer && world != null && !world!!.isClient) { // if (inv == internalBuffer && world != null && !world!!.isClient) {
markDirty() // markDirty()
sync() // sync()
} // }
} // }
//
override fun toTag(tag: CompoundTag): CompoundTag { // override fun toTag(tag: CompoundTag): CompoundTag {
tag.put("InternalBuffer", internalBuffer.toTag()) // tag.put("InternalBuffer", internalBuffer.toTag())
return super.toTag(tag) // return super.toTag(tag)
} // }
//
override fun fromTag(state: BlockState, tag: CompoundTag) { // override fun fromTag(state: BlockState, tag: CompoundTag) {
super.fromTag(state, tag) // super.fromTag(state, tag)
internalBuffer.fromTag(tag.getCompound("InternalBuffer")) // internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
} // }
//
override fun toClientTag(tag: CompoundTag): CompoundTag { // override fun toClientTag(tag: CompoundTag): CompoundTag {
tag.put("InternalBuffer", internalBuffer.toTag()) // tag.put("InternalBuffer", internalBuffer.toTag())
val list = ListTag() // val list = ListTag()
tag.put("CachedNetItems", list) // tag.put("CachedNetItems", list)
for ((stack, amount) in cachedNetItems) { // for ((stack, amount) in cachedNetItems) {
val entryTag = stack.toTag(CompoundTag()) // val entryTag = stack.toTag(CompoundTag())
entryTag.putInt("NetAmount", amount) // entryTag.putInt("NetAmount", amount)
list.add(entryTag) // list.add(entryTag)
} // }
return tag // return tag
} // }
//
override fun fromClientTag(tag: CompoundTag) { // override fun fromClientTag(tag: CompoundTag) {
internalBuffer.fromTag(tag.getCompound("InternalBuffer")) // internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
val list = tag.getList("CachedNetItems", 10) // val list = tag.getList("CachedNetItems", 10)
cachedNetItems.clear() // cachedNetItems.clear()
for (entryTag in list) { // for (entryTag in list) {
val stack = ItemStack.fromTag(entryTag as CompoundTag) // val stack = ItemStack.fromTag(entryTag as CompoundTag)
val netAmount = entryTag.getInt("NetAmount") // val netAmount = entryTag.getInt("NetAmount")
cachedNetItems[stack] = netAmount // cachedNetItems[stack] = netAmount
} // }
cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map { // cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
val stack = it.key.copy() // val stack = it.key.copy()
stack.count = it.intValue // stack.count = it.intValue
stack // stack
} // }
} // }
//
} //}
//
data class StackLocateRequest( //data class StackLocateRequest(
val stack: ItemStack, // val stack: ItemStack,
val amount: Int, // val amount: Int,
val timestamp: Int, // val timestamp: Int,
var results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf() // var results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf()
) { //) {
val totalResultAmount: Int // val totalResultAmount: Int
get() = results.fold(0) { acc, (amount, _) -> acc + amount } // get() = results.fold(0) { acc, (amount, _) -> acc + amount }
//
fun isFinishable(currentTimestamp: Int): Boolean { // fun isFinishable(currentTimestamp: Int): Boolean {
return totalResultAmount > amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT // return totalResultAmount > amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
} // }
} //}
//
data class PendingStackInsertion( //data class PendingStackInsertion(
val bufferSlot: Int, // val bufferSlot: Int,
val stack: ItemStack, // val stack: ItemStack,
val timestamp: Int, // val timestamp: Int,
val results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf(), // val results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf(),
) { //) {
val totalCapacity: Int // val totalCapacity: Int
get() = results.fold(0) { acc, (amount, _) -> acc + amount } // get() = results.fold(0) { acc, (amount, _) -> acc + amount }
//
fun isFinishable(currentTimestamp: Int): Boolean { // fun isFinishable(currentTimestamp: Int): Boolean {
return totalCapacity > stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT // return totalCapacity > stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT
} // }
} //}

View File

@ -1,61 +1,61 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
import net.minecraft.screen.slot.Slot //import net.minecraft.screen.slot.Slot
import net.minecraft.entity.player.PlayerEntity //import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.Inventory //import net.minecraft.inventory.Inventory
import net.minecraft.item.ItemStack //import net.minecraft.item.ItemStack
//
/** ///**
* @author shadowfacts // * @author shadowfacts
*/ // */
class TerminalFakeSlot(val terminal: TerminalBlockEntity, slot: Int, x: Int, y: Int): Slot(FakeInventory(terminal, slot), slot, x, y) { //class TerminalFakeSlot(val terminal: TerminalBlockEntity, slot: Int, x: Int, y: Int): Slot(FakeInventory(terminal, slot), slot, x, y) {
//
override fun canInsert(stack: ItemStack): Boolean { // override fun canInsert(stack: ItemStack): Boolean {
return false // return false
} // }
//
override fun setStack(stack: ItemStack) { // override fun setStack(stack: ItemStack) {
} // }
//
override fun canTakeItems(player: PlayerEntity): Boolean { // override fun canTakeItems(player: PlayerEntity): Boolean {
return false // return false
} // }
//
} //}
//
class FakeInventory(val terminal: TerminalBlockEntity, val slot: Int): Inventory { //class FakeInventory(val terminal: TerminalBlockEntity, val slot: Int): Inventory {
override fun getStack(_slot: Int): ItemStack { // override fun getStack(_slot: Int): ItemStack {
if (slot >= terminal.cachedSortedNetItems.size) return ItemStack.EMPTY // if (slot >= terminal.cachedSortedNetItems.size) return ItemStack.EMPTY
return terminal.cachedSortedNetItems[slot] // return terminal.cachedSortedNetItems[slot]
} // }
//
override fun markDirty() { // override fun markDirty() {
} // }
//
override fun clear() { // override fun clear() {
} // }
//
override fun setStack(p0: Int, p1: ItemStack?) { // override fun setStack(p0: Int, p1: ItemStack?) {
} // }
//
override fun removeStack(p0: Int): ItemStack { // override fun removeStack(p0: Int): ItemStack {
return ItemStack.EMPTY // return ItemStack.EMPTY
} // }
//
override fun canPlayerUse(p0: PlayerEntity?): Boolean { // override fun canPlayerUse(p0: PlayerEntity?): Boolean {
return false // return false
} // }
//
override fun size(): Int { // override fun size(): Int {
return 1 // return 1
} // }
//
override fun removeStack(p0: Int, p1: Int): ItemStack { // override fun removeStack(p0: Int, p1: Int): ItemStack {
return ItemStack.EMPTY // return ItemStack.EMPTY
} // }
//
override fun isEmpty(): Boolean { // override fun isEmpty(): Boolean {
return false // return false
} // }
//
} //}

View File

@ -1,58 +1,58 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
//
import com.mojang.blaze3d.platform.GlStateManager //import com.mojang.blaze3d.platform.GlStateManager
import net.minecraft.client.gui.DrawableHelper //import net.minecraft.client.gui.DrawableHelper
import net.minecraft.client.gui.screen.ingame.HandledScreen //import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.util.math.MatrixStack //import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory //import net.minecraft.entity.player.PlayerInventory
import net.minecraft.screen.slot.Slot //import net.minecraft.screen.slot.Slot
import net.minecraft.text.LiteralText //import net.minecraft.text.LiteralText
import net.minecraft.text.Text //import net.minecraft.text.Text
import net.minecraft.util.Identifier //import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity //import net.shadowfacts.phycon.PhysicalConnectivity
//
/** ///**
* @author shadowfacts // * @author shadowfacts
*/ // */
// todo: translate title //// todo: translate title
class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen<TerminalScreenHandler>(handler, playerInv, title) { //class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen<TerminalScreenHandler>(handler, playerInv, title) {
companion object { // companion object {
val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png") // val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
} // }
//
init { // init {
backgroundWidth = 252 // backgroundWidth = 252
backgroundHeight = 222 // backgroundHeight = 222
} // }
//
override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) { // override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
textRenderer.draw(matrixStack, title, 65f, 6f, 0x404040) // textRenderer.draw(matrixStack, title, 65f, 6f, 0x404040)
textRenderer.draw(matrixStack, playerInventory.displayName, 65f, backgroundHeight - 94f, 0x404040) // textRenderer.draw(matrixStack, playerInventory.displayName, 65f, backgroundHeight - 94f, 0x404040)
// todo: translate this // // todo: translate this
textRenderer.draw(matrixStack, "Buffer", 7f, 6f, 0x404040) // textRenderer.draw(matrixStack, "Buffer", 7f, 6f, 0x404040)
} // }
//
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) { // override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
GlStateManager.color4f(1f, 1f, 1f, 1f) // GlStateManager.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND) // client!!.textureManager.bindTexture(BACKGROUND)
val x = (width - backgroundWidth) / 2 // val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2 // val y = (height - backgroundHeight) / 2
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight) // drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
} // }
//
@ExperimentalUnsignedTypes // @ExperimentalUnsignedTypes
fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) { // fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) {
if (!handler.isBufferSlot(slot.id)) { // if (!handler.isBufferSlot(slot.id)) {
return // return
} // }
//
val mode = handler.terminal.internalBuffer.getMode(slot.id - handler.bufferSlotsStart) // val mode = handler.terminal.internalBuffer.getMode(slot.id - handler.bufferSlotsStart)
val color: UInt = when (mode) { // val color: UInt = when (mode) {
TerminalBufferInventory.Mode.TO_NETWORK -> 0xFFFF0000u // TerminalBufferInventory.Mode.TO_NETWORK -> 0xFFFF0000u
TerminalBufferInventory.Mode.FROM_NETWORK -> 0xFF00FF00u // TerminalBufferInventory.Mode.FROM_NETWORK -> 0xFF00FF00u
else -> return // else -> return
} // }
DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt()) // DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
} // }
//
} //}

View File

@ -1,161 +1,161 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
//
import net.minecraft.screen.slot.Slot //import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType //import net.minecraft.screen.slot.SlotActionType
import net.minecraft.entity.player.PlayerEntity //import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory //import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack //import net.minecraft.item.ItemStack
import net.minecraft.network.PacketByteBuf //import net.minecraft.network.PacketByteBuf
import net.minecraft.screen.ScreenHandler //import net.minecraft.screen.ScreenHandler
import net.minecraft.util.Identifier //import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity //import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.init.PhyBlocks //import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyScreens //import net.shadowfacts.phycon.init.PhyScreens
import kotlin.math.ceil //import kotlin.math.ceil
import kotlin.math.min //import kotlin.math.min
//
/** ///**
* @author shadowfacts // * @author shadowfacts
*/ // */
class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL_SCREEN_HANDLER, syncId) { //class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL_SCREEN_HANDLER, syncId) {
//
companion object { // companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "terminal") // val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
} // }
//
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf): // constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
this(syncId, playerInv, PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!) // this(syncId, playerInv, PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!)
//
init { // init {
// network // // network
for (y in 0 until 6) { // for (y in 0 until 6) {
for (x in 0 until 9) { // for (x in 0 until 9) {
addSlot(TerminalFakeSlot(terminal, y * 9 + x, 66 + x * 18, 18 + y * 18)) // addSlot(TerminalFakeSlot(terminal, y * 9 + x, 66 + x * 18, 18 + y * 18))
} // }
} // }
//
// internal buffer // // internal buffer
for (y in 0 until 6) { // for (y in 0 until 6) {
for (x in 0 until 3) { // for (x in 0 until 3) {
addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18)) // addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18))
} // }
} // }
//
// player inv // // player inv
for (y in 0 until 3) { // for (y in 0 until 3) {
for (x in 0 until 9) { // for (x in 0 until 9) {
addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18)) // addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18))
} // }
} // }
// hotbar // // hotbar
for (x in 0 until 9) { // for (x in 0 until 9) {
addSlot(Slot(playerInv, x, 66 + x * 18, 198)) // addSlot(Slot(playerInv, x, 66 + x * 18, 198))
} // }
} // }
//
override fun canUse(player: PlayerEntity): Boolean { // override fun canUse(player: PlayerEntity): Boolean {
return true // return true
} // }
//
override fun close(player: PlayerEntity) { // override fun close(player: PlayerEntity) {
super.close(player) // super.close(player)
//
terminal.removeObserver() // terminal.removeObserver()
} // }
//
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack { // override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
if (isNetworkSlot(slotId)) { // if (isNetworkSlot(slotId)) {
// the slot clicked was one of the network stacks // // the slot clicked was one of the network stacks
if (actionType == SlotActionType.QUICK_MOVE) { // if (actionType == SlotActionType.QUICK_MOVE) {
val stack = slots[slotId].stack // val stack = slots[slotId].stack
if (!stack.isEmpty && !player.world.isClient) { // if (!stack.isEmpty && !player.world.isClient) {
terminal.requestItem(stack, min(stack.count, stack.maxCount)) // terminal.requestItem(stack, min(stack.count, stack.maxCount))
} // }
} else if (actionType == SlotActionType.PICKUP && clickData == 1) { // } else if (actionType == SlotActionType.PICKUP && clickData == 1) {
if (clickData == 1) { // if (clickData == 1) {
// right click, request half stack // // right click, request half stack
val stack = slots[slotId].stack // val stack = slots[slotId].stack
if (!stack.isEmpty && !player.world.isClient) { // if (!stack.isEmpty && !player.world.isClient) {
terminal.requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt()) // terminal.requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt())
} // }
} else { // } else {
// todo: left click, show amount dialog // // todo: left click, show amount dialog
} // }
} // }
return ItemStack.EMPTY // return ItemStack.EMPTY
} else if (isBufferSlot(slotId)) { // } else if (isBufferSlot(slotId)) {
// internal buffer // // internal buffer
// todo: why does this think it's quick_craft sometimes? // // todo: why does this think it's quick_craft sometimes?
if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) { // if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) {
// placing cursor stack into buffer // // placing cursor stack into buffer
val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index // 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) // terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
} // }
} // }
return super.onSlotClick(slotId, clickData, actionType, player) // return super.onSlotClick(slotId, clickData, actionType, player)
} // }
//
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack { // override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
if (isNetworkSlot(slotId)) { // if (isNetworkSlot(slotId)) {
return ItemStack.EMPTY; // return ItemStack.EMPTY;
} // }
//
val slot = slots[slotId] // val slot = slots[slotId]
if (!slot.hasStack()) { // if (!slot.hasStack()) {
return ItemStack.EMPTY // return ItemStack.EMPTY
} // }
//
val result = slot.stack.copy() // val result = slot.stack.copy()
//
if (isBufferSlot(slotId)) { // if (isBufferSlot(slotId)) {
if (!insertItem(slot.stack, playerSlotsStart, playerSlotsEnd, false)) { // if (!insertItem(slot.stack, playerSlotsStart, playerSlotsEnd, false)) {
return ItemStack.EMPTY // return ItemStack.EMPTY
} // }
if (slot.stack.isEmpty) { // if (slot.stack.isEmpty) {
terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED) // terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED)
} // }
} else if (isPlayerSlot(slotId)) { // } else if (isPlayerSlot(slotId)) {
val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK } // 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) } // slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) }
if (slot.stack.isEmpty) { // if (slot.stack.isEmpty) {
return ItemStack.EMPTY // return ItemStack.EMPTY
} // }
} // }
//
return result // return result
} // }
//
private fun tryInsertItem(stack: ItemStack, slots: IntRange, slotPredicate: (Int) -> Boolean): Collection<Int> { // private fun tryInsertItem(stack: ItemStack, slots: IntRange, slotPredicate: (Int) -> Boolean): Collection<Int> {
val slotsInsertedInto = mutableListOf<Int>() // val slotsInsertedInto = mutableListOf<Int>()
for (index in slots) { // for (index in slots) {
if (stack.isEmpty) break // if (stack.isEmpty) break
if (!slotPredicate(index)) continue // if (!slotPredicate(index)) continue
//
val slot = this.slots[index] // val slot = this.slots[index]
val slotStack = slot.stack // val slotStack = slot.stack
if (slotStack.isEmpty) { // if (slotStack.isEmpty) {
slot.stack = stack.copy() // slot.stack = stack.copy()
stack.count = 0 // stack.count = 0
//
slot.markDirty() // slot.markDirty()
slotsInsertedInto.add(index) // slotsInsertedInto.add(index)
} else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) { // } else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) {
val maxToMove = slotStack.maxCount - slotStack.count // val maxToMove = slotStack.maxCount - slotStack.count
val toMove = min(maxToMove, stack.count) // val toMove = min(maxToMove, stack.count)
slotStack.increment(toMove) // slotStack.increment(toMove)
stack.decrement(toMove) // stack.decrement(toMove)
//
slot.markDirty() // slot.markDirty()
slotsInsertedInto.add(index) // slotsInsertedInto.add(index)
} // }
} // }
return slotsInsertedInto // return slotsInsertedInto
} // }
//
val bufferSlotsStart = 54 // val bufferSlotsStart = 54
val playerSlotsStart = 72 // val playerSlotsStart = 72
val playerSlotsEnd = 72 + 36 // val playerSlotsEnd = 72 + 36
fun isNetworkSlot(id: Int) = id in 0 until bufferSlotsStart // fun isNetworkSlot(id: Int) = id in 0 until bufferSlotsStart
fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart // fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart
fun isPlayerSlot(id: Int) = id >= playerSlotsStart // fun isPlayerSlot(id: Int) = id >= playerSlotsStart
} //}

View File

@ -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<DestBlockEntity>(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<Direction> {
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
}
}

View File

@ -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
}
}

View File

@ -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<SourceBlockEntity>(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<Direction> {
return EnumSet.allOf(Direction::class.java)
}
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
return getBlockEntity(world, pos)!!.interfaces.first()
}
}

View File

@ -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
}
}

View File

@ -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) {
}

View File

@ -26,6 +26,6 @@ fun <BE> BE.handleItemStack(packet: ItemStackPacket) where BE: BlockEntity, BE:
val remainder = doHandleItemStack(packet) val remainder = doHandleItemStack(packet)
// if there are any items remaining, send them back to the source with incremented bounce count // if there are any items remaining, send them back to the source with incremented bounce count
if (!remainder.isEmpty) { if (!remainder.isEmpty) {
sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source)) // sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source))
} }
} }

View File

@ -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) {
}

View File

@ -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
}

View File

@ -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
}

View File

@ -1,14 +1,14 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
abstract class BasePacket( abstract class BasePacket(
@JvmField private val source: MACAddress, @JvmField private val source: IPAddress,
@JvmField private val destination: MACAddress @JvmField private val destination: IPAddress
): Packet { ): Packet {
override fun getSource() = source override fun getSource() = source

View File

@ -1,11 +1,11 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity //import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: MACAddress, destination: MACAddress): BasePacket(source, destination) { //class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
} //}

View File

@ -1,10 +1,10 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
/** /**
* @author shadowfacts * @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) {
} }

View File

@ -1,11 +1,11 @@
package net.shadowfacts.phycon.network.packet 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 import net.shadowfacts.phycon.network.DeviceBlockEntity
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class DeviceRemovedPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) { class DeviceRemovedPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) {
constructor(device: DeviceBlockEntity): this(device.macAddress) constructor(device: DeviceBlockEntity): this(device.ipAddress)
} }

View File

@ -1,10 +1,10 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
/** /**
* @author shadowfacts * @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) {
} }

View File

@ -1,11 +1,11 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) { class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
constructor(stack: ItemStack, source: MACAddress, destination: MACAddress): this(stack, 0, source, destination) constructor(stack: ItemStack, source: IPAddress, destination: IPAddress): this(stack, 0, source, destination)
} }

View File

@ -1,10 +1,10 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
/** /**
* @author shadowfacts * @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) {
} }

View File

@ -1,13 +1,13 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import alexiil.mc.lib.attributes.item.GroupedItemInv import alexiil.mc.lib.attributes.item.GroupedItemInv
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class ReadInventoryPacket( class ReadInventoryPacket(
val inventory: GroupedItemInv, val inventory: GroupedItemInv,
source: MACAddress, source: IPAddress,
destination: MACAddress destination: IPAddress
): BasePacket(source, destination) ): BasePacket(source, destination)

View File

@ -1,8 +1,8 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class RequestInventoryPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) class RequestInventoryPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination)

View File

@ -1,18 +1,18 @@
package net.shadowfacts.phycon.network.packet package net.shadowfacts.phycon.network.packet
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity //import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
// todo: better name with LocateStackPacket // todo: better name with LocateStackPacket
class StackLocationPacket( //class StackLocationPacket(
val stack: ItemStack, // val stack: ItemStack,
val amount: Int, // val amount: Int,
val sourceInterface: InterfaceBlockEntity, // val sourceInterface: InterfaceBlockEntity,
source: MACAddress, // source: IPAddress,
destination: MACAddress // destination: IPAddress
): BasePacket(source, destination) { //): BasePacket(source, destination) {
} //}