Implement layer 3 networking
This commit is contained in:
parent
26134cea9d
commit
e8425b80fd
|
@ -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);
|
||||
|
||||
}
|
|
@ -3,6 +3,6 @@ package net.shadowfacts.phycon.api;
|
|||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
public interface NetworkCable extends NetworkComponent {
|
||||
public interface NetworkCableBlock extends NetworkComponentBlock {
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
package net.shadowfacts.phycon.api;
|
||||
|
||||
import net.shadowfacts.phycon.api.packet.Packet;
|
||||
import net.shadowfacts.phycon.api.util.MACAddress;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
public interface PacketSink {
|
||||
public interface PacketSink extends NetworkDevice {
|
||||
|
||||
@NotNull
|
||||
MACAddress getMACAddress();
|
||||
Iterable<Interface> getDeviceInterfaces();
|
||||
|
||||
void handle(@NotNull Packet packet);
|
||||
void handle(@NotNull Packet packet, @NotNull Interface itf);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
package net.shadowfacts.phycon.api;
|
||||
|
||||
import net.shadowfacts.phycon.api.packet.Packet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
public interface PacketSource {
|
||||
// todo: does PacketSource actually need to extend NetworkDevice?
|
||||
public interface PacketSource extends NetworkDevice {
|
||||
// todo: better name for this
|
||||
void sendToSingle(Packet packet);
|
||||
void sendPacket(@NotNull Packet packet, @Nullable Interface itf);
|
||||
|
||||
void sendToAll(Packet packet);
|
||||
|
||||
void sendToAll(Packet packet, Iterable<PacketSink> destinations);
|
||||
// void sendToAll(@NotNull Packet packet);
|
||||
//
|
||||
// void sendToAll(@NotNull Packet packet, @NotNull Iterable<PacketSink> destinations);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,5 @@ import alexiil.mc.lib.attributes.Attributes;
|
|||
public class PhyAttributes {
|
||||
|
||||
public static final Attribute<PacketSink> PACKET_SINK = Attributes.create(PacketSink.class);
|
||||
public static final Attribute<NetworkInterface> NETWORK_INTERFACE = Attributes.create(NetworkInterface.class);
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package net.shadowfacts.phycon.api.packet;
|
||||
|
||||
import net.shadowfacts.phycon.api.util.MACAddress;
|
||||
import net.shadowfacts.phycon.api.util.IPAddress;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
|
@ -9,9 +9,9 @@ import org.jetbrains.annotations.NotNull;
|
|||
public interface Packet {
|
||||
|
||||
@NotNull
|
||||
MACAddress getSource();
|
||||
IPAddress getSource();
|
||||
|
||||
@NotNull
|
||||
MACAddress getDestination();
|
||||
IPAddress getDestination();
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -15,12 +15,14 @@ public final class MACAddress {
|
|||
|
||||
public static final MACAddress BROADCAST = new MACAddress(0xffffffffffffL);
|
||||
|
||||
@NotNull
|
||||
public static MACAddress random(Random random) {
|
||||
long value = random.nextLong() & 0xfeffffffffffL;
|
||||
return new MACAddress(value);
|
||||
}
|
||||
|
||||
private static final Random macAddressRandom = new Random();
|
||||
@NotNull
|
||||
public static MACAddress random() {
|
||||
return random(macAddressRandom);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package net.shadowfacts.phycon.mixin.client;
|
|||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreen;
|
||||
//import net.shadowfacts.phycon.network.block.terminal.TerminalScreen;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
|
@ -17,10 +17,10 @@ public class MixinHandledScreen {
|
|||
|
||||
@Inject(method = "drawSlot(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/screen/slot/Slot;)V", at = @At(value = "INVOKE", target = "enableDepthTest()V"))
|
||||
private void drawSlot(MatrixStack matrixStack, Slot slot, CallbackInfo ci) {
|
||||
if ((Object)this instanceof TerminalScreen) {
|
||||
TerminalScreen self = (TerminalScreen)(Object)this;
|
||||
self.drawSlotUnderlay(matrixStack, slot);
|
||||
}
|
||||
// if ((Object)this instanceof TerminalScreen) {
|
||||
// TerminalScreen self = (TerminalScreen)(Object)this;
|
||||
// self.drawSlotUnderlay(matrixStack, slot);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry
|
|||
import net.minecraft.client.render.RenderLayer
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
import net.shadowfacts.phycon.init.PhyScreens
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreen
|
||||
//import net.shadowfacts.phycon.network.block.terminal.TerminalScreen
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
|
@ -15,6 +15,6 @@ object PhysicalConnectivityClient: ClientModInitializer {
|
|||
override fun onInitializeClient() {
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(PhyBlocks.CABLE, RenderLayer.getTranslucent())
|
||||
|
||||
ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen)
|
||||
// ScreenRegistry.register(PhyScreens.TERMINAL_SCREEN_HANDLER, ::TerminalScreen)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,30 +5,39 @@ import net.minecraft.block.entity.BlockEntity
|
|||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlockEntity
|
||||
|
||||
//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
//import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
//import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object PhyBlockEntities {
|
||||
|
||||
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
|
||||
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
||||
// val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
|
||||
// val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
||||
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
||||
val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE)
|
||||
val DEST = create(::DestBlockEntity, PhyBlocks.DEST)
|
||||
|
||||
private fun <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() {
|
||||
register(InterfaceBlock.ID, INTERFACE)
|
||||
register(TerminalBlock.ID, TERMINAL)
|
||||
// register(InterfaceBlock.ID, INTERFACE)
|
||||
// register(TerminalBlock.ID, TERMINAL)
|
||||
register(SwitchBlock.ID, SWITCH)
|
||||
register(SourceBlock.ID, SOURCE)
|
||||
register(DestBlock.ID, DEST)
|
||||
}
|
||||
|
||||
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
||||
|
|
|
@ -4,25 +4,29 @@ import net.minecraft.block.Block
|
|||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object PhyBlocks {
|
||||
|
||||
val INTERFACE = InterfaceBlock()
|
||||
val TERMINAL = TerminalBlock()
|
||||
// val INTERFACE = InterfaceBlock()
|
||||
// val TERMINAL = TerminalBlock()
|
||||
val SWITCH = SwitchBlock()
|
||||
val CABLE = CableBlock()
|
||||
val SOURCE = SourceBlock()
|
||||
val DEST = DestBlock()
|
||||
|
||||
fun init() {
|
||||
register(InterfaceBlock.ID, INTERFACE)
|
||||
register(TerminalBlock.ID, TERMINAL)
|
||||
// register(InterfaceBlock.ID, INTERFACE)
|
||||
// register(TerminalBlock.ID, TERMINAL)
|
||||
register(SwitchBlock.ID, SWITCH)
|
||||
register(CableBlock.ID, CABLE)
|
||||
register(SourceBlock.ID, SOURCE)
|
||||
register(DestBlock.ID, DEST)
|
||||
}
|
||||
|
||||
private fun register(id: Identifier, block: Block) {
|
||||
|
|
|
@ -6,27 +6,34 @@ import net.minecraft.util.Identifier
|
|||
import net.minecraft.util.registry.Registry
|
||||
import net.shadowfacts.phycon.item.ScrewdriverItem
|
||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||
|
||||
//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||
//import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
object PhyItems {
|
||||
|
||||
val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings())
|
||||
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
||||
// val INTERFACE = BlockItem(PhyBlocks.INTERFACE, Item.Settings())
|
||||
// val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
||||
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
|
||||
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
|
||||
val SOURCE = BlockItem(PhyBlocks.SOURCE, Item.Settings())
|
||||
val DEST = BlockItem(PhyBlocks.DEST , Item.Settings())
|
||||
|
||||
val SCREWDRIVER = ScrewdriverItem()
|
||||
|
||||
fun init() {
|
||||
register(InterfaceBlock.ID, INTERFACE)
|
||||
register(TerminalBlock.ID, TERMINAL)
|
||||
// register(InterfaceBlock.ID, INTERFACE)
|
||||
// register(TerminalBlock.ID, TERMINAL)
|
||||
register(SwitchBlock.ID, SWITCH)
|
||||
register(CableBlock.ID, CABLE)
|
||||
register(SourceBlock.ID, SOURCE)
|
||||
register(DestBlock.ID, DEST)
|
||||
|
||||
register(ScrewdriverItem.ID, SCREWDRIVER)
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ package net.shadowfacts.phycon.init
|
|||
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
||||
//import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
||||
|
||||
object PhyScreens {
|
||||
|
||||
val TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler)
|
||||
// val TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler)
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -4,12 +4,13 @@ import net.minecraft.block.BlockState
|
|||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class DeviceBlock<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) {
|
||||
super.onBreak(world, pos, state, player)
|
||||
|
|
|
@ -1,83 +1,235 @@
|
|||
package net.shadowfacts.phycon.network
|
||||
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.util.Tickable
|
||||
import net.shadowfacts.phycon.api.PacketSink
|
||||
import net.shadowfacts.phycon.api.PacketSource
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
||||
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.network.frame.ARPQueryFrame
|
||||
import net.shadowfacts.phycon.network.frame.ARPResponseFrame
|
||||
import net.shadowfacts.phycon.network.frame.BasePacketFrame
|
||||
import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket
|
||||
import java.lang.RuntimeException
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), PacketSink, PacketSource {
|
||||
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||
BlockEntityClientSerializable,
|
||||
Tickable,
|
||||
PacketSink,
|
||||
PacketSource,
|
||||
InterfaceDelegate {
|
||||
|
||||
var macAddress = MACAddress.random()
|
||||
companion object {
|
||||
private const val ARP_RETRY_TIMEOUT = 200
|
||||
}
|
||||
|
||||
// var macAddress: MACAddress = MACAddress.random()
|
||||
// protected set
|
||||
|
||||
var ipAddress: IPAddress = IPAddress.random()
|
||||
protected set
|
||||
|
||||
override fun getMACAddress(): MACAddress {
|
||||
return macAddress
|
||||
}
|
||||
open val interfaces: List<BaseInterface> = listOf()
|
||||
// abstract val itf: BaseInterface
|
||||
|
||||
override fun handle(packet: Packet) {
|
||||
if (acceptsPacket(packet)) {
|
||||
handlePacket(packet)
|
||||
private val arpTable = mutableMapOf<IPAddress, MACAddress>()
|
||||
private val packetQueue = LinkedList<PendingPacket>()
|
||||
|
||||
protected var counter: Long = 0
|
||||
|
||||
override fun getIPAddress() = ipAddress
|
||||
|
||||
override fun getDeviceInterfaces() = interfaces
|
||||
|
||||
abstract override fun handle(packet: Packet, itf: Interface)
|
||||
|
||||
override fun handle(frame: EthernetFrame, fromItf: Interface) {
|
||||
println("$this ($ipAddress, ${fromItf.macAddress}) received frame from ${frame.source}: $frame")
|
||||
when (frame) {
|
||||
is ARPQueryFrame -> handleARPQuery(frame, fromItf)
|
||||
is ARPResponseFrame -> handleARPResponse(frame, fromItf)
|
||||
is PacketFrame -> {
|
||||
if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) {
|
||||
handle(frame.packet, fromItf)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun handlePacket(packet: Packet)
|
||||
|
||||
protected open fun acceptsPacket(packet: Packet): Boolean {
|
||||
return when (packet.destination.type) {
|
||||
MACAddress.Type.BROADCAST -> true
|
||||
MACAddress.Type.UNICAST -> macAddress == packet.destination
|
||||
MACAddress.Type.MULTICAST -> acceptsMulticastPacket(packet)
|
||||
private fun handleARPQuery(frame: ARPQueryFrame, fromItf: Interface) {
|
||||
println("$this ($ipAddress) received ARP query for ${frame.queryIP}")
|
||||
arpTable[frame.sourceIP] = frame.source
|
||||
if (frame.queryIP == ipAddress) {
|
||||
println("$this ($ipAddress) sending ARP response to ${frame.source} with ${fromItf.macAddress}")
|
||||
fromItf.send(ARPResponseFrame(ipAddress, fromItf.macAddress, frame.source))
|
||||
}
|
||||
}
|
||||
|
||||
open fun acceptsMulticastPacket(packet: Packet): Boolean {
|
||||
return false
|
||||
private fun handleARPResponse(frame: ARPResponseFrame, fromItf: Interface) {
|
||||
arpTable[frame.query] = frame.source
|
||||
println("$this ($ipAddress) received ARP response for ${frame.query} with ${frame.source}")
|
||||
|
||||
packetQueue.removeIf { (packet, itf, _) ->
|
||||
if (packet.destination == frame.query) {
|
||||
itf.send(BasePacketFrame(packet, itf.macAddress, frame.source))
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun send(packet: Packet, destination: PacketSink) {
|
||||
destination.handle(packet)
|
||||
// protected abstract fun handlePacket(packet: Packet, itf: Interface)
|
||||
//
|
||||
// protected open fun acceptsPacket(packet: Packet, itf: Interface): Boolean {
|
||||
// return when (packet.destination.type) {
|
||||
// MACAddress.Type.BROADCAST -> true
|
||||
// MACAddress.Type.UNICAST -> itf.macAddress == packet.destination
|
||||
// MACAddress.Type.MULTICAST -> acceptsMulticastPacket(packet)
|
||||
// }
|
||||
// }
|
||||
|
||||
// open fun acceptsMulticastPacket(packet: Packet): Boolean {
|
||||
// return false
|
||||
// }
|
||||
|
||||
fun sendPacket(packet: Packet) {
|
||||
sendPacket(packet, null)
|
||||
}
|
||||
|
||||
override fun 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
|
||||
override fun sendPacket(packet: Packet, itf: Interface?) {
|
||||
@Suppress("NAME_SHADOWING") var itf = itf
|
||||
if (itf == null) {
|
||||
if (interfaces.size == 1) {
|
||||
itf = interfaces.first()
|
||||
} else {
|
||||
throw RuntimeException("Cannot send packet from device with multiple interfaces without explicitly specifying interface")
|
||||
}
|
||||
send(packet, destinations.first())
|
||||
}
|
||||
|
||||
override fun sendToAll(packet: Packet) {
|
||||
sendToAll(packet, NetworkUtil.findDestinations(world!!, pos))
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendToAll(packet: Packet, destinations: Iterable<PacketSink>) {
|
||||
destinations.forEach {
|
||||
it.handle(packet)
|
||||
// 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 {
|
||||
tag.putLong("MACAddress", macAddress.address)
|
||||
tag.putInt("IPAddress", ipAddress.address)
|
||||
// tag.putLong("MACAddress", macAddress.address)
|
||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
super.fromTag(state, tag)
|
||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||
// todo: what happens if the defined number of ports changes between mod versions?
|
||||
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
||||
interfaces[i].macAddress = MACAddress(l)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
tag.putInt("IPAddress", ipAddress.address)
|
||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun fromClientTag(tag: CompoundTag) {
|
||||
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
||||
interfaces[i].macAddress = MACAddress(l)
|
||||
}
|
||||
}
|
||||
|
||||
fun onBreak() {
|
||||
sendToAll(DeviceRemovedPacket(this))
|
||||
sendPacket(DeviceRemovedPacket(this))
|
||||
}
|
||||
|
||||
data class PendingPacket(
|
||||
val packet: Packet,
|
||||
val sourceItf: Interface,
|
||||
var timestamp: Long,
|
||||
)
|
||||
|
||||
}
|
||||
|
|
|
@ -3,10 +3,7 @@ package net.shadowfacts.phycon.network
|
|||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.api.NetworkCable
|
||||
import net.shadowfacts.phycon.api.NetworkComponent
|
||||
import net.shadowfacts.phycon.api.PacketSink
|
||||
import net.shadowfacts.phycon.api.PhyAttributes
|
||||
import net.shadowfacts.phycon.api.*
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
|
@ -14,6 +11,28 @@ import java.util.*
|
|||
*/
|
||||
object NetworkUtil {
|
||||
|
||||
fun findConnectedInterface(world: World, startPos: BlockPos, startSide: Direction): Interface? {
|
||||
var curSide = startSide
|
||||
var pos = startPos.offset(startSide)
|
||||
var state = world.getBlockState(pos)
|
||||
while (state.block is NetworkComponentBlock) {
|
||||
val block = state.block as NetworkComponentBlock
|
||||
val itf = block.getNetworkInterfaceForSide(curSide.opposite, state, world, pos)
|
||||
if (itf != null) {
|
||||
return itf
|
||||
}
|
||||
val connectedSides = block.getNetworkConnectedSides(state, world, pos).filter { it != curSide.opposite }
|
||||
if (connectedSides.size == 1) {
|
||||
curSide = connectedSides.first()
|
||||
pos = pos.offset(curSide)
|
||||
state = world.getBlockState(pos)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List<PacketSink> {
|
||||
val results = LinkedList<PacketSink>()
|
||||
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) {
|
||||
val state = world.getBlockState(pos)
|
||||
val block = state.block
|
||||
if (block is NetworkComponent && (includeNonCables || block is NetworkCable)) {
|
||||
if (block is NetworkComponentBlock && (includeNonCables || block is NetworkCableBlock)) {
|
||||
val connections = block.getNetworkConnectedSides(state, world, pos)
|
||||
for (side in connections) {
|
||||
val newPos = pos.offset(side)
|
||||
|
|
|
@ -19,8 +19,9 @@ import net.minecraft.world.BlockView
|
|||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkCable
|
||||
import net.shadowfacts.phycon.api.NetworkComponent
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.NetworkCableBlock
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.init.PhyItems
|
||||
import net.shadowfacts.phycon.util.CableConnection
|
||||
import java.util.*
|
||||
|
@ -31,7 +32,7 @@ import java.util.*
|
|||
class CableBlock: Block(
|
||||
Settings.of(CABLE_MATERIAL)
|
||||
.nonOpaque()
|
||||
), NetworkCable {
|
||||
), NetworkCableBlock {
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "cable")
|
||||
val CABLE_MATERIAL = Material(MaterialColor.IRON, false, false, true, false, true, false, PistonBehavior.NORMAL)
|
||||
|
@ -108,11 +109,16 @@ class CableBlock: Block(
|
|||
else -> CableConnection.ON
|
||||
}
|
||||
}
|
||||
is NetworkComponent -> CableConnection.ON
|
||||
is NetworkComponentBlock -> CableConnection.ON
|
||||
else -> CableConnection.OFF
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||
// cables don't have network interfaces
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onUse(
|
||||
state: BlockState,
|
||||
world: World,
|
||||
|
@ -141,7 +147,7 @@ class CableBlock: Block(
|
|||
world.setBlockState(connectedToPos, connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON))
|
||||
}
|
||||
|
||||
state.with(prop, if (connectedTo.block is NetworkComponent) CableConnection.ON else CableConnection.OFF)
|
||||
state.with(prop, if (connectedTo.block is NetworkComponentBlock) CableConnection.ON else CableConnection.OFF)
|
||||
}
|
||||
else -> state.with(prop, CableConnection.DISABLED)
|
||||
}
|
||||
|
|
|
@ -1,120 +1,128 @@
|
|||
package net.shadowfacts.phycon.network.block.netinterface
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList
|
||||
import alexiil.mc.lib.attributes.AttributeProvider
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.block.ShapeContext
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.EnumProperty
|
||||
import net.minecraft.state.property.Properties
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
import net.minecraft.util.shape.VoxelShapes
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkComponent
|
||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider {
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
|
||||
val FACING = Properties.FACING
|
||||
val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java)
|
||||
private val SIDE_SHAPES = mapOf<Direction, VoxelShape>(
|
||||
Direction.DOWN to createCuboidShape(2.0, 0.0, 2.0, 14.0, 2.0, 14.0),
|
||||
Direction.UP to createCuboidShape(2.0, 14.0, 2.0, 14.0, 16.0, 14.0),
|
||||
Direction.NORTH to createCuboidShape(2.0, 2.0, 0.0, 14.0, 14.0, 2.0),
|
||||
Direction.SOUTH to createCuboidShape(2.0, 2.0, 14.0, 14.0, 14.0, 16.0),
|
||||
Direction.WEST to createCuboidShape(0.0, 2.0, 2.0, 2.0, 14.0, 14.0),
|
||||
Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.0)
|
||||
)
|
||||
private val CENTER_SHAPES = mapOf<Direction, VoxelShape>(
|
||||
Direction.DOWN to createCuboidShape(6.0, 2.0, 6.0, 10.0, 10.0, 10.0),
|
||||
Direction.UP to createCuboidShape(6.0, 6.0, 6.0, 10.0, 14.0, 10.0),
|
||||
Direction.NORTH to createCuboidShape(6.0, 6.0, 2.0, 10.0, 10.0, 10.0),
|
||||
Direction.SOUTH to createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 14.0),
|
||||
Direction.WEST to createCuboidShape(2.0, 6.0, 6.0, 10.0, 10.0, 10.0),
|
||||
Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 14.0, 10.0, 10.0)
|
||||
)
|
||||
|
||||
private val shapeCache = mutableMapOf<Pair<Direction, Direction>, VoxelShape>()
|
||||
fun getShape(facing: Direction, cableConnection: Direction): VoxelShape {
|
||||
return shapeCache.getOrPut(facing to cableConnection) {
|
||||
VoxelShapes.union(
|
||||
VoxelShapes.union(SIDE_SHAPES[facing], CENTER_SHAPES[facing]),
|
||||
CableBlock.SIDE_SHAPES[cableConnection]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
|
||||
return EnumSet.of(state[CABLE_CONNECTION])
|
||||
}
|
||||
|
||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
super.appendProperties(builder)
|
||||
builder.add(FACING)
|
||||
builder.add(CABLE_CONNECTION)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity()
|
||||
|
||||
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
||||
val cableConnection = getCableConnectionSide(context.world, context.blockPos) ?: facing.opposite
|
||||
return defaultState.with(FACING, facing).with(CABLE_CONNECTION, cableConnection)
|
||||
}
|
||||
|
||||
private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? {
|
||||
for (side in Direction.values()) {
|
||||
val offsetPos = pos.offset(side)
|
||||
if (world.getBlockState(offsetPos).block is NetworkComponent) {
|
||||
return side
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
|
||||
if (!world.isClient) {
|
||||
getBlockEntity(world, pos)!!.updateInventory()
|
||||
}
|
||||
}
|
||||
|
||||
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, boolean_1: Boolean) {
|
||||
if (!world.isClient) {
|
||||
getBlockEntity(world, pos)!!.updateInventory()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState {
|
||||
if (neighborState.block is NetworkComponent && world.getBlockState(pos.offset(state[CABLE_CONNECTION])).block !is NetworkComponent) {
|
||||
return state.with(CABLE_CONNECTION, side)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||
to.offer(getBlockEntity(world, pos))
|
||||
}
|
||||
|
||||
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||
return getShape(state[FACING], state[CABLE_CONNECTION])
|
||||
}
|
||||
|
||||
}
|
||||
//
|
||||
//import alexiil.mc.lib.attributes.AttributeList
|
||||
//import alexiil.mc.lib.attributes.AttributeProvider
|
||||
//import net.minecraft.block.Block
|
||||
//import net.minecraft.block.BlockState
|
||||
//import net.minecraft.block.Material
|
||||
//import net.minecraft.block.ShapeContext
|
||||
//import net.minecraft.entity.LivingEntity
|
||||
//import net.minecraft.item.ItemPlacementContext
|
||||
//import net.minecraft.item.ItemStack
|
||||
//import net.minecraft.state.StateManager
|
||||
//import net.minecraft.state.property.EnumProperty
|
||||
//import net.minecraft.state.property.Properties
|
||||
//import net.minecraft.util.Identifier
|
||||
//import net.minecraft.util.math.BlockPos
|
||||
//import net.minecraft.util.math.Direction
|
||||
//import net.minecraft.util.shape.VoxelShape
|
||||
//import net.minecraft.util.shape.VoxelShapes
|
||||
//import net.minecraft.world.BlockView
|
||||
//import net.minecraft.world.World
|
||||
//import net.minecraft.world.WorldAccess
|
||||
//import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
//import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
//import net.shadowfacts.phycon.api.Interface
|
||||
//import net.shadowfacts.phycon.block.BlockWithEntity
|
||||
//import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||
//import java.util.*
|
||||
//
|
||||
///**
|
||||
// * @author shadowfacts
|
||||
// */
|
||||
//class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material.METAL)),
|
||||
// NetworkComponentBlock,
|
||||
// AttributeProvider {
|
||||
//
|
||||
// companion object {
|
||||
// val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
|
||||
// val FACING = Properties.FACING
|
||||
// val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java)
|
||||
// private val SIDE_SHAPES = mapOf<Direction, VoxelShape>(
|
||||
// Direction.DOWN to createCuboidShape(2.0, 0.0, 2.0, 14.0, 2.0, 14.0),
|
||||
// Direction.UP to createCuboidShape(2.0, 14.0, 2.0, 14.0, 16.0, 14.0),
|
||||
// Direction.NORTH to createCuboidShape(2.0, 2.0, 0.0, 14.0, 14.0, 2.0),
|
||||
// Direction.SOUTH to createCuboidShape(2.0, 2.0, 14.0, 14.0, 14.0, 16.0),
|
||||
// Direction.WEST to createCuboidShape(0.0, 2.0, 2.0, 2.0, 14.0, 14.0),
|
||||
// Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.0)
|
||||
// )
|
||||
// private val CENTER_SHAPES = mapOf<Direction, VoxelShape>(
|
||||
// Direction.DOWN to createCuboidShape(6.0, 2.0, 6.0, 10.0, 10.0, 10.0),
|
||||
// Direction.UP to createCuboidShape(6.0, 6.0, 6.0, 10.0, 14.0, 10.0),
|
||||
// Direction.NORTH to createCuboidShape(6.0, 6.0, 2.0, 10.0, 10.0, 10.0),
|
||||
// Direction.SOUTH to createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 14.0),
|
||||
// Direction.WEST to createCuboidShape(2.0, 6.0, 6.0, 10.0, 10.0, 10.0),
|
||||
// Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 14.0, 10.0, 10.0)
|
||||
// )
|
||||
//
|
||||
// private val shapeCache = mutableMapOf<Pair<Direction, Direction>, VoxelShape>()
|
||||
// fun getShape(facing: Direction, cableConnection: Direction): VoxelShape {
|
||||
// return shapeCache.getOrPut(facing to cableConnection) {
|
||||
// VoxelShapes.union(
|
||||
// VoxelShapes.union(SIDE_SHAPES[facing], CENTER_SHAPES[facing]),
|
||||
// CableBlock.SIDE_SHAPES[cableConnection]
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
|
||||
// return EnumSet.of(state[CABLE_CONNECTION])
|
||||
// }
|
||||
//
|
||||
// override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||
// return getBlockEntity(world, pos)?.deviceInterfaces?.first()
|
||||
// }
|
||||
//
|
||||
// override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||
// super.appendProperties(builder)
|
||||
// builder.add(FACING)
|
||||
// builder.add(CABLE_CONNECTION)
|
||||
// }
|
||||
//
|
||||
// override fun createBlockEntity(world: BlockView) = InterfaceBlockEntity()
|
||||
//
|
||||
// override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||
// val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
||||
// val cableConnection = getCableConnectionSide(context.world, context.blockPos) ?: facing.opposite
|
||||
// return defaultState.with(FACING, facing).with(CABLE_CONNECTION, cableConnection)
|
||||
// }
|
||||
//
|
||||
// private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? {
|
||||
// for (side in Direction.values()) {
|
||||
// val offsetPos = pos.offset(side)
|
||||
// if (world.getBlockState(offsetPos).block is NetworkComponentBlock) {
|
||||
// return side
|
||||
// }
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
|
||||
// if (!world.isClient) {
|
||||
// getBlockEntity(world, pos)!!.updateInventory()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, boolean_1: Boolean) {
|
||||
// if (!world.isClient) {
|
||||
// getBlockEntity(world, pos)!!.updateInventory()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState {
|
||||
// if (neighborState.block is NetworkComponentBlock && world.getBlockState(pos.offset(state[CABLE_CONNECTION])).block !is NetworkComponentBlock) {
|
||||
// return state.with(CABLE_CONNECTION, side)
|
||||
// }
|
||||
// return state
|
||||
// }
|
||||
//
|
||||
// override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||
// to.offer(getBlockEntity(world, pos))
|
||||
// }
|
||||
//
|
||||
// override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||
// return getShape(state[FACING], state[CABLE_CONNECTION])
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -1,89 +1,93 @@
|
|||
package net.shadowfacts.phycon.network.block.netinterface
|
||||
|
||||
import alexiil.mc.lib.attributes.SearchOptions
|
||||
import alexiil.mc.lib.attributes.Simulation
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
||||
import net.shadowfacts.phycon.network.packet.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler {
|
||||
|
||||
private val facing: Direction
|
||||
get() = world!!.getBlockState(pos)[InterfaceBlock.FACING]
|
||||
|
||||
// todo: should this be a weak ref?
|
||||
private var inventory: GroupedItemInv? = null
|
||||
|
||||
fun updateInventory() {
|
||||
val offsetPos = pos.offset(facing)
|
||||
val option = SearchOptions.inDirection(facing)
|
||||
inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option)
|
||||
}
|
||||
|
||||
private fun getInventory(): GroupedItemInv? {
|
||||
// if we don't have an inventory, try to get one
|
||||
// this happens when readAll is called before a neighbor state changes, such as immediately after world load
|
||||
if (inventory == null) updateInventory()
|
||||
return inventory
|
||||
}
|
||||
|
||||
override fun handlePacket(packet: Packet) {
|
||||
when (packet) {
|
||||
is RequestInventoryPacket -> handleRequestInventory(packet)
|
||||
is LocateStackPacket -> handleLocateStack(packet)
|
||||
is ExtractStackPacket -> handleExtractStack(packet)
|
||||
is CheckCapacityPacket -> handleCheckCapacity(packet)
|
||||
is ItemStackPacket -> handleItemStack(packet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||
getInventory()?.also { inv ->
|
||||
sendToSingle(ReadInventoryPacket(inv, macAddress, packet.source))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||
getInventory()?.also { inv ->
|
||||
val amount = inv.getAmount(packet.stack)
|
||||
sendToSingle(StackLocationPacket(packet.stack, amount, this, macAddress, packet.source))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleExtractStack(packet: ExtractStackPacket) {
|
||||
getInventory()?.also { inv ->
|
||||
val extracted = inv.extract(packet.stack, packet.amount)
|
||||
sendToSingle(ItemStackPacket(extracted, macAddress, packet.source))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCheckCapacity(packet: CheckCapacityPacket) {
|
||||
getInventory()?.also { inv ->
|
||||
val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE)
|
||||
val couldAccept = packet.stack.count - remaining.count
|
||||
sendToSingle(CapacityPacket(packet.stack, couldAccept, this, macAddress, packet.source))
|
||||
}
|
||||
}
|
||||
|
||||
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||
val inventory = getInventory()
|
||||
if (inventory != null) {
|
||||
val remaining = inventory.insert(packet.stack)
|
||||
// whatever could not be inserted will be sent back to the packet's source
|
||||
return remaining
|
||||
} else {
|
||||
return packet.stack
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//
|
||||
//import alexiil.mc.lib.attributes.SearchOptions
|
||||
//import alexiil.mc.lib.attributes.Simulation
|
||||
//import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||
//import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||
//import net.minecraft.item.ItemStack
|
||||
//import net.minecraft.util.math.Direction
|
||||
//import net.shadowfacts.phycon.api.Interface
|
||||
//import net.shadowfacts.phycon.api.packet.Packet
|
||||
//import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
//import net.shadowfacts.phycon.network.BaseInterface
|
||||
//import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
//import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
||||
//import net.shadowfacts.phycon.network.component.handleItemStack
|
||||
//import net.shadowfacts.phycon.network.packet.*
|
||||
//
|
||||
///**
|
||||
// * @author shadowfacts
|
||||
// */
|
||||
//class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler {
|
||||
//
|
||||
// override val interfaces = listOf(BaseInterface(this))
|
||||
//
|
||||
// private val facing: Direction
|
||||
// get() = world!!.getBlockState(pos)[InterfaceBlock.FACING]
|
||||
//
|
||||
// // todo: should this be a weak ref?
|
||||
// private var inventory: GroupedItemInv? = null
|
||||
//
|
||||
// fun updateInventory() {
|
||||
// val offsetPos = pos.offset(facing)
|
||||
// val option = SearchOptions.inDirection(facing)
|
||||
// inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option)
|
||||
// }
|
||||
//
|
||||
// private fun getInventory(): GroupedItemInv? {
|
||||
// // if we don't have an inventory, try to get one
|
||||
// // this happens when readAll is called before a neighbor state changes, such as immediately after world load
|
||||
// if (inventory == null) updateInventory()
|
||||
// return inventory
|
||||
// }
|
||||
//
|
||||
// override fun handle(packet: Packet, itf: Interface) {
|
||||
// when (packet) {
|
||||
// is RequestInventoryPacket -> handleRequestInventory(packet)
|
||||
// is LocateStackPacket -> handleLocateStack(packet)
|
||||
// is ExtractStackPacket -> handleExtractStack(packet)
|
||||
// is CheckCapacityPacket -> handleCheckCapacity(packet)
|
||||
// is ItemStackPacket -> handleItemStack(packet)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||
// getInventory()?.also { inv ->
|
||||
// sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun handleLocateStack(packet: LocateStackPacket) {
|
||||
// getInventory()?.also { inv ->
|
||||
// val amount = inv.getAmount(packet.stack)
|
||||
// sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun handleExtractStack(packet: ExtractStackPacket) {
|
||||
// getInventory()?.also { inv ->
|
||||
// val extracted = inv.extract(packet.stack, packet.amount)
|
||||
// sendPacket(ItemStackPacket(extracted, ipAddress, packet.source))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun handleCheckCapacity(packet: CheckCapacityPacket) {
|
||||
// getInventory()?.also { inv ->
|
||||
// val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE)
|
||||
// val couldAccept = packet.stack.count - remaining.count
|
||||
// sendPacket(CapacityPacket(packet.stack, couldAccept, this, ipAddress, packet.source))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||
// val inventory = getInventory()
|
||||
// if (inventory != null) {
|
||||
// val remaining = inventory.insert(packet.stack)
|
||||
// // whatever could not be inserted will be sent back to the packet's source
|
||||
// return remaining
|
||||
// } else {
|
||||
// return packet.stack
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -10,14 +10,18 @@ import net.minecraft.util.math.Direction
|
|||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkComponent
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider {
|
||||
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)),
|
||||
NetworkComponentBlock,
|
||||
AttributeProvider {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "switch")
|
||||
}
|
||||
|
@ -26,6 +30,10 @@ class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL
|
|||
return EnumSet.allOf(Direction::class.java)
|
||||
}
|
||||
|
||||
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||
return getBlockEntity(world, pos)?.interfaces?.find { it.side == side }
|
||||
}
|
||||
|
||||
override fun createBlockEntity(world: BlockView) = SwitchBlockEntity()
|
||||
|
||||
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||
|
|
|
@ -1,82 +1,129 @@
|
|||
package net.shadowfacts.phycon.network.block.netswitch
|
||||
|
||||
import net.minecraft.entity.ItemEntity
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.util.Tickable
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.shadowfacts.phycon.api.PacketSink
|
||||
import net.shadowfacts.phycon.api.Interface
|
||||
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.BaseInterface
|
||||
import net.shadowfacts.phycon.network.InterfaceDelegate
|
||||
import net.shadowfacts.phycon.network.NetworkUtil
|
||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
||||
import java.lang.RuntimeException
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class SwitchBlockEntity: DeviceBlockEntity(PhyBlockEntities.SWITCH), Tickable {
|
||||
class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||
BlockEntityClientSerializable,
|
||||
InterfaceDelegate,
|
||||
Tickable {
|
||||
|
||||
companion object {
|
||||
var SWITCHING_CAPACITY = 256
|
||||
}
|
||||
|
||||
val interfaces = Direction.values().map { SwitchInterface(it, this) }
|
||||
|
||||
private val macTable = mutableMapOf<MACAddress, Direction>()
|
||||
private var packetsHandledThisTick = 0
|
||||
|
||||
override fun acceptsPacket(packet: Packet) = true
|
||||
// override fun handle(packet: Packet, itf: Interface) {
|
||||
// if (packetsHandledThisTick >= SWITCHING_CAPACITY) {
|
||||
// if (packet is ItemStackPacket) {
|
||||
// // todo: calculate entity spawn point by finding non-obstructed location
|
||||
// val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack)
|
||||
// world!!.spawnEntity(entity)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// packetsHandledThisTick++
|
||||
//
|
||||
// if (packet.destination.isBroadcast) {
|
||||
//// for (other in interfaces) {
|
||||
//// if (other == itf) continue
|
||||
//// sendPacket(packet, other)
|
||||
//// }
|
||||
// flood(packet, itf)
|
||||
// } else {
|
||||
// val direction = ipTable[packet.destination]
|
||||
// if (direction != null) {
|
||||
// sendPacket()
|
||||
//// val dest = findDestination(direction)
|
||||
//// if (dest != null && packet.destination == dest.macAddress) {
|
||||
//// sendPacke(packet, dest)
|
||||
//// return
|
||||
//// }
|
||||
// }
|
||||
// flood(packet, itf)
|
||||
// }
|
||||
// }
|
||||
|
||||
override fun handlePacket(packet: Packet) {
|
||||
if (packetsHandledThisTick >= SWITCHING_CAPACITY) {
|
||||
if (packet is ItemStackPacket) {
|
||||
// todo: calculate entity spawn point by finding non-obstructed location
|
||||
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack)
|
||||
world!!.spawnEntity(entity)
|
||||
}
|
||||
return
|
||||
fun interfaceForSide(side: Direction): SwitchInterface {
|
||||
return interfaces.find { it.side == side }!!
|
||||
}
|
||||
|
||||
packetsHandledThisTick++
|
||||
override fun handle(frame: EthernetFrame, fromItf: Interface) {
|
||||
val itfSide = (fromItf as SwitchInterface).side
|
||||
macTable[frame.source] = itfSide
|
||||
|
||||
if (packet.destination == MACAddress.BROADCAST) {
|
||||
val allDestinations = NetworkUtil.findDestinations(world!!, pos).filter { it.macAddress != packet.source }
|
||||
sendToAll(packet, allDestinations)
|
||||
val knownDir = macTable[frame.destination]
|
||||
if (knownDir != null) {
|
||||
println("$this ($itfSide, ${fromItf.macAddress}) forwarding $frame to side $knownDir")
|
||||
interfaceForSide(knownDir).send(frame)
|
||||
} else {
|
||||
val direction = macTable[packet.destination]
|
||||
if (direction != null) {
|
||||
val dest = findDestination(direction)
|
||||
if (dest != null && packet.destination == dest.macAddress) {
|
||||
send(packet, dest)
|
||||
return
|
||||
}
|
||||
}
|
||||
flood(packet)
|
||||
println("$this ($itfSide, ${fromItf.macAddress}) flooding $frame")
|
||||
flood(frame, fromItf)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findDestination(direction: Direction): PacketSink? {
|
||||
val allDestinations = NetworkUtil.findDestinations(world!!, pos, direction)
|
||||
if (allDestinations.size > 1) {
|
||||
// todo: do this better
|
||||
println("Can't send packet, multiple destinations: $allDestinations")
|
||||
return null
|
||||
private fun flood(frame: EthernetFrame, source: Interface) {
|
||||
for (itf in interfaces) {
|
||||
if (source == itf) continue
|
||||
itf.send(frame)
|
||||
}
|
||||
return allDestinations.firstOrNull()
|
||||
}
|
||||
|
||||
private fun flood(packet: Packet) {
|
||||
for (dir in Direction.values()) {
|
||||
val dest = findDestination(dir)
|
||||
if (dest != null && packet.destination == dest.macAddress) {
|
||||
macTable[packet.destination] = dir
|
||||
send(packet, dest)
|
||||
break
|
||||
}
|
||||
}
|
||||
override fun findDestination(fromItf: Interface): Interface? {
|
||||
val side = (fromItf as SwitchInterface).side
|
||||
return NetworkUtil.findConnectedInterface(world!!, pos, side)
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
packetsHandledThisTick = 0
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
super.fromTag(state, tag)
|
||||
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
||||
interfaces[i].macAddress = MACAddress(l)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
tag.putLongArray("InterfaceAddresses", interfaces.map { it.macAddress.address })
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun fromClientTag(tag: CompoundTag) {
|
||||
tag.getLongArray("InterfaceAddresses")?.forEachIndexed { i, l ->
|
||||
interfaces[i].macAddress = MACAddress(l)
|
||||
}
|
||||
}
|
||||
|
||||
class SwitchInterface(val side: Direction, delegate: InterfaceDelegate): BaseInterface(delegate) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,43 +1,44 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList
|
||||
import alexiil.mc.lib.attributes.AttributeProvider
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.Material
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.api.NetworkComponent
|
||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class TerminalBlock: BlockWithEntity<TerminalBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider {
|
||||
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 createBlockEntity(world: BlockView) = TerminalBlockEntity()
|
||||
|
||||
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
|
||||
getBlockEntity(world, pos)!!.onActivate(player)
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||
to.offer(getBlockEntity(world, pos))
|
||||
}
|
||||
}
|
||||
//
|
||||
//import alexiil.mc.lib.attributes.AttributeList
|
||||
//import alexiil.mc.lib.attributes.AttributeProvider
|
||||
//import net.minecraft.block.BlockState
|
||||
//import net.minecraft.block.Material
|
||||
//import net.minecraft.entity.player.PlayerEntity
|
||||
//import net.minecraft.util.ActionResult
|
||||
//import net.minecraft.util.Hand
|
||||
//import net.minecraft.util.Identifier
|
||||
//import net.minecraft.util.hit.BlockHitResult
|
||||
//import net.minecraft.util.math.BlockPos
|
||||
//import net.minecraft.util.math.Direction
|
||||
//import net.minecraft.world.BlockView
|
||||
//import net.minecraft.world.World
|
||||
//import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
//import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||
//import net.shadowfacts.phycon.block.BlockWithEntity
|
||||
//import java.util.*
|
||||
//
|
||||
///**
|
||||
// * @author shadowfacts
|
||||
// */
|
||||
//class TerminalBlock: BlockWithEntity<TerminalBlockEntity>(Settings.of(Material.METAL)),
|
||||
// NetworkComponentBlock, AttributeProvider {
|
||||
// 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 createBlockEntity(world: BlockView) = TerminalBlockEntity()
|
||||
//
|
||||
// override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): ActionResult {
|
||||
// getBlockEntity(world, pos)!!.onActivate(player)
|
||||
// return ActionResult.SUCCESS
|
||||
// }
|
||||
//
|
||||
// override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||
// to.offer(getBlockEntity(world, pos))
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -1,330 +1,330 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.inventory.Inventory
|
||||
import net.minecraft.inventory.InventoryChangedListener
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.LiteralText
|
||||
import net.minecraft.util.Tickable
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
||||
import net.shadowfacts.phycon.network.packet.*
|
||||
import java.util.*
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable, ItemStackPacketHandler {
|
||||
|
||||
companion object {
|
||||
val LOCATE_REQUEST_TIMEOUT = 40 // ticks
|
||||
val INSERTION_TIMEOUT = 40
|
||||
}
|
||||
|
||||
private val inventoryCache = mutableMapOf<MACAddress, GroupedItemInv>()
|
||||
val internalBuffer = TerminalBufferInventory(18)
|
||||
|
||||
private val locateRequestQueue = LinkedList<StackLocateRequest>()
|
||||
private val pendingRequests = LinkedList<StackLocateRequest>()
|
||||
private val pendingInsertions = Int2ObjectArrayMap<PendingStackInsertion>()
|
||||
|
||||
private var observers = 0
|
||||
val cachedNetItems = ItemStackCollections.intMap()
|
||||
var cachedSortedNetItems = listOf<ItemStack>()
|
||||
var counter = 0
|
||||
|
||||
init {
|
||||
internalBuffer.addListener(this)
|
||||
}
|
||||
|
||||
override fun handlePacket(packet: Packet) {
|
||||
when (packet) {
|
||||
is ReadInventoryPacket -> handleReadInventory(packet)
|
||||
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||
is StackLocationPacket -> handleStackLocation(packet)
|
||||
is ItemStackPacket -> handleItemStack(packet)
|
||||
is CapacityPacket -> handleCapacity(packet)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleReadInventory(packet: ReadInventoryPacket) {
|
||||
inventoryCache[packet.source] = packet.inventory
|
||||
updateNetItems()
|
||||
sync()
|
||||
}
|
||||
|
||||
private fun handleDeviceRemoved(packet: DeviceRemovedPacket) {
|
||||
inventoryCache.remove(packet.source)
|
||||
updateNetItems()
|
||||
sync()
|
||||
}
|
||||
|
||||
private fun handleStackLocation(packet: StackLocationPacket) {
|
||||
val request = pendingRequests.firstOrNull {
|
||||
ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack)
|
||||
}
|
||||
if (request != null) {
|
||||
request.results.add(packet.amount to packet.sourceInterface)
|
||||
if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) {
|
||||
stackLocateRequestCompleted(request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||
val remaining = internalBuffer.insertFromNetwork(packet.stack)
|
||||
|
||||
// this happens outside the normal update loop because by receiving the item stack packet
|
||||
// we "know" how much the count in the source inventory has changed
|
||||
updateNetItems()
|
||||
sync()
|
||||
|
||||
return remaining
|
||||
}
|
||||
|
||||
private fun handleCapacity(packet: CapacityPacket) {
|
||||
val insertion = pendingInsertions.values.firstOrNull {
|
||||
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
|
||||
}
|
||||
if (insertion != null) {
|
||||
insertion.results.add(packet.capacity to packet.receivingInterface)
|
||||
if (insertion.isFinishable(counter)) {
|
||||
finishInsertion(insertion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateNetItems() {
|
||||
cachedNetItems.clear()
|
||||
for (inventory in inventoryCache.values) {
|
||||
for (stack in inventory.storedStacks) {
|
||||
val amount = inventory.getAmount(stack)
|
||||
cachedNetItems.mergeInt(stack, amount) { a, b -> a + b }
|
||||
}
|
||||
}
|
||||
// todo: is the map necessary or is just the sorted list enough?
|
||||
cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
|
||||
val stack = it.key.copy()
|
||||
stack.count = it.intValue
|
||||
stack
|
||||
}
|
||||
}
|
||||
|
||||
private fun beginInsertions() {
|
||||
if (world!!.isClient) return
|
||||
|
||||
for (slot in 0 until internalBuffer.size()) {
|
||||
if (internalBuffer.getMode(slot) != TerminalBufferInventory.Mode.TO_NETWORK) continue
|
||||
if (slot in pendingInsertions) continue
|
||||
val stack = internalBuffer.getStack(slot)
|
||||
pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter)
|
||||
sendToSingle(CheckCapacityPacket(stack, macAddress, MACAddress.BROADCAST))
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishPendingInsertions() {
|
||||
if (world!!.isClient) return
|
||||
|
||||
for (insertion in pendingInsertions.values) {
|
||||
if (!insertion.isFinishable(counter)) continue
|
||||
finishInsertion(insertion)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendEnqueuedLocateRequests() {
|
||||
if (world!!.isClient) return
|
||||
|
||||
for (request in locateRequestQueue) {
|
||||
pendingRequests.add(request)
|
||||
sendToSingle(LocateStackPacket(request.stack, macAddress))
|
||||
}
|
||||
locateRequestQueue.clear()
|
||||
}
|
||||
|
||||
private fun finishPendingRequests() {
|
||||
if (world!!.isClient) return
|
||||
|
||||
for (request in pendingRequests) {
|
||||
if (request.isFinishable(counter)) {
|
||||
stackLocateRequestCompleted(request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addObserver() {
|
||||
observers++
|
||||
}
|
||||
|
||||
fun removeObserver() {
|
||||
observers--
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
if (observers > 0 && (++counter % 10) == 0) {
|
||||
if (world!!.isClient) {
|
||||
println(cachedNetItems)
|
||||
} else {
|
||||
updateNetItems()
|
||||
sendEnqueuedLocateRequests()
|
||||
finishPendingRequests()
|
||||
beginInsertions()
|
||||
finishPendingInsertions()
|
||||
sync()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onActivate(player: PlayerEntity) {
|
||||
if (!world!!.isClient) {
|
||||
updateNetItems()
|
||||
sync()
|
||||
|
||||
inventoryCache.clear()
|
||||
sendToSingle(RequestInventoryPacket(macAddress))
|
||||
val factory = object: ExtendedScreenHandlerFactory {
|
||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
||||
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
||||
}
|
||||
|
||||
override fun getDisplayName() = LiteralText("Terminal")
|
||||
|
||||
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
||||
buf.writeBlockPos(this@TerminalBlockEntity.pos)
|
||||
}
|
||||
}
|
||||
player.openHandledScreen(factory)
|
||||
}
|
||||
addObserver()
|
||||
}
|
||||
|
||||
fun requestItem(stack: ItemStack, amount: Int = stack.count) {
|
||||
locateRequestQueue.add(StackLocateRequest(stack, amount, counter))
|
||||
}
|
||||
|
||||
private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||
pendingRequests.remove(request)
|
||||
|
||||
// todo: also sort results by interface priority
|
||||
val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
|
||||
var amountRequested = 0
|
||||
while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
||||
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
||||
val amountToRequest = min(sourceAmount, request.amount - amountRequested)
|
||||
amountRequested += amountToRequest
|
||||
sendToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress))
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishInsertion(insertion: PendingStackInsertion) {
|
||||
pendingInsertions.remove(insertion.bufferSlot)
|
||||
|
||||
// todo: also sort results by interface priority
|
||||
val sortedResults = insertion.results.sortedBy { it.first }.toMutableList()
|
||||
val remaining = insertion.stack
|
||||
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
||||
val (capacity, receivingInterface) = sortedResults.removeAt(0)
|
||||
if (capacity <= 0) continue
|
||||
sendToSingle(ItemStackPacket(remaining.copy(), macAddress, receivingInterface.macAddress))
|
||||
// todo: the interface should confirm how much was actually inserted, in case of race condition
|
||||
remaining.count -= capacity
|
||||
}
|
||||
internalBuffer.setStack(insertion.bufferSlot, remaining)
|
||||
|
||||
// as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets
|
||||
updateNetItems()
|
||||
sync()
|
||||
}
|
||||
|
||||
override fun onInventoryChanged(inv: Inventory) {
|
||||
if (inv == internalBuffer && world != null && !world!!.isClient) {
|
||||
markDirty()
|
||||
sync()
|
||||
}
|
||||
}
|
||||
|
||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
tag.put("InternalBuffer", internalBuffer.toTag())
|
||||
return super.toTag(tag)
|
||||
}
|
||||
|
||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
super.fromTag(state, tag)
|
||||
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||
}
|
||||
|
||||
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
tag.put("InternalBuffer", internalBuffer.toTag())
|
||||
val list = ListTag()
|
||||
tag.put("CachedNetItems", list)
|
||||
for ((stack, amount) in cachedNetItems) {
|
||||
val entryTag = stack.toTag(CompoundTag())
|
||||
entryTag.putInt("NetAmount", amount)
|
||||
list.add(entryTag)
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
override fun fromClientTag(tag: CompoundTag) {
|
||||
internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||
val list = tag.getList("CachedNetItems", 10)
|
||||
cachedNetItems.clear()
|
||||
for (entryTag in list) {
|
||||
val stack = ItemStack.fromTag(entryTag as CompoundTag)
|
||||
val netAmount = entryTag.getInt("NetAmount")
|
||||
cachedNetItems[stack] = netAmount
|
||||
}
|
||||
cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
|
||||
val stack = it.key.copy()
|
||||
stack.count = it.intValue
|
||||
stack
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class StackLocateRequest(
|
||||
val stack: ItemStack,
|
||||
val amount: Int,
|
||||
val timestamp: Int,
|
||||
var results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf()
|
||||
) {
|
||||
val totalResultAmount: Int
|
||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
|
||||
fun isFinishable(currentTimestamp: Int): Boolean {
|
||||
return totalResultAmount > amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
||||
}
|
||||
}
|
||||
|
||||
data class PendingStackInsertion(
|
||||
val bufferSlot: Int,
|
||||
val stack: ItemStack,
|
||||
val timestamp: Int,
|
||||
val results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf(),
|
||||
) {
|
||||
val totalCapacity: Int
|
||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
|
||||
fun isFinishable(currentTimestamp: Int): Boolean {
|
||||
return totalCapacity > stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT
|
||||
}
|
||||
}
|
||||
//
|
||||
//import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||
//import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||
//import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||
//import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
|
||||
//import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||
//import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
||||
//import net.minecraft.block.BlockState
|
||||
//import net.minecraft.entity.player.PlayerEntity
|
||||
//import net.minecraft.entity.player.PlayerInventory
|
||||
//import net.minecraft.inventory.Inventory
|
||||
//import net.minecraft.inventory.InventoryChangedListener
|
||||
//import net.minecraft.item.ItemStack
|
||||
//import net.minecraft.nbt.CompoundTag
|
||||
//import net.minecraft.nbt.ListTag
|
||||
//import net.minecraft.network.PacketByteBuf
|
||||
//import net.minecraft.screen.ScreenHandler
|
||||
//import net.minecraft.server.network.ServerPlayerEntity
|
||||
//import net.minecraft.text.LiteralText
|
||||
//import net.minecraft.util.Tickable
|
||||
//import net.shadowfacts.phycon.api.packet.Packet
|
||||
//import net.shadowfacts.phycon.api.util.MACAddress
|
||||
//import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||
//import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
//import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
||||
//import net.shadowfacts.phycon.network.component.handleItemStack
|
||||
//import net.shadowfacts.phycon.network.packet.*
|
||||
//import java.util.*
|
||||
//import kotlin.math.min
|
||||
//
|
||||
///**
|
||||
// * @author shadowfacts
|
||||
// */
|
||||
//class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable, ItemStackPacketHandler {
|
||||
//
|
||||
// companion object {
|
||||
// val LOCATE_REQUEST_TIMEOUT = 40 // ticks
|
||||
// val INSERTION_TIMEOUT = 40
|
||||
// }
|
||||
//
|
||||
// private val inventoryCache = mutableMapOf<MACAddress, GroupedItemInv>()
|
||||
// val internalBuffer = TerminalBufferInventory(18)
|
||||
//
|
||||
// private val locateRequestQueue = LinkedList<StackLocateRequest>()
|
||||
// private val pendingRequests = LinkedList<StackLocateRequest>()
|
||||
// private val pendingInsertions = Int2ObjectArrayMap<PendingStackInsertion>()
|
||||
//
|
||||
// private var observers = 0
|
||||
// val cachedNetItems = ItemStackCollections.intMap()
|
||||
// var cachedSortedNetItems = listOf<ItemStack>()
|
||||
// var counter = 0
|
||||
//
|
||||
// init {
|
||||
// internalBuffer.addListener(this)
|
||||
// }
|
||||
//
|
||||
// override fun handlePacket(packet: Packet) {
|
||||
// when (packet) {
|
||||
// is ReadInventoryPacket -> handleReadInventory(packet)
|
||||
// is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||
// is StackLocationPacket -> handleStackLocation(packet)
|
||||
// is ItemStackPacket -> handleItemStack(packet)
|
||||
// is CapacityPacket -> handleCapacity(packet)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun handleReadInventory(packet: ReadInventoryPacket) {
|
||||
// inventoryCache[packet.source] = packet.inventory
|
||||
// updateNetItems()
|
||||
// sync()
|
||||
// }
|
||||
//
|
||||
// private fun handleDeviceRemoved(packet: DeviceRemovedPacket) {
|
||||
// inventoryCache.remove(packet.source)
|
||||
// updateNetItems()
|
||||
// sync()
|
||||
// }
|
||||
//
|
||||
// private fun handleStackLocation(packet: StackLocationPacket) {
|
||||
// val request = pendingRequests.firstOrNull {
|
||||
// ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack)
|
||||
// }
|
||||
// if (request != null) {
|
||||
// request.results.add(packet.amount to packet.sourceInterface)
|
||||
// if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) {
|
||||
// stackLocateRequestCompleted(request)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
||||
// val remaining = internalBuffer.insertFromNetwork(packet.stack)
|
||||
//
|
||||
// // this happens outside the normal update loop because by receiving the item stack packet
|
||||
// // we "know" how much the count in the source inventory has changed
|
||||
// updateNetItems()
|
||||
// sync()
|
||||
//
|
||||
// return remaining
|
||||
// }
|
||||
//
|
||||
// private fun handleCapacity(packet: CapacityPacket) {
|
||||
// val insertion = pendingInsertions.values.firstOrNull {
|
||||
// ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
|
||||
// }
|
||||
// if (insertion != null) {
|
||||
// insertion.results.add(packet.capacity to packet.receivingInterface)
|
||||
// if (insertion.isFinishable(counter)) {
|
||||
// finishInsertion(insertion)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun updateNetItems() {
|
||||
// cachedNetItems.clear()
|
||||
// for (inventory in inventoryCache.values) {
|
||||
// for (stack in inventory.storedStacks) {
|
||||
// val amount = inventory.getAmount(stack)
|
||||
// cachedNetItems.mergeInt(stack, amount) { a, b -> a + b }
|
||||
// }
|
||||
// }
|
||||
// // todo: is the map necessary or is just the sorted list enough?
|
||||
// cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
|
||||
// val stack = it.key.copy()
|
||||
// stack.count = it.intValue
|
||||
// stack
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun beginInsertions() {
|
||||
// if (world!!.isClient) return
|
||||
//
|
||||
// for (slot in 0 until internalBuffer.size()) {
|
||||
// if (internalBuffer.getMode(slot) != TerminalBufferInventory.Mode.TO_NETWORK) continue
|
||||
// if (slot in pendingInsertions) continue
|
||||
// val stack = internalBuffer.getStack(slot)
|
||||
// pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter)
|
||||
// sendToSingle(CheckCapacityPacket(stack, macAddress, MACAddress.BROADCAST))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun finishPendingInsertions() {
|
||||
// if (world!!.isClient) return
|
||||
//
|
||||
// for (insertion in pendingInsertions.values) {
|
||||
// if (!insertion.isFinishable(counter)) continue
|
||||
// finishInsertion(insertion)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun sendEnqueuedLocateRequests() {
|
||||
// if (world!!.isClient) return
|
||||
//
|
||||
// for (request in locateRequestQueue) {
|
||||
// pendingRequests.add(request)
|
||||
// sendToSingle(LocateStackPacket(request.stack, macAddress))
|
||||
// }
|
||||
// locateRequestQueue.clear()
|
||||
// }
|
||||
//
|
||||
// private fun finishPendingRequests() {
|
||||
// if (world!!.isClient) return
|
||||
//
|
||||
// for (request in pendingRequests) {
|
||||
// if (request.isFinishable(counter)) {
|
||||
// stackLocateRequestCompleted(request)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun addObserver() {
|
||||
// observers++
|
||||
// }
|
||||
//
|
||||
// fun removeObserver() {
|
||||
// observers--
|
||||
// }
|
||||
//
|
||||
// override fun tick() {
|
||||
// if (observers > 0 && (++counter % 10) == 0) {
|
||||
// if (world!!.isClient) {
|
||||
// println(cachedNetItems)
|
||||
// } else {
|
||||
// updateNetItems()
|
||||
// sendEnqueuedLocateRequests()
|
||||
// finishPendingRequests()
|
||||
// beginInsertions()
|
||||
// finishPendingInsertions()
|
||||
// sync()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fun onActivate(player: PlayerEntity) {
|
||||
// if (!world!!.isClient) {
|
||||
// updateNetItems()
|
||||
// sync()
|
||||
//
|
||||
// inventoryCache.clear()
|
||||
// sendToSingle(RequestInventoryPacket(macAddress))
|
||||
// val factory = object: ExtendedScreenHandlerFactory {
|
||||
// override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
||||
// return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
||||
// }
|
||||
//
|
||||
// override fun getDisplayName() = LiteralText("Terminal")
|
||||
//
|
||||
// override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
||||
// buf.writeBlockPos(this@TerminalBlockEntity.pos)
|
||||
// }
|
||||
// }
|
||||
// player.openHandledScreen(factory)
|
||||
// }
|
||||
// addObserver()
|
||||
// }
|
||||
//
|
||||
// fun requestItem(stack: ItemStack, amount: Int = stack.count) {
|
||||
// locateRequestQueue.add(StackLocateRequest(stack, amount, counter))
|
||||
// }
|
||||
//
|
||||
// private fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
||||
// pendingRequests.remove(request)
|
||||
//
|
||||
// // todo: also sort results by interface priority
|
||||
// val sortedResults = request.results.sortedByDescending { it.first }.toMutableList()
|
||||
// var amountRequested = 0
|
||||
// while (amountRequested < request.amount && sortedResults.isNotEmpty()) {
|
||||
// val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
||||
// val amountToRequest = min(sourceAmount, request.amount - amountRequested)
|
||||
// amountRequested += amountToRequest
|
||||
// sendToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun finishInsertion(insertion: PendingStackInsertion) {
|
||||
// pendingInsertions.remove(insertion.bufferSlot)
|
||||
//
|
||||
// // todo: also sort results by interface priority
|
||||
// val sortedResults = insertion.results.sortedBy { it.first }.toMutableList()
|
||||
// val remaining = insertion.stack
|
||||
// while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
||||
// val (capacity, receivingInterface) = sortedResults.removeAt(0)
|
||||
// if (capacity <= 0) continue
|
||||
// sendToSingle(ItemStackPacket(remaining.copy(), macAddress, receivingInterface.macAddress))
|
||||
// // todo: the interface should confirm how much was actually inserted, in case of race condition
|
||||
// remaining.count -= capacity
|
||||
// }
|
||||
// internalBuffer.setStack(insertion.bufferSlot, remaining)
|
||||
//
|
||||
// // as with extracting, we "know" the new amounts and so can update instantly without actually sending out packets
|
||||
// updateNetItems()
|
||||
// sync()
|
||||
// }
|
||||
//
|
||||
// override fun onInventoryChanged(inv: Inventory) {
|
||||
// if (inv == internalBuffer && world != null && !world!!.isClient) {
|
||||
// markDirty()
|
||||
// sync()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun toTag(tag: CompoundTag): CompoundTag {
|
||||
// tag.put("InternalBuffer", internalBuffer.toTag())
|
||||
// return super.toTag(tag)
|
||||
// }
|
||||
//
|
||||
// override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||
// super.fromTag(state, tag)
|
||||
// internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||
// }
|
||||
//
|
||||
// override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||
// tag.put("InternalBuffer", internalBuffer.toTag())
|
||||
// val list = ListTag()
|
||||
// tag.put("CachedNetItems", list)
|
||||
// for ((stack, amount) in cachedNetItems) {
|
||||
// val entryTag = stack.toTag(CompoundTag())
|
||||
// entryTag.putInt("NetAmount", amount)
|
||||
// list.add(entryTag)
|
||||
// }
|
||||
// return tag
|
||||
// }
|
||||
//
|
||||
// override fun fromClientTag(tag: CompoundTag) {
|
||||
// internalBuffer.fromTag(tag.getCompound("InternalBuffer"))
|
||||
// val list = tag.getList("CachedNetItems", 10)
|
||||
// cachedNetItems.clear()
|
||||
// for (entryTag in list) {
|
||||
// val stack = ItemStack.fromTag(entryTag as CompoundTag)
|
||||
// val netAmount = entryTag.getInt("NetAmount")
|
||||
// cachedNetItems[stack] = netAmount
|
||||
// }
|
||||
// cachedSortedNetItems = cachedNetItems.object2IntEntrySet().sortedByDescending { it.intValue }.map {
|
||||
// val stack = it.key.copy()
|
||||
// stack.count = it.intValue
|
||||
// stack
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
//data class StackLocateRequest(
|
||||
// val stack: ItemStack,
|
||||
// val amount: Int,
|
||||
// val timestamp: Int,
|
||||
// var results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf()
|
||||
//) {
|
||||
// val totalResultAmount: Int
|
||||
// get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
//
|
||||
// fun isFinishable(currentTimestamp: Int): Boolean {
|
||||
// return totalResultAmount > amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//data class PendingStackInsertion(
|
||||
// val bufferSlot: Int,
|
||||
// val stack: ItemStack,
|
||||
// val timestamp: Int,
|
||||
// val results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf(),
|
||||
//) {
|
||||
// val totalCapacity: Int
|
||||
// get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||
//
|
||||
// fun isFinishable(currentTimestamp: Int): Boolean {
|
||||
// return totalCapacity > stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -1,61 +1,61 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.inventory.Inventory
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class TerminalFakeSlot(val terminal: TerminalBlockEntity, slot: Int, x: Int, y: Int): Slot(FakeInventory(terminal, slot), slot, x, y) {
|
||||
|
||||
override fun canInsert(stack: ItemStack): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setStack(stack: ItemStack) {
|
||||
}
|
||||
|
||||
override fun canTakeItems(player: PlayerEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FakeInventory(val terminal: TerminalBlockEntity, val slot: Int): Inventory {
|
||||
override fun getStack(_slot: Int): ItemStack {
|
||||
if (slot >= terminal.cachedSortedNetItems.size) return ItemStack.EMPTY
|
||||
return terminal.cachedSortedNetItems[slot]
|
||||
}
|
||||
|
||||
override fun markDirty() {
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
}
|
||||
|
||||
override fun setStack(p0: Int, p1: ItemStack?) {
|
||||
}
|
||||
|
||||
override fun removeStack(p0: Int): ItemStack {
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
|
||||
override fun canPlayerUse(p0: PlayerEntity?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
override fun removeStack(p0: Int, p1: Int): ItemStack {
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
//import net.minecraft.screen.slot.Slot
|
||||
//import net.minecraft.entity.player.PlayerEntity
|
||||
//import net.minecraft.inventory.Inventory
|
||||
//import net.minecraft.item.ItemStack
|
||||
//
|
||||
///**
|
||||
// * @author shadowfacts
|
||||
// */
|
||||
//class TerminalFakeSlot(val terminal: TerminalBlockEntity, slot: Int, x: Int, y: Int): Slot(FakeInventory(terminal, slot), slot, x, y) {
|
||||
//
|
||||
// override fun canInsert(stack: ItemStack): Boolean {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// override fun setStack(stack: ItemStack) {
|
||||
// }
|
||||
//
|
||||
// override fun canTakeItems(player: PlayerEntity): Boolean {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
//class FakeInventory(val terminal: TerminalBlockEntity, val slot: Int): Inventory {
|
||||
// override fun getStack(_slot: Int): ItemStack {
|
||||
// if (slot >= terminal.cachedSortedNetItems.size) return ItemStack.EMPTY
|
||||
// return terminal.cachedSortedNetItems[slot]
|
||||
// }
|
||||
//
|
||||
// override fun markDirty() {
|
||||
// }
|
||||
//
|
||||
// override fun clear() {
|
||||
// }
|
||||
//
|
||||
// override fun setStack(p0: Int, p1: ItemStack?) {
|
||||
// }
|
||||
//
|
||||
// override fun removeStack(p0: Int): ItemStack {
|
||||
// return ItemStack.EMPTY
|
||||
// }
|
||||
//
|
||||
// override fun canPlayerUse(p0: PlayerEntity?): Boolean {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// override fun size(): Int {
|
||||
// return 1
|
||||
// }
|
||||
//
|
||||
// override fun removeStack(p0: Int, p1: Int): ItemStack {
|
||||
// return ItemStack.EMPTY
|
||||
// }
|
||||
//
|
||||
// override fun isEmpty(): Boolean {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -1,58 +1,58 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import net.minecraft.client.gui.DrawableHelper
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.text.LiteralText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
// todo: translate title
|
||||
class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen<TerminalScreenHandler>(handler, playerInv, title) {
|
||||
companion object {
|
||||
val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
|
||||
}
|
||||
|
||||
init {
|
||||
backgroundWidth = 252
|
||||
backgroundHeight = 222
|
||||
}
|
||||
|
||||
override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
|
||||
textRenderer.draw(matrixStack, title, 65f, 6f, 0x404040)
|
||||
textRenderer.draw(matrixStack, playerInventory.displayName, 65f, backgroundHeight - 94f, 0x404040)
|
||||
// todo: translate this
|
||||
textRenderer.draw(matrixStack, "Buffer", 7f, 6f, 0x404040)
|
||||
}
|
||||
|
||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||
GlStateManager.color4f(1f, 1f, 1f, 1f)
|
||||
client!!.textureManager.bindTexture(BACKGROUND)
|
||||
val x = (width - backgroundWidth) / 2
|
||||
val y = (height - backgroundHeight) / 2
|
||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) {
|
||||
if (!handler.isBufferSlot(slot.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
val mode = handler.terminal.internalBuffer.getMode(slot.id - handler.bufferSlotsStart)
|
||||
val color: UInt = when (mode) {
|
||||
TerminalBufferInventory.Mode.TO_NETWORK -> 0xFFFF0000u
|
||||
TerminalBufferInventory.Mode.FROM_NETWORK -> 0xFF00FF00u
|
||||
else -> return
|
||||
}
|
||||
DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
|
||||
}
|
||||
|
||||
}
|
||||
//
|
||||
//import com.mojang.blaze3d.platform.GlStateManager
|
||||
//import net.minecraft.client.gui.DrawableHelper
|
||||
//import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||
//import net.minecraft.client.util.math.MatrixStack
|
||||
//import net.minecraft.entity.player.PlayerInventory
|
||||
//import net.minecraft.screen.slot.Slot
|
||||
//import net.minecraft.text.LiteralText
|
||||
//import net.minecraft.text.Text
|
||||
//import net.minecraft.util.Identifier
|
||||
//import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
//
|
||||
///**
|
||||
// * @author shadowfacts
|
||||
// */
|
||||
//// todo: translate title
|
||||
//class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen<TerminalScreenHandler>(handler, playerInv, title) {
|
||||
// companion object {
|
||||
// val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
|
||||
// }
|
||||
//
|
||||
// init {
|
||||
// backgroundWidth = 252
|
||||
// backgroundHeight = 222
|
||||
// }
|
||||
//
|
||||
// override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
|
||||
// textRenderer.draw(matrixStack, title, 65f, 6f, 0x404040)
|
||||
// textRenderer.draw(matrixStack, playerInventory.displayName, 65f, backgroundHeight - 94f, 0x404040)
|
||||
// // todo: translate this
|
||||
// textRenderer.draw(matrixStack, "Buffer", 7f, 6f, 0x404040)
|
||||
// }
|
||||
//
|
||||
// override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||
// GlStateManager.color4f(1f, 1f, 1f, 1f)
|
||||
// client!!.textureManager.bindTexture(BACKGROUND)
|
||||
// val x = (width - backgroundWidth) / 2
|
||||
// val y = (height - backgroundHeight) / 2
|
||||
// drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||
// }
|
||||
//
|
||||
// @ExperimentalUnsignedTypes
|
||||
// fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) {
|
||||
// if (!handler.isBufferSlot(slot.id)) {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// val mode = handler.terminal.internalBuffer.getMode(slot.id - handler.bufferSlotsStart)
|
||||
// val color: UInt = when (mode) {
|
||||
// TerminalBufferInventory.Mode.TO_NETWORK -> 0xFFFF0000u
|
||||
// TerminalBufferInventory.Mode.FROM_NETWORK -> 0xFF00FF00u
|
||||
// else -> return
|
||||
// }
|
||||
// DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -1,161 +1,161 @@
|
|||
package net.shadowfacts.phycon.network.block.terminal
|
||||
|
||||
import net.minecraft.screen.slot.Slot
|
||||
import net.minecraft.screen.slot.SlotActionType
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
import net.shadowfacts.phycon.init.PhyBlocks
|
||||
import net.shadowfacts.phycon.init.PhyScreens
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL_SCREEN_HANDLER, syncId) {
|
||||
|
||||
companion object {
|
||||
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
||||
}
|
||||
|
||||
constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
|
||||
this(syncId, playerInv, PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!)
|
||||
|
||||
init {
|
||||
// network
|
||||
for (y in 0 until 6) {
|
||||
for (x in 0 until 9) {
|
||||
addSlot(TerminalFakeSlot(terminal, y * 9 + x, 66 + x * 18, 18 + y * 18))
|
||||
}
|
||||
}
|
||||
|
||||
// internal buffer
|
||||
for (y in 0 until 6) {
|
||||
for (x in 0 until 3) {
|
||||
addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18))
|
||||
}
|
||||
}
|
||||
|
||||
// player inv
|
||||
for (y in 0 until 3) {
|
||||
for (x in 0 until 9) {
|
||||
addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18))
|
||||
}
|
||||
}
|
||||
// hotbar
|
||||
for (x in 0 until 9) {
|
||||
addSlot(Slot(playerInv, x, 66 + x * 18, 198))
|
||||
}
|
||||
}
|
||||
|
||||
override fun canUse(player: PlayerEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun close(player: PlayerEntity) {
|
||||
super.close(player)
|
||||
|
||||
terminal.removeObserver()
|
||||
}
|
||||
|
||||
override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
|
||||
if (isNetworkSlot(slotId)) {
|
||||
// the slot clicked was one of the network stacks
|
||||
if (actionType == SlotActionType.QUICK_MOVE) {
|
||||
val stack = slots[slotId].stack
|
||||
if (!stack.isEmpty && !player.world.isClient) {
|
||||
terminal.requestItem(stack, min(stack.count, stack.maxCount))
|
||||
}
|
||||
} else if (actionType == SlotActionType.PICKUP && clickData == 1) {
|
||||
if (clickData == 1) {
|
||||
// right click, request half stack
|
||||
val stack = slots[slotId].stack
|
||||
if (!stack.isEmpty && !player.world.isClient) {
|
||||
terminal.requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt())
|
||||
}
|
||||
} else {
|
||||
// todo: left click, show amount dialog
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY
|
||||
} else if (isBufferSlot(slotId)) {
|
||||
// internal buffer
|
||||
// todo: why does this think it's quick_craft sometimes?
|
||||
if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) {
|
||||
// placing cursor stack into buffer
|
||||
val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index
|
||||
terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
|
||||
}
|
||||
}
|
||||
return super.onSlotClick(slotId, clickData, actionType, player)
|
||||
}
|
||||
|
||||
override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||
if (isNetworkSlot(slotId)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
val slot = slots[slotId]
|
||||
if (!slot.hasStack()) {
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
|
||||
val result = slot.stack.copy()
|
||||
|
||||
if (isBufferSlot(slotId)) {
|
||||
if (!insertItem(slot.stack, playerSlotsStart, playerSlotsEnd, false)) {
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
if (slot.stack.isEmpty) {
|
||||
terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED)
|
||||
}
|
||||
} else if (isPlayerSlot(slotId)) {
|
||||
val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK }
|
||||
slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) }
|
||||
if (slot.stack.isEmpty) {
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun tryInsertItem(stack: ItemStack, slots: IntRange, slotPredicate: (Int) -> Boolean): Collection<Int> {
|
||||
val slotsInsertedInto = mutableListOf<Int>()
|
||||
for (index in slots) {
|
||||
if (stack.isEmpty) break
|
||||
if (!slotPredicate(index)) continue
|
||||
|
||||
val slot = this.slots[index]
|
||||
val slotStack = slot.stack
|
||||
if (slotStack.isEmpty) {
|
||||
slot.stack = stack.copy()
|
||||
stack.count = 0
|
||||
|
||||
slot.markDirty()
|
||||
slotsInsertedInto.add(index)
|
||||
} else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) {
|
||||
val maxToMove = slotStack.maxCount - slotStack.count
|
||||
val toMove = min(maxToMove, stack.count)
|
||||
slotStack.increment(toMove)
|
||||
stack.decrement(toMove)
|
||||
|
||||
slot.markDirty()
|
||||
slotsInsertedInto.add(index)
|
||||
}
|
||||
}
|
||||
return slotsInsertedInto
|
||||
}
|
||||
|
||||
val bufferSlotsStart = 54
|
||||
val playerSlotsStart = 72
|
||||
val playerSlotsEnd = 72 + 36
|
||||
fun isNetworkSlot(id: Int) = id in 0 until bufferSlotsStart
|
||||
fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart
|
||||
fun isPlayerSlot(id: Int) = id >= playerSlotsStart
|
||||
}
|
||||
//
|
||||
//import net.minecraft.screen.slot.Slot
|
||||
//import net.minecraft.screen.slot.SlotActionType
|
||||
//import net.minecraft.entity.player.PlayerEntity
|
||||
//import net.minecraft.entity.player.PlayerInventory
|
||||
//import net.minecraft.item.ItemStack
|
||||
//import net.minecraft.network.PacketByteBuf
|
||||
//import net.minecraft.screen.ScreenHandler
|
||||
//import net.minecraft.util.Identifier
|
||||
//import net.shadowfacts.phycon.PhysicalConnectivity
|
||||
//import net.shadowfacts.phycon.init.PhyBlocks
|
||||
//import net.shadowfacts.phycon.init.PhyScreens
|
||||
//import kotlin.math.ceil
|
||||
//import kotlin.math.min
|
||||
//
|
||||
///**
|
||||
// * @author shadowfacts
|
||||
// */
|
||||
//class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): ScreenHandler(PhyScreens.TERMINAL_SCREEN_HANDLER, syncId) {
|
||||
//
|
||||
// companion object {
|
||||
// val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
||||
// }
|
||||
//
|
||||
// constructor(syncId: Int, playerInv: PlayerInventory, buf: PacketByteBuf):
|
||||
// this(syncId, playerInv, PhyBlocks.TERMINAL.getBlockEntity(playerInv.player.world, buf.readBlockPos())!!)
|
||||
//
|
||||
// init {
|
||||
// // network
|
||||
// for (y in 0 until 6) {
|
||||
// for (x in 0 until 9) {
|
||||
// addSlot(TerminalFakeSlot(terminal, y * 9 + x, 66 + x * 18, 18 + y * 18))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // internal buffer
|
||||
// for (y in 0 until 6) {
|
||||
// for (x in 0 until 3) {
|
||||
// addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // player inv
|
||||
// for (y in 0 until 3) {
|
||||
// for (x in 0 until 9) {
|
||||
// addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18))
|
||||
// }
|
||||
// }
|
||||
// // hotbar
|
||||
// for (x in 0 until 9) {
|
||||
// addSlot(Slot(playerInv, x, 66 + x * 18, 198))
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun canUse(player: PlayerEntity): Boolean {
|
||||
// return true
|
||||
// }
|
||||
//
|
||||
// override fun close(player: PlayerEntity) {
|
||||
// super.close(player)
|
||||
//
|
||||
// terminal.removeObserver()
|
||||
// }
|
||||
//
|
||||
// override fun onSlotClick(slotId: Int, clickData: Int, actionType: SlotActionType, player: PlayerEntity): ItemStack {
|
||||
// if (isNetworkSlot(slotId)) {
|
||||
// // the slot clicked was one of the network stacks
|
||||
// if (actionType == SlotActionType.QUICK_MOVE) {
|
||||
// val stack = slots[slotId].stack
|
||||
// if (!stack.isEmpty && !player.world.isClient) {
|
||||
// terminal.requestItem(stack, min(stack.count, stack.maxCount))
|
||||
// }
|
||||
// } else if (actionType == SlotActionType.PICKUP && clickData == 1) {
|
||||
// if (clickData == 1) {
|
||||
// // right click, request half stack
|
||||
// val stack = slots[slotId].stack
|
||||
// if (!stack.isEmpty && !player.world.isClient) {
|
||||
// terminal.requestItem(stack, ceil(min(stack.count, stack.maxCount) / 2f).toInt())
|
||||
// }
|
||||
// } else {
|
||||
// // todo: left click, show amount dialog
|
||||
// }
|
||||
// }
|
||||
// return ItemStack.EMPTY
|
||||
// } else if (isBufferSlot(slotId)) {
|
||||
// // internal buffer
|
||||
// // todo: why does this think it's quick_craft sometimes?
|
||||
// if ((actionType == SlotActionType.PICKUP || actionType == SlotActionType.QUICK_CRAFT) && !player.inventory.cursorStack.isEmpty) {
|
||||
// // placing cursor stack into buffer
|
||||
// val bufferSlot = slotId - bufferSlotsStart // subtract 54 to convert the handler slot ID to a valid buffer index
|
||||
// terminal.internalBuffer.markSlot(bufferSlot, TerminalBufferInventory.Mode.TO_NETWORK)
|
||||
// }
|
||||
// }
|
||||
// return super.onSlotClick(slotId, clickData, actionType, player)
|
||||
// }
|
||||
//
|
||||
// override fun transferSlot(player: PlayerEntity, slotId: Int): ItemStack {
|
||||
// if (isNetworkSlot(slotId)) {
|
||||
// return ItemStack.EMPTY;
|
||||
// }
|
||||
//
|
||||
// val slot = slots[slotId]
|
||||
// if (!slot.hasStack()) {
|
||||
// return ItemStack.EMPTY
|
||||
// }
|
||||
//
|
||||
// val result = slot.stack.copy()
|
||||
//
|
||||
// if (isBufferSlot(slotId)) {
|
||||
// if (!insertItem(slot.stack, playerSlotsStart, playerSlotsEnd, false)) {
|
||||
// return ItemStack.EMPTY
|
||||
// }
|
||||
// if (slot.stack.isEmpty) {
|
||||
// terminal.internalBuffer.markSlot(slotId - bufferSlotsStart, TerminalBufferInventory.Mode.UNASSIGNED)
|
||||
// }
|
||||
// } else if (isPlayerSlot(slotId)) {
|
||||
// val slotsInsertedInto = tryInsertItem(slot.stack, bufferSlotsStart until playerSlotsStart) { terminal.internalBuffer.getMode(it - bufferSlotsStart) != TerminalBufferInventory.Mode.FROM_NETWORK }
|
||||
// slotsInsertedInto.forEach { terminal.internalBuffer.markSlot(it - bufferSlotsStart, TerminalBufferInventory.Mode.TO_NETWORK) }
|
||||
// if (slot.stack.isEmpty) {
|
||||
// return ItemStack.EMPTY
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return result
|
||||
// }
|
||||
//
|
||||
// private fun tryInsertItem(stack: ItemStack, slots: IntRange, slotPredicate: (Int) -> Boolean): Collection<Int> {
|
||||
// val slotsInsertedInto = mutableListOf<Int>()
|
||||
// for (index in slots) {
|
||||
// if (stack.isEmpty) break
|
||||
// if (!slotPredicate(index)) continue
|
||||
//
|
||||
// val slot = this.slots[index]
|
||||
// val slotStack = slot.stack
|
||||
// if (slotStack.isEmpty) {
|
||||
// slot.stack = stack.copy()
|
||||
// stack.count = 0
|
||||
//
|
||||
// slot.markDirty()
|
||||
// slotsInsertedInto.add(index)
|
||||
// } else if (canStacksCombine(slotStack, stack) && slotStack.count < slotStack.maxCount) {
|
||||
// val maxToMove = slotStack.maxCount - slotStack.count
|
||||
// val toMove = min(maxToMove, stack.count)
|
||||
// slotStack.increment(toMove)
|
||||
// stack.decrement(toMove)
|
||||
//
|
||||
// slot.markDirty()
|
||||
// slotsInsertedInto.add(index)
|
||||
// }
|
||||
// }
|
||||
// return slotsInsertedInto
|
||||
// }
|
||||
//
|
||||
// val bufferSlotsStart = 54
|
||||
// val playerSlotsStart = 72
|
||||
// val playerSlotsEnd = 72 + 36
|
||||
// fun isNetworkSlot(id: Int) = id in 0 until bufferSlotsStart
|
||||
// fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart
|
||||
// fun isPlayerSlot(id: Int) = id >= playerSlotsStart
|
||||
//}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
}
|
|
@ -26,6 +26,6 @@ fun <BE> BE.handleItemStack(packet: ItemStackPacket) where BE: BlockEntity, BE:
|
|||
val remainder = doHandleItemStack(packet)
|
||||
// if there are any items remaining, send them back to the source with incremented bounce count
|
||||
if (!remainder.isEmpty) {
|
||||
sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source))
|
||||
// sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source))
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.shadowfacts.phycon.api.packet.Packet
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class BasePacket(
|
||||
@JvmField private val source: MACAddress,
|
||||
@JvmField private val destination: MACAddress
|
||||
@JvmField private val source: IPAddress,
|
||||
@JvmField private val destination: IPAddress
|
||||
): Packet {
|
||||
|
||||
override fun getSource() = source
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
||||
}
|
||||
//class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||
//}
|
|
@ -1,10 +1,10 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class CheckCapacityPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
||||
class CheckCapacityPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class DeviceRemovedPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) {
|
||||
constructor(device: DeviceBlockEntity): this(device.macAddress)
|
||||
class DeviceRemovedPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) {
|
||||
constructor(device: DeviceBlockEntity): this(device.ipAddress)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
||||
class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
||||
constructor(stack: ItemStack, source: MACAddress, destination: MACAddress): this(stack, 0, source, destination)
|
||||
class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||
constructor(stack: ItemStack, source: IPAddress, destination: IPAddress): this(stack, 0, source, destination)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class LocateStackPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) {
|
||||
class LocateStackPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) {
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ReadInventoryPacket(
|
||||
val inventory: GroupedItemInv,
|
||||
source: MACAddress,
|
||||
destination: MACAddress
|
||||
source: IPAddress,
|
||||
destination: IPAddress
|
||||
): BasePacket(source, destination)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class RequestInventoryPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination)
|
||||
class RequestInventoryPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination)
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
package net.shadowfacts.phycon.network.packet
|
||||
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.shadowfacts.phycon.api.util.MACAddress
|
||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
import net.shadowfacts.phycon.api.util.IPAddress
|
||||
//import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
// todo: better name with LocateStackPacket
|
||||
class StackLocationPacket(
|
||||
val stack: ItemStack,
|
||||
val amount: Int,
|
||||
val sourceInterface: InterfaceBlockEntity,
|
||||
source: MACAddress,
|
||||
destination: MACAddress
|
||||
): BasePacket(source, destination) {
|
||||
}
|
||||
//class StackLocationPacket(
|
||||
// val stack: ItemStack,
|
||||
// val amount: Int,
|
||||
// val sourceInterface: InterfaceBlockEntity,
|
||||
// source: IPAddress,
|
||||
// destination: IPAddress
|
||||
//): BasePacket(source, destination) {
|
||||
//}
|
||||
|
|
Loading…
Reference in New Issue