Compare commits
13 Commits
26134cea9d
...
0f7689d73c
Author | SHA1 | Date |
---|---|---|
Shadowfacts | 0f7689d73c | |
Shadowfacts | 649408c509 | |
Shadowfacts | 0dcb647de4 | |
Shadowfacts | e0dfefb72b | |
Shadowfacts | 583afd3dc9 | |
Shadowfacts | 633f9d94aa | |
Shadowfacts | 6b340740ce | |
Shadowfacts | 584d8cd04e | |
Shadowfacts | 446a2a42c3 | |
Shadowfacts | 27713aedba | |
Shadowfacts | c8cdf425cb | |
Shadowfacts | fc3716153f | |
Shadowfacts | e8425b80fd |
|
@ -0,0 +1,19 @@
|
||||||
|
package net.shadowfacts.phycon.api;
|
||||||
|
|
||||||
|
import net.shadowfacts.phycon.api.frame.EthernetFrame;
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,6 @@ package net.shadowfacts.phycon.api;
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @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,16 +1,12 @@
|
||||||
package net.shadowfacts.phycon.api;
|
package net.shadowfacts.phycon.api;
|
||||||
|
|
||||||
import net.shadowfacts.phycon.api.packet.Packet;
|
import net.shadowfacts.phycon.api.packet.Packet;
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
public interface PacketSink {
|
public interface PacketSink extends NetworkDevice {
|
||||||
|
|
||||||
@NotNull
|
|
||||||
MACAddress getMACAddress();
|
|
||||||
|
|
||||||
void handle(@NotNull Packet packet);
|
void handle(@NotNull Packet packet);
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
package net.shadowfacts.phycon.api;
|
package net.shadowfacts.phycon.api;
|
||||||
|
|
||||||
import net.shadowfacts.phycon.api.packet.Packet;
|
import net.shadowfacts.phycon.api.packet.Packet;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
public interface PacketSource {
|
// todo: does PacketSource actually need to extend NetworkDevice?
|
||||||
|
public interface PacketSource extends NetworkDevice {
|
||||||
// todo: better name for this
|
// todo: better name for this
|
||||||
void sendToSingle(Packet packet);
|
void sendPacket(@NotNull Packet packet);
|
||||||
|
|
||||||
void sendToAll(Packet packet);
|
// void sendToAll(@NotNull Packet packet);
|
||||||
|
//
|
||||||
void sendToAll(Packet packet, Iterable<PacketSink> destinations);
|
// void sendToAll(@NotNull Packet packet, @NotNull Iterable<PacketSink> destinations);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,5 @@ import alexiil.mc.lib.attributes.Attributes;
|
||||||
public class PhyAttributes {
|
public class PhyAttributes {
|
||||||
|
|
||||||
public static final Attribute<PacketSink> PACKET_SINK = Attributes.create(PacketSink.class);
|
public static final Attribute<PacketSink> PACKET_SINK = Attributes.create(PacketSink.class);
|
||||||
public static final Attribute<NetworkInterface> NETWORK_INTERFACE = Attributes.create(NetworkInterface.class);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
package net.shadowfacts.phycon.api.packet;
|
||||||
|
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress;
|
import net.shadowfacts.phycon.api.util.IPAddress;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,9 +9,9 @@ import org.jetbrains.annotations.NotNull;
|
||||||
public interface Packet {
|
public interface Packet {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
MACAddress getSource();
|
IPAddress getSource();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
MACAddress getDestination();
|
IPAddress getDestination();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
public static final MACAddress BROADCAST = new MACAddress(0xffffffffffffL);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public static MACAddress random(Random random) {
|
public static MACAddress random(Random random) {
|
||||||
long value = random.nextLong() & 0xfeffffffffffL;
|
long value = random.nextLong() & 0xfeffffffffffL;
|
||||||
return new MACAddress(value);
|
return new MACAddress(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Random macAddressRandom = new Random();
|
private static final Random macAddressRandom = new Random();
|
||||||
|
@NotNull
|
||||||
public static MACAddress random() {
|
public static MACAddress random() {
|
||||||
return random(macAddressRandom);
|
return random(macAddressRandom);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import net.fabricmc.api.ModInitializer
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.init.PhyBlocks
|
import net.shadowfacts.phycon.init.PhyBlocks
|
||||||
import net.shadowfacts.phycon.init.PhyItems
|
import net.shadowfacts.phycon.init.PhyItems
|
||||||
|
import net.shadowfacts.phycon.init.PhyScreens
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -16,6 +17,7 @@ object PhysicalConnectivity: ModInitializer {
|
||||||
PhyBlocks.init()
|
PhyBlocks.init()
|
||||||
PhyBlockEntities.init()
|
PhyBlockEntities.init()
|
||||||
PhyItems.init()
|
PhyItems.init()
|
||||||
|
PhyScreens.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,20 @@ import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.block.entity.BlockEntityType
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
|
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlockEntity
|
||||||
|
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.miner.MinerBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity
|
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
|
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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -20,15 +28,25 @@ object PhyBlockEntities {
|
||||||
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
|
val INTERFACE = create(::InterfaceBlockEntity, PhyBlocks.INTERFACE)
|
||||||
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
val TERMINAL = create(::TerminalBlockEntity, PhyBlocks.TERMINAL)
|
||||||
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
val SWITCH = create(::SwitchBlockEntity, PhyBlocks.SWITCH)
|
||||||
|
val EXTRACTOR = create(::ExtractorBlockEntity, PhyBlocks.EXTRACTOR)
|
||||||
|
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
|
||||||
|
|
||||||
|
val SOURCE = create(::SourceBlockEntity, PhyBlocks.SOURCE)
|
||||||
|
val DEST = create(::DestBlockEntity, PhyBlocks.DEST)
|
||||||
|
|
||||||
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
private fun <T: BlockEntity> create(builder: () -> T, block: Block): BlockEntityType<T> {
|
||||||
return BlockEntityType.Builder.create(builder, arrayOf(block)).build(null)
|
return BlockEntityType.Builder.create(builder, block).build(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(InterfaceBlock.ID, INTERFACE)
|
register(InterfaceBlock.ID, INTERFACE)
|
||||||
register(TerminalBlock.ID, TERMINAL)
|
register(TerminalBlock.ID, TERMINAL)
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
|
register(MinerBlock.ID, MINER)
|
||||||
|
|
||||||
|
register(SourceBlock.ID, SOURCE)
|
||||||
|
register(DestBlock.ID, DEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
private fun register(id: Identifier, type: BlockEntityType<*>) {
|
||||||
|
|
|
@ -4,9 +4,13 @@ import net.minecraft.block.Block
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -17,12 +21,22 @@ object PhyBlocks {
|
||||||
val TERMINAL = TerminalBlock()
|
val TERMINAL = TerminalBlock()
|
||||||
val SWITCH = SwitchBlock()
|
val SWITCH = SwitchBlock()
|
||||||
val CABLE = CableBlock()
|
val CABLE = CableBlock()
|
||||||
|
val EXTRACTOR = ExtractorBlock()
|
||||||
|
val MINER = MinerBlock()
|
||||||
|
|
||||||
|
val SOURCE = SourceBlock()
|
||||||
|
val DEST = DestBlock()
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(InterfaceBlock.ID, INTERFACE)
|
register(InterfaceBlock.ID, INTERFACE)
|
||||||
register(TerminalBlock.ID, TERMINAL)
|
register(TerminalBlock.ID, TERMINAL)
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(CableBlock.ID, CABLE)
|
register(CableBlock.ID, CABLE)
|
||||||
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
|
register(MinerBlock.ID, MINER)
|
||||||
|
|
||||||
|
register(SourceBlock.ID, SOURCE)
|
||||||
|
register(DestBlock.ID, DEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, block: Block) {
|
private fun register(id: Identifier, block: Block) {
|
||||||
|
|
|
@ -4,11 +4,16 @@ import net.minecraft.item.BlockItem
|
||||||
import net.minecraft.item.Item
|
import net.minecraft.item.Item
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.minecraft.util.registry.Registry
|
import net.minecraft.util.registry.Registry
|
||||||
|
import net.shadowfacts.phycon.item.ConsoleItem
|
||||||
import net.shadowfacts.phycon.item.ScrewdriverItem
|
import net.shadowfacts.phycon.item.ScrewdriverItem
|
||||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.miner.MinerBlock
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlock
|
||||||
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
import net.shadowfacts.phycon.network.block.netswitch.SwitchBlock
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
import net.shadowfacts.phycon.network.block.terminal.TerminalBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.test.DestBlock
|
||||||
|
import net.shadowfacts.phycon.network.block.test.SourceBlock
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -19,16 +24,28 @@ object PhyItems {
|
||||||
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
val TERMINAL = BlockItem(PhyBlocks.TERMINAL, Item.Settings())
|
||||||
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
|
val SWITCH = BlockItem(PhyBlocks.SWITCH, Item.Settings())
|
||||||
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
|
val CABLE = BlockItem(PhyBlocks.CABLE, Item.Settings())
|
||||||
|
val EXTRACTOR = BlockItem(PhyBlocks.EXTRACTOR, Item.Settings())
|
||||||
|
val MINER = BlockItem(PhyBlocks.MINER, Item.Settings())
|
||||||
|
|
||||||
|
val SOURCE = BlockItem(PhyBlocks.SOURCE, Item.Settings())
|
||||||
|
val DEST = BlockItem(PhyBlocks.DEST , Item.Settings())
|
||||||
|
|
||||||
val SCREWDRIVER = ScrewdriverItem()
|
val SCREWDRIVER = ScrewdriverItem()
|
||||||
|
val CONSOLE = ConsoleItem()
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
register(InterfaceBlock.ID, INTERFACE)
|
register(InterfaceBlock.ID, INTERFACE)
|
||||||
register(TerminalBlock.ID, TERMINAL)
|
register(TerminalBlock.ID, TERMINAL)
|
||||||
register(SwitchBlock.ID, SWITCH)
|
register(SwitchBlock.ID, SWITCH)
|
||||||
register(CableBlock.ID, CABLE)
|
register(CableBlock.ID, CABLE)
|
||||||
|
register(ExtractorBlock.ID, EXTRACTOR)
|
||||||
|
register(MinerBlock.ID, MINER)
|
||||||
|
|
||||||
|
register(SourceBlock.ID, SOURCE)
|
||||||
|
register(DestBlock.ID, DEST)
|
||||||
|
|
||||||
register(ScrewdriverItem.ID, SCREWDRIVER)
|
register(ScrewdriverItem.ID, SCREWDRIVER)
|
||||||
|
register(ConsoleItem.ID, CONSOLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun register(id: Identifier, item: Item) {
|
private fun register(id: Identifier, item: Item) {
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
package net.shadowfacts.phycon.init
|
package net.shadowfacts.phycon.init
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry
|
||||||
|
import net.minecraft.screen.ScreenHandlerType
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
import net.shadowfacts.phycon.network.block.terminal.TerminalScreenHandler
|
||||||
|
|
||||||
object PhyScreens {
|
object PhyScreens {
|
||||||
|
|
||||||
val TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler)
|
lateinit var TERMINAL_SCREEN_HANDLER: ScreenHandlerType<TerminalScreenHandler>
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
TERMINAL_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(Identifier(PhysicalConnectivity.MODID, "terminal"), ::TerminalScreenHandler)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package net.shadowfacts.phycon.item
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType
|
||||||
|
import net.fabricmc.api.Environment
|
||||||
|
import net.minecraft.client.MinecraftClient
|
||||||
|
import net.minecraft.item.Item
|
||||||
|
import net.minecraft.item.ItemUsageContext
|
||||||
|
import net.minecraft.text.LiteralText
|
||||||
|
import net.minecraft.util.ActionResult
|
||||||
|
import net.minecraft.util.Identifier
|
||||||
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.network.DeviceBlock
|
||||||
|
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.screen.DeviceConsoleScreen
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class ConsoleItem: Item(Settings()) {
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier(PhysicalConnectivity.MODID, "console")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun useOnBlock(context: ItemUsageContext): ActionResult {
|
||||||
|
val state = context.world.getBlockState(context.blockPos)
|
||||||
|
val block = state.block
|
||||||
|
if (block is DeviceBlock<*>) {
|
||||||
|
val be = block.getBlockEntity(context.world, context.blockPos)
|
||||||
|
if (be != null) {
|
||||||
|
if (context.world.isClient) {
|
||||||
|
this.openScreen(be)
|
||||||
|
} else {
|
||||||
|
be.sync()
|
||||||
|
}
|
||||||
|
return ActionResult.SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ActionResult.PASS
|
||||||
|
}
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
private fun openScreen(be: DeviceBlockEntity) {
|
||||||
|
val screen = DeviceConsoleScreen(be)
|
||||||
|
MinecraftClient.getInstance().openScreen(screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,13 +3,22 @@ package net.shadowfacts.phycon.network
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.entity.player.PlayerEntity
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
import net.shadowfacts.phycon.api.Interface
|
||||||
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
import net.shadowfacts.phycon.block.BlockWithEntity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithEntity<T>(settings) {
|
abstract class DeviceBlock<T: DeviceBlockEntity>(settings: Settings): BlockWithEntity<T>(settings), NetworkComponentBlock {
|
||||||
|
|
||||||
|
abstract override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction>
|
||||||
|
|
||||||
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||||
|
return getBlockEntity(world, pos)!!
|
||||||
|
}
|
||||||
|
|
||||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
|
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
|
||||||
super.onBreak(world, pos, state, player)
|
super.onBreak(world, pos, state, player)
|
||||||
|
|
|
@ -1,83 +1,174 @@
|
||||||
package net.shadowfacts.phycon.network
|
package net.shadowfacts.phycon.network
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||||
import net.minecraft.block.BlockState
|
import net.minecraft.block.BlockState
|
||||||
import net.minecraft.block.entity.BlockEntity
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.block.entity.BlockEntityType
|
import net.minecraft.block.entity.BlockEntityType
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.util.Tickable
|
||||||
import net.shadowfacts.phycon.api.PacketSink
|
import net.shadowfacts.phycon.api.PacketSink
|
||||||
import net.shadowfacts.phycon.api.PacketSource
|
import net.shadowfacts.phycon.api.PacketSource
|
||||||
|
import net.shadowfacts.phycon.api.Interface
|
||||||
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
|
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
||||||
|
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
|
import net.shadowfacts.phycon.network.frame.ARPQueryFrame
|
||||||
|
import net.shadowfacts.phycon.network.frame.ARPResponseFrame
|
||||||
|
import net.shadowfacts.phycon.network.frame.BasePacketFrame
|
||||||
import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket
|
import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket
|
||||||
|
import java.lang.RuntimeException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), PacketSink, PacketSource {
|
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type),
|
||||||
|
BlockEntityClientSerializable,
|
||||||
|
Tickable,
|
||||||
|
PacketSink,
|
||||||
|
PacketSource,
|
||||||
|
Interface {
|
||||||
|
|
||||||
var macAddress = MACAddress.random()
|
companion object {
|
||||||
|
private const val ARP_RETRY_TIMEOUT = 200
|
||||||
|
}
|
||||||
|
|
||||||
|
var macAddress: MACAddress = MACAddress.random()
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
override fun getMACAddress(): MACAddress {
|
var ipAddress: IPAddress = IPAddress.random()
|
||||||
return macAddress
|
protected set
|
||||||
|
|
||||||
|
private val arpTable = mutableMapOf<IPAddress, MACAddress>()
|
||||||
|
private val packetQueue = LinkedList<PendingPacket>()
|
||||||
|
|
||||||
|
protected var counter: Long = 0
|
||||||
|
|
||||||
|
override fun getIPAddress() = ipAddress
|
||||||
|
override fun getMACAddress() = macAddress
|
||||||
|
|
||||||
|
abstract override fun handle(packet: Packet)
|
||||||
|
|
||||||
|
override fun send(frame: EthernetFrame) {
|
||||||
|
findDestination()?.receive(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(packet: Packet) {
|
override fun receive(frame: EthernetFrame) {
|
||||||
if (acceptsPacket(packet)) {
|
println("$this ($ipAddress, ${macAddress}) received frame from ${frame.source}: $frame")
|
||||||
handlePacket(packet)
|
when (frame) {
|
||||||
|
is ARPQueryFrame -> handleARPQuery(frame)
|
||||||
|
is ARPResponseFrame -> handleARPResponse(frame)
|
||||||
|
is PacketFrame -> {
|
||||||
|
if (frame.packet.destination.isBroadcast || frame.packet.destination == ipAddress) {
|
||||||
|
println("$this ($ipAddress) received packet: ${frame.packet}")
|
||||||
|
handle(frame.packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun handlePacket(packet: Packet)
|
private fun handleARPQuery(frame: ARPQueryFrame) {
|
||||||
|
println("$this ($ipAddress) received ARP query for ${frame.queryIP}")
|
||||||
protected open fun acceptsPacket(packet: Packet): Boolean {
|
arpTable[frame.sourceIP] = frame.source
|
||||||
return when (packet.destination.type) {
|
if (frame.queryIP == ipAddress) {
|
||||||
MACAddress.Type.BROADCAST -> true
|
println("$this ($ipAddress) sending ARP response to ${frame.source} with $macAddress")
|
||||||
MACAddress.Type.UNICAST -> macAddress == packet.destination
|
send(ARPResponseFrame(ipAddress, macAddress, frame.source))
|
||||||
MACAddress.Type.MULTICAST -> acceptsMulticastPacket(packet)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun acceptsMulticastPacket(packet: Packet): Boolean {
|
private fun handleARPResponse(frame: ARPResponseFrame) {
|
||||||
return false
|
arpTable[frame.query] = frame.source
|
||||||
|
println("$this ($ipAddress) received ARP response for ${frame.query} with ${frame.source}")
|
||||||
|
|
||||||
|
val toRemove = packetQueue.filter { (packet, _) ->
|
||||||
|
if (packet.destination == frame.query) {
|
||||||
|
send(BasePacketFrame(packet, macAddress, frame.source))
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
packetQueue.removeAll(toRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun send(packet: Packet, destination: PacketSink) {
|
override fun sendPacket(packet: Packet) {
|
||||||
destination.handle(packet)
|
if (packet.destination.isBroadcast) {
|
||||||
|
send(BasePacketFrame(packet, macAddress, MACAddress.BROADCAST))
|
||||||
|
} else if (arpTable.containsKey(packet.destination)) {
|
||||||
|
send(BasePacketFrame(packet, macAddress, arpTable[packet.destination]!!))
|
||||||
|
} else {
|
||||||
|
packetQueue.add(PendingPacket(packet, counter))
|
||||||
|
|
||||||
|
println("$this ($ipAddress) sending ARP query for ${packet.destination}")
|
||||||
|
send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendToSingle(packet: Packet) {
|
open fun findDestination(): Interface? {
|
||||||
val destinations = NetworkUtil.findDestinations(world!!, pos)
|
val sides = (cachedState.block as NetworkComponentBlock).getNetworkConnectedSides(cachedState, world!!, pos)
|
||||||
if (destinations.size != 1) {
|
if (sides.size != 1) {
|
||||||
// todo: handle this better
|
throw RuntimeException("DeviceBlockEntity.findDestination must be overridden by devices which have more than 1 network connected side")
|
||||||
println("Can't send packet, multiple destinations available: $destinations")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
send(packet, destinations.first())
|
return NetworkUtil.findConnectedInterface(world!!, pos, sides.first())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendToAll(packet: Packet) {
|
override fun tick() {
|
||||||
sendToAll(packet, NetworkUtil.findDestinations(world!!, pos))
|
counter++
|
||||||
}
|
|
||||||
|
|
||||||
override fun sendToAll(packet: Packet, destinations: Iterable<PacketSink>) {
|
if (!world!!.isClient) {
|
||||||
destinations.forEach {
|
val toRemove = packetQueue.filter { entry ->
|
||||||
it.handle(packet)
|
val (packet, timestamp) = entry
|
||||||
|
if (arpTable.containsKey(packet.destination)) {
|
||||||
|
send(BasePacketFrame(packet, macAddress, arpTable[packet.destination]!!))
|
||||||
|
true
|
||||||
|
} else if (counter - timestamp >= ARP_RETRY_TIMEOUT) {
|
||||||
|
send(ARPQueryFrame(packet.destination, ipAddress, macAddress))
|
||||||
|
entry.timestamp = counter
|
||||||
|
// todo: should there be a retry counter?
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
packetQueue.removeAll(toRemove)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toTag(tag: CompoundTag): CompoundTag {
|
override fun toTag(tag: CompoundTag): CompoundTag {
|
||||||
|
tag.putInt("IPAddress", ipAddress.address)
|
||||||
tag.putLong("MACAddress", macAddress.address)
|
tag.putLong("MACAddress", macAddress.address)
|
||||||
return super.toTag(tag)
|
return super.toTag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
override fun fromTag(state: BlockState, tag: CompoundTag) {
|
||||||
super.fromTag(state, tag)
|
super.fromTag(state, tag)
|
||||||
|
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||||
|
macAddress = MACAddress(tag.getLong("MACAddress"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toClientTag(tag: CompoundTag): CompoundTag {
|
||||||
|
tag.putInt("IPAddress", ipAddress.address)
|
||||||
|
tag.putLong("MACAddress", macAddress.address)
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromClientTag(tag: CompoundTag) {
|
||||||
|
ipAddress = IPAddress(tag.getInt("IPAddress"))
|
||||||
macAddress = MACAddress(tag.getLong("MACAddress"))
|
macAddress = MACAddress(tag.getLong("MACAddress"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onBreak() {
|
fun onBreak() {
|
||||||
sendToAll(DeviceRemovedPacket(this))
|
if (!world!!.isClient) {
|
||||||
|
sendPacket(DeviceRemovedPacket(this))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class PendingPacket(
|
||||||
|
val packet: Packet,
|
||||||
|
var timestamp: Long,
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,7 @@ package net.shadowfacts.phycon.network
|
||||||
import net.minecraft.util.math.BlockPos
|
import net.minecraft.util.math.BlockPos
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.shadowfacts.phycon.api.NetworkCable
|
import net.shadowfacts.phycon.api.*
|
||||||
import net.shadowfacts.phycon.api.NetworkComponent
|
|
||||||
import net.shadowfacts.phycon.api.PacketSink
|
|
||||||
import net.shadowfacts.phycon.api.PhyAttributes
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,6 +11,32 @@ import java.util.*
|
||||||
*/
|
*/
|
||||||
object NetworkUtil {
|
object NetworkUtil {
|
||||||
|
|
||||||
|
fun findConnectedInterface(world: World, startPos: BlockPos, startSide: Direction): Interface? {
|
||||||
|
var curSide = startSide
|
||||||
|
var pos = startPos.offset(startSide)
|
||||||
|
var state = world.getBlockState(pos)
|
||||||
|
while (state.block is NetworkComponentBlock) {
|
||||||
|
val block = state.block as NetworkComponentBlock
|
||||||
|
val itf = block.getNetworkInterfaceForSide(curSide.opposite, state, world, pos)
|
||||||
|
if (itf != null) {
|
||||||
|
return itf
|
||||||
|
}
|
||||||
|
val connectedSides = block.getNetworkConnectedSides(state, world, pos).filter { it != curSide.opposite }
|
||||||
|
if (connectedSides.size == 1) {
|
||||||
|
curSide = connectedSides.first()
|
||||||
|
pos = pos.offset(curSide)
|
||||||
|
if (!world.isChunkLoaded(pos)) {
|
||||||
|
// avoid loading unloaded chunks
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
state = world.getBlockState(pos)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List<PacketSink> {
|
fun findDestinations(world: World, startPos: BlockPos, direction: Direction? = null): List<PacketSink> {
|
||||||
val results = LinkedList<PacketSink>()
|
val results = LinkedList<PacketSink>()
|
||||||
val visited = hashSetOf(startPos)
|
val visited = hashSetOf(startPos)
|
||||||
|
@ -43,7 +66,7 @@ object NetworkUtil {
|
||||||
private fun findEdges(queue: MutableList<BlockPos>, visited: Set<BlockPos>, world: World, pos: BlockPos, includeNonCables: Boolean = false) {
|
private fun findEdges(queue: MutableList<BlockPos>, visited: Set<BlockPos>, world: World, pos: BlockPos, includeNonCables: Boolean = false) {
|
||||||
val state = world.getBlockState(pos)
|
val state = world.getBlockState(pos)
|
||||||
val block = state.block
|
val block = state.block
|
||||||
if (block is NetworkComponent && (includeNonCables || block is NetworkCable)) {
|
if (block is NetworkComponentBlock && (includeNonCables || block is NetworkCableBlock)) {
|
||||||
val connections = block.getNetworkConnectedSides(state, world, pos)
|
val connections = block.getNetworkConnectedSides(state, world, pos)
|
||||||
for (side in connections) {
|
for (side in connections) {
|
||||||
val newPos = pos.offset(side)
|
val newPos = pos.offset(side)
|
||||||
|
|
|
@ -19,8 +19,9 @@ import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.NetworkCable
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.NetworkComponent
|
import net.shadowfacts.phycon.api.NetworkCableBlock
|
||||||
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.init.PhyItems
|
import net.shadowfacts.phycon.init.PhyItems
|
||||||
import net.shadowfacts.phycon.util.CableConnection
|
import net.shadowfacts.phycon.util.CableConnection
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -31,7 +32,7 @@ import java.util.*
|
||||||
class CableBlock: Block(
|
class CableBlock: Block(
|
||||||
Settings.of(CABLE_MATERIAL)
|
Settings.of(CABLE_MATERIAL)
|
||||||
.nonOpaque()
|
.nonOpaque()
|
||||||
), NetworkCable {
|
), NetworkCableBlock {
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "cable")
|
val ID = Identifier(PhysicalConnectivity.MODID, "cable")
|
||||||
val CABLE_MATERIAL = Material(MaterialColor.IRON, false, false, true, false, true, false, PistonBehavior.NORMAL)
|
val CABLE_MATERIAL = Material(MaterialColor.IRON, false, false, true, false, true, false, PistonBehavior.NORMAL)
|
||||||
|
@ -108,11 +109,16 @@ class CableBlock: Block(
|
||||||
else -> CableConnection.ON
|
else -> CableConnection.ON
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is NetworkComponent -> CableConnection.ON
|
is NetworkComponentBlock -> CableConnection.ON
|
||||||
else -> CableConnection.OFF
|
else -> CableConnection.OFF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||||
|
// cables don't have network interfaces
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
override fun onUse(
|
override fun onUse(
|
||||||
state: BlockState,
|
state: BlockState,
|
||||||
world: World,
|
world: World,
|
||||||
|
@ -141,7 +147,7 @@ class CableBlock: Block(
|
||||||
world.setBlockState(connectedToPos, connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON))
|
world.setBlockState(connectedToPos, connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON))
|
||||||
}
|
}
|
||||||
|
|
||||||
state.with(prop, if (connectedTo.block is NetworkComponent) CableConnection.ON else CableConnection.OFF)
|
state.with(prop, if (connectedTo.block is NetworkComponentBlock) CableConnection.ON else CableConnection.OFF)
|
||||||
}
|
}
|
||||||
else -> state.with(prop, CableConnection.DISABLED)
|
else -> state.with(prop, CableConnection.DISABLED)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
package net.shadowfacts.phycon.network.block.extractor
|
||||||
|
|
||||||
|
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.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.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
import net.shadowfacts.phycon.api.Interface
|
||||||
|
import net.shadowfacts.phycon.network.DeviceBlock
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class ExtractorBlock: DeviceBlock<ExtractorBlockEntity>(Settings.of(Material.METAL)) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier(PhysicalConnectivity.MODID, "extractor")
|
||||||
|
val FACING = Properties.FACING
|
||||||
|
private val EXTRACTOR_SHAPES = mutableMapOf<Direction, VoxelShape>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val components = arrayOf(
|
||||||
|
doubleArrayOf(0.0, 0.0, 0.0, 16.0, 2.0, 16.0),
|
||||||
|
doubleArrayOf(2.0, 2.0, 2.0, 14.0, 4.0, 14.0),
|
||||||
|
doubleArrayOf(4.0, 4.0, 4.0, 12.0, 6.0, 12.0),
|
||||||
|
doubleArrayOf(6.0, 6.0, 6.0, 10.0, 16.0, 10.0)
|
||||||
|
)
|
||||||
|
val directions = arrayOf(
|
||||||
|
Triple(Direction.DOWN, null, false),
|
||||||
|
Triple(Direction.UP, null, true),
|
||||||
|
Triple(Direction.NORTH, 2, false),
|
||||||
|
Triple(Direction.SOUTH, 2, true),
|
||||||
|
Triple(Direction.WEST, 1, false),
|
||||||
|
Triple(Direction.EAST, 1, true),
|
||||||
|
)
|
||||||
|
for ((dir, rotate, flip) in directions) {
|
||||||
|
val shapes = components.map { it ->
|
||||||
|
val arr = it.copyOf()
|
||||||
|
if (rotate != null) {
|
||||||
|
for (i in 0 until 3) {
|
||||||
|
arr[i] = it[(i + rotate) % 3]
|
||||||
|
arr[3 + i] = it[3 + ((i + rotate) % 3)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flip) {
|
||||||
|
for (i in arr.indices) {
|
||||||
|
arr[i] = 16.0 - arr[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createCuboidShape(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5])
|
||||||
|
}
|
||||||
|
EXTRACTOR_SHAPES[dir] = shapes.reduce { a, b -> VoxelShapes.union(a, b) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
|
||||||
|
return EnumSet.of(state[FACING].opposite)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||||
|
return if (side == state[FACING].opposite) {
|
||||||
|
getBlockEntity(world, pos)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
|
super.appendProperties(builder)
|
||||||
|
builder.add(FACING)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createBlockEntity(world: BlockView) = ExtractorBlockEntity()
|
||||||
|
|
||||||
|
override fun getPlacementState(context: ItemPlacementContext): BlockState {
|
||||||
|
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
||||||
|
return defaultState.with(FACING, facing)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
|
||||||
|
return EXTRACTOR_SHAPES[state[FACING]]!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, stack: ItemStack) {
|
||||||
|
if (!world.isClient) {
|
||||||
|
getBlockEntity(world, pos)!!.updateInventory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighbor: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||||
|
if (!world.isClient) {
|
||||||
|
getBlockEntity(world, pos)!!.updateInventory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package net.shadowfacts.phycon.network.block.extractor
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.SearchOptions
|
||||||
|
import alexiil.mc.lib.attributes.item.FixedItemInv
|
||||||
|
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
||||||
|
import alexiil.mc.lib.attributes.item.ItemAttributes
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
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.DeviceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.network.packet.CapacityPacket
|
||||||
|
import net.shadowfacts.phycon.network.packet.CheckCapacityPacket
|
||||||
|
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class ExtractorBlockEntity: DeviceBlockEntity(PhyBlockEntities.EXTRACTOR) {
|
||||||
|
|
||||||
|
private val facing: Direction
|
||||||
|
get() = cachedState[ExtractorBlock.FACING]
|
||||||
|
|
||||||
|
private var inventory: GroupedItemInv? = null
|
||||||
|
private var shouldExtract = false
|
||||||
|
|
||||||
|
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 (inventory == null) updateInventory()
|
||||||
|
return inventory
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(packet: Packet) {
|
||||||
|
if (packet is CapacityPacket && shouldExtract) {
|
||||||
|
getInventory()?.also { inv ->
|
||||||
|
shouldExtract = false
|
||||||
|
val extracted = inv.extract(packet.stack, packet.capacity)
|
||||||
|
sendPacket(ItemStackPacket(extracted, ipAddress, packet.stackReceiver.ipAddress))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
super.tick()
|
||||||
|
|
||||||
|
if (!world!!.isClient && counter % 40 == 0L) {
|
||||||
|
getInventory()?.also {
|
||||||
|
val stack = it.storedStacks.firstOrNull() ?: return
|
||||||
|
shouldExtract = true
|
||||||
|
sendPacket(CheckCapacityPacket(stack, ipAddress, IPAddress.BROADCAST))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package net.shadowfacts.phycon.network.block.miner
|
||||||
|
|
||||||
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.Material
|
||||||
|
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.Properties
|
||||||
|
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 net.shadowfacts.phycon.network.block.extractor.ExtractorBlock
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class MinerBlock: DeviceBlock<MinerBlockEntity>(Settings.of(Material.METAL)) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ID = Identifier(PhysicalConnectivity.MODID, "miner")
|
||||||
|
val FACING = Properties.FACING
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
|
||||||
|
return EnumSet.of(state[FACING].opposite)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||||
|
return if (side == state[FACING]) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
getBlockEntity(world, pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
|
super.appendProperties(builder)
|
||||||
|
builder.add(FACING)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createBlockEntity(world: BlockView) = MinerBlockEntity()
|
||||||
|
|
||||||
|
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
|
||||||
|
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite
|
||||||
|
return defaultState.with(ExtractorBlock.FACING, facing)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPlaced(world: World, pos: BlockPos, state: BlockState, entity: LivingEntity?, itemStack: ItemStack) {
|
||||||
|
if (!world.isClient) {
|
||||||
|
// getBlockEntity(world, pos)!!.updateBlockToMine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighbor: Block, neighborPos: BlockPos, bl: Boolean) {
|
||||||
|
if (!world.isClient) {
|
||||||
|
// getBlockEntity(world, pos)!!.updateBlockToMine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package net.shadowfacts.phycon.network.block.miner
|
||||||
|
|
||||||
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
|
import alexiil.mc.lib.attributes.item.filter.ItemFilter
|
||||||
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
import net.minecraft.server.world.ServerWorld
|
||||||
|
import net.minecraft.util.math.BlockPos
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.minecraft.world.World
|
||||||
|
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.DeviceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
||||||
|
import net.shadowfacts.phycon.network.packet.*
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
|
||||||
|
NetworkStackProvider {
|
||||||
|
|
||||||
|
private val facing: Direction
|
||||||
|
get() = cachedState[MinerBlock.FACING]
|
||||||
|
|
||||||
|
private val invProxy = MinerInvProxy(this)
|
||||||
|
|
||||||
|
override fun handle(packet: Packet) {
|
||||||
|
when (packet) {
|
||||||
|
is RequestInventoryPacket -> handleRequestInventory(packet)
|
||||||
|
is LocateStackPacket -> handleLocateStack(packet)
|
||||||
|
is ExtractStackPacket -> handleExtractStack(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||||
|
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||||
|
val amount = invProxy.getAmount(packet.stack)
|
||||||
|
if (amount > 0) {
|
||||||
|
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleExtractStack(packet: ExtractStackPacket) {
|
||||||
|
// always recalculate immediately before breaking
|
||||||
|
val drops = invProxy.getDrops(true)
|
||||||
|
if (invProxy.getAmount(packet.stack) > 0) {
|
||||||
|
world!!.breakBlock(pos.offset(facing), false)
|
||||||
|
|
||||||
|
// send the requested amount back to the requester
|
||||||
|
var remaining = packet.amount
|
||||||
|
for (droppedStack in drops) {
|
||||||
|
if (remaining <= 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (!ItemStackUtil.areEqualIgnoreAmounts(droppedStack, packet.stack)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val copy = droppedStack.copy()
|
||||||
|
|
||||||
|
val toDecr = min(droppedStack.count, remaining)
|
||||||
|
droppedStack.decrement(toDecr)
|
||||||
|
remaining -= toDecr
|
||||||
|
|
||||||
|
// todo: should this try to combine stacks and send as few packets as possible?
|
||||||
|
copy.count = toDecr
|
||||||
|
sendPacket(ItemStackPacket(copy, ipAddress, packet.source))
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump any remaining drops into the network
|
||||||
|
for (droppedStack in drops) {
|
||||||
|
if (droppedStack.isEmpty) continue
|
||||||
|
sendPacket(ItemStackPacket(droppedStack, ipAddress, IPAddress.BROADCAST))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
|
||||||
|
private var cachedState: BlockState? = null
|
||||||
|
private var cachedDrops: List<ItemStack>? = null
|
||||||
|
|
||||||
|
private val world: World
|
||||||
|
get() = miner.world!!
|
||||||
|
private val pos: BlockPos
|
||||||
|
get() = miner.pos!!
|
||||||
|
private val facing: Direction
|
||||||
|
get() = miner.facing
|
||||||
|
|
||||||
|
fun getDrops(recalculate: Boolean = false): List<ItemStack> {
|
||||||
|
val targetPos = pos.offset(facing)
|
||||||
|
val realState = world.getBlockState(targetPos)
|
||||||
|
// todo: does BlockState.equals actually work?
|
||||||
|
if (cachedDrops == null || realState != cachedState || recalculate) {
|
||||||
|
cachedState = realState
|
||||||
|
val be = if (realState.block.hasBlockEntity()) world.getBlockEntity(targetPos) else null
|
||||||
|
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be)
|
||||||
|
}
|
||||||
|
return cachedDrops!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStoredStacks(): Set<ItemStack> {
|
||||||
|
return getDrops().toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTotalCapacity(): Int {
|
||||||
|
return Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic {
|
||||||
|
var totalCount = 0
|
||||||
|
for (s in getDrops()) {
|
||||||
|
if (filter.matches(s)) {
|
||||||
|
totalCount += s.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GroupedItemInvView.ItemInvStatistic(filter, totalCount, 0, Int.MAX_VALUE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,10 +2,7 @@ package net.shadowfacts.phycon.network.block.netinterface
|
||||||
|
|
||||||
import alexiil.mc.lib.attributes.AttributeList
|
import alexiil.mc.lib.attributes.AttributeList
|
||||||
import alexiil.mc.lib.attributes.AttributeProvider
|
import alexiil.mc.lib.attributes.AttributeProvider
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.*
|
||||||
import net.minecraft.block.BlockState
|
|
||||||
import net.minecraft.block.Material
|
|
||||||
import net.minecraft.block.ShapeContext
|
|
||||||
import net.minecraft.entity.LivingEntity
|
import net.minecraft.entity.LivingEntity
|
||||||
import net.minecraft.item.ItemPlacementContext
|
import net.minecraft.item.ItemPlacementContext
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
@ -21,15 +18,19 @@ import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraft.world.WorldAccess
|
import net.minecraft.world.WorldAccess
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.NetworkComponent
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
import net.shadowfacts.phycon.api.Interface
|
||||||
|
import net.shadowfacts.phycon.network.DeviceBlock
|
||||||
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
import net.shadowfacts.phycon.network.block.cable.CableBlock
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider {
|
class InterfaceBlock: DeviceBlock<InterfaceBlockEntity>(Settings.of(Material.METAL)),
|
||||||
|
NetworkComponentBlock,
|
||||||
|
AttributeProvider {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
|
val ID = Identifier(PhysicalConnectivity.MODID, "network_interface")
|
||||||
val FACING = Properties.FACING
|
val FACING = Properties.FACING
|
||||||
|
@ -63,7 +64,17 @@ class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
|
override fun getNetworkConnectedSides(state: BlockState, world: World, pos: BlockPos): Collection<Direction> {
|
||||||
return EnumSet.of(state[CABLE_CONNECTION])
|
val set = EnumSet.of(state[CABLE_CONNECTION])
|
||||||
|
set.remove(state[FACING])
|
||||||
|
return set
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||||
|
return if (side == state[FACING]) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
getBlockEntity(world, pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
|
||||||
|
@ -83,7 +94,7 @@ class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material
|
||||||
private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? {
|
private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? {
|
||||||
for (side in Direction.values()) {
|
for (side in Direction.values()) {
|
||||||
val offsetPos = pos.offset(side)
|
val offsetPos = pos.offset(side)
|
||||||
if (world.getBlockState(offsetPos).block is NetworkComponent) {
|
if (world.getBlockState(offsetPos).block is NetworkComponentBlock) {
|
||||||
return side
|
return side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +114,7 @@ class InterfaceBlock: BlockWithEntity<InterfaceBlockEntity>(Settings.of(Material
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState {
|
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) {
|
if (neighborState.block is NetworkComponentBlock && world.getBlockState(pos.offset(state[CABLE_CONNECTION])).block !is NetworkComponentBlock) {
|
||||||
return state.with(CABLE_CONNECTION, side)
|
return state.with(CABLE_CONNECTION, side)
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
|
|
@ -10,16 +10,21 @@ import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
||||||
|
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
||||||
|
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
|
||||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
import net.shadowfacts.phycon.network.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.network.packet.*
|
import net.shadowfacts.phycon.network.packet.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler {
|
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
|
||||||
|
ItemStackPacketHandler,
|
||||||
|
NetworkStackProvider,
|
||||||
|
NetworkStackReceiver {
|
||||||
|
|
||||||
private val facing: Direction
|
private val facing: Direction
|
||||||
get() = world!!.getBlockState(pos)[InterfaceBlock.FACING]
|
get() = cachedState[InterfaceBlock.FACING]
|
||||||
|
|
||||||
// todo: should this be a weak ref?
|
// todo: should this be a weak ref?
|
||||||
private var inventory: GroupedItemInv? = null
|
private var inventory: GroupedItemInv? = null
|
||||||
|
@ -37,7 +42,7 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemS
|
||||||
return inventory
|
return inventory
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handlePacket(packet: Packet) {
|
override fun handle(packet: Packet) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is RequestInventoryPacket -> handleRequestInventory(packet)
|
is RequestInventoryPacket -> handleRequestInventory(packet)
|
||||||
is LocateStackPacket -> handleLocateStack(packet)
|
is LocateStackPacket -> handleLocateStack(packet)
|
||||||
|
@ -49,21 +54,21 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemS
|
||||||
|
|
||||||
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
private fun handleRequestInventory(packet: RequestInventoryPacket) {
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
sendToSingle(ReadInventoryPacket(inv, macAddress, packet.source))
|
sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleLocateStack(packet: LocateStackPacket) {
|
private fun handleLocateStack(packet: LocateStackPacket) {
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
val amount = inv.getAmount(packet.stack)
|
val amount = inv.getAmount(packet.stack)
|
||||||
sendToSingle(StackLocationPacket(packet.stack, amount, this, macAddress, packet.source))
|
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleExtractStack(packet: ExtractStackPacket) {
|
private fun handleExtractStack(packet: ExtractStackPacket) {
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
val extracted = inv.extract(packet.stack, packet.amount)
|
val extracted = inv.extract(packet.stack, packet.amount)
|
||||||
sendToSingle(ItemStackPacket(extracted, macAddress, packet.source))
|
sendPacket(ItemStackPacket(extracted, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +76,7 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemS
|
||||||
getInventory()?.also { inv ->
|
getInventory()?.also { inv ->
|
||||||
val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE)
|
val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE)
|
||||||
val couldAccept = packet.stack.count - remaining.count
|
val couldAccept = packet.stack.count - remaining.count
|
||||||
sendToSingle(CapacityPacket(packet.stack, couldAccept, this, macAddress, packet.source))
|
sendPacket(CapacityPacket(packet.stack, couldAccept, this, ipAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,18 @@ import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.world.BlockView
|
import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.NetworkComponent
|
import net.shadowfacts.phycon.api.Interface
|
||||||
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
import net.shadowfacts.phycon.block.BlockWithEntity
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider {
|
class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL)),
|
||||||
|
NetworkComponentBlock,
|
||||||
|
AttributeProvider {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "switch")
|
val ID = Identifier(PhysicalConnectivity.MODID, "switch")
|
||||||
}
|
}
|
||||||
|
@ -26,6 +30,10 @@ class SwitchBlock: BlockWithEntity<SwitchBlockEntity>(Settings.of(Material.METAL
|
||||||
return EnumSet.allOf(Direction::class.java)
|
return EnumSet.allOf(Direction::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: World, pos: BlockPos): Interface? {
|
||||||
|
return getBlockEntity(world, pos)?.interfaces?.find { it.side == side }
|
||||||
|
}
|
||||||
|
|
||||||
override fun createBlockEntity(world: BlockView) = SwitchBlockEntity()
|
override fun createBlockEntity(world: BlockView) = SwitchBlockEntity()
|
||||||
|
|
||||||
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
override fun addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) {
|
||||||
|
|
|
@ -1,82 +1,119 @@
|
||||||
package net.shadowfacts.phycon.network.block.netswitch
|
package net.shadowfacts.phycon.network.block.netswitch
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
|
||||||
|
import net.minecraft.block.BlockState
|
||||||
|
import net.minecraft.block.entity.BlockEntity
|
||||||
import net.minecraft.entity.ItemEntity
|
import net.minecraft.entity.ItemEntity
|
||||||
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.util.Tickable
|
import net.minecraft.util.Tickable
|
||||||
import net.minecraft.util.math.Direction
|
import net.minecraft.util.math.Direction
|
||||||
import net.shadowfacts.phycon.api.PacketSink
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.frame.EthernetFrame
|
||||||
|
import net.shadowfacts.phycon.api.frame.PacketFrame
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.MACAddress
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
|
||||||
import net.shadowfacts.phycon.network.NetworkUtil
|
import net.shadowfacts.phycon.network.NetworkUtil
|
||||||
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
import net.shadowfacts.phycon.network.packet.ItemStackPacket
|
||||||
import java.lang.RuntimeException
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class SwitchBlockEntity: DeviceBlockEntity(PhyBlockEntities.SWITCH), Tickable {
|
class SwitchBlockEntity: BlockEntity(PhyBlockEntities.SWITCH),
|
||||||
|
BlockEntityClientSerializable,
|
||||||
|
Tickable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var SWITCHING_CAPACITY = 256
|
var SWITCHING_CAPACITY = 256 // 256 items/tick
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val interfaces = Direction.values().map { SwitchInterface(it, WeakReference(this), MACAddress.random()) }
|
||||||
|
|
||||||
private val macTable = mutableMapOf<MACAddress, Direction>()
|
private val macTable = mutableMapOf<MACAddress, Direction>()
|
||||||
private var packetsHandledThisTick = 0
|
private var itemsHandledThisTick = 0
|
||||||
|
|
||||||
override fun acceptsPacket(packet: Packet) = true
|
fun interfaceForSide(side: Direction): SwitchInterface {
|
||||||
|
return interfaces.find { it.side == side }!!
|
||||||
|
}
|
||||||
|
|
||||||
override fun handlePacket(packet: Packet) {
|
private fun handle(frame: EthernetFrame, fromItf: SwitchInterface) {
|
||||||
if (packetsHandledThisTick >= SWITCHING_CAPACITY) {
|
macTable[frame.source] = fromItf.side
|
||||||
if (packet is ItemStackPacket) {
|
|
||||||
|
if (frame is PacketFrame && frame.packet is ItemStackPacket) {
|
||||||
|
val packet = frame.packet as ItemStackPacket
|
||||||
|
if (itemsHandledThisTick + packet.stack.count > SWITCHING_CAPACITY) {
|
||||||
// todo: calculate entity spawn point by finding non-obstructed location
|
// 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)
|
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack)
|
||||||
world!!.spawnEntity(entity)
|
world!!.spawnEntity(entity)
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
packetsHandledThisTick++
|
|
||||||
|
|
||||||
if (packet.destination == MACAddress.BROADCAST) {
|
|
||||||
val allDestinations = NetworkUtil.findDestinations(world!!, pos).filter { it.macAddress != packet.source }
|
|
||||||
sendToAll(packet, allDestinations)
|
|
||||||
} else {
|
} else {
|
||||||
val direction = macTable[packet.destination]
|
itemsHandledThisTick += packet.stack.count
|
||||||
if (direction != null) {
|
|
||||||
val dest = findDestination(direction)
|
|
||||||
if (dest != null && packet.destination == dest.macAddress) {
|
|
||||||
send(packet, dest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flood(packet)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findDestination(direction: Direction): PacketSink? {
|
if (frame.destination.type != MACAddress.Type.BROADCAST && macTable.containsKey(frame.destination)) {
|
||||||
val allDestinations = NetworkUtil.findDestinations(world!!, pos, direction)
|
val dir = macTable[frame.destination]!!
|
||||||
if (allDestinations.size > 1) {
|
println("$this (${fromItf.side}, ${fromItf.macAddress}) forwarding $frame to side $dir")
|
||||||
// todo: do this better
|
interfaceForSide(dir).send(frame)
|
||||||
println("Can't send packet, multiple destinations: $allDestinations")
|
} else {
|
||||||
return null
|
println("$this (${fromItf.side}, ${fromItf.macAddress}) flooding $frame")
|
||||||
|
flood(frame, fromItf)
|
||||||
}
|
}
|
||||||
return allDestinations.firstOrNull()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun flood(packet: Packet) {
|
private fun flood(frame: EthernetFrame, source: Interface) {
|
||||||
for (dir in Direction.values()) {
|
for (itf in interfaces) {
|
||||||
val dest = findDestination(dir)
|
if (source == itf) continue
|
||||||
if (dest != null && packet.destination == dest.macAddress) {
|
itf.send(frame)
|
||||||
macTable[packet.destination] = dir
|
|
||||||
send(packet, dest)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findDestination(fromItf: Interface): Interface? {
|
||||||
|
val side = (fromItf as SwitchInterface).side
|
||||||
|
return NetworkUtil.findConnectedInterface(world!!, pos, side)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
packetsHandledThisTick = 0
|
itemsHandledThisTick = 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,
|
||||||
|
val switch: WeakReference<SwitchBlockEntity>,
|
||||||
|
@JvmField var macAddress: MACAddress,
|
||||||
|
): Interface {
|
||||||
|
override fun getMACAddress() = macAddress
|
||||||
|
|
||||||
|
override fun receive(frame: EthernetFrame) {
|
||||||
|
switch.get()?.handle(frame, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun send(frame: EthernetFrame) {
|
||||||
|
switch.get()?.findDestination(this)?.receive(frame)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,17 @@ import net.minecraft.util.math.Direction
|
||||||
import net.minecraft.world.BlockView
|
import net.minecraft.world.BlockView
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
import net.shadowfacts.phycon.api.NetworkComponent
|
import net.shadowfacts.phycon.api.NetworkComponentBlock
|
||||||
import net.shadowfacts.phycon.block.BlockWithEntity
|
import net.shadowfacts.phycon.network.DeviceBlock
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class TerminalBlock: BlockWithEntity<TerminalBlockEntity>(Settings.of(Material.METAL)), NetworkComponent, AttributeProvider {
|
class TerminalBlock: DeviceBlock<TerminalBlockEntity>(Settings.of(Material.METAL)),
|
||||||
|
NetworkComponentBlock,
|
||||||
|
AttributeProvider {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
val ID = Identifier(PhysicalConnectivity.MODID, "terminal")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package net.shadowfacts.phycon.network.block.terminal
|
package net.shadowfacts.phycon.network.block.terminal
|
||||||
|
|
||||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
||||||
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
|
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
|
||||||
|
@ -17,14 +17,18 @@ import net.minecraft.nbt.ListTag
|
||||||
import net.minecraft.network.PacketByteBuf
|
import net.minecraft.network.PacketByteBuf
|
||||||
import net.minecraft.screen.ScreenHandler
|
import net.minecraft.screen.ScreenHandler
|
||||||
import net.minecraft.server.network.ServerPlayerEntity
|
import net.minecraft.server.network.ServerPlayerEntity
|
||||||
import net.minecraft.text.LiteralText
|
import net.minecraft.text.TranslatableText
|
||||||
import net.minecraft.util.Tickable
|
import net.minecraft.util.Tickable
|
||||||
|
import net.minecraft.util.math.Direction
|
||||||
|
import net.shadowfacts.phycon.api.Interface
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.init.PhyBlockEntities
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
import net.shadowfacts.phycon.network.NetworkUtil
|
||||||
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
|
||||||
|
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
||||||
|
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
|
||||||
import net.shadowfacts.phycon.network.component.handleItemStack
|
import net.shadowfacts.phycon.network.component.handleItemStack
|
||||||
import net.shadowfacts.phycon.network.packet.*
|
import net.shadowfacts.phycon.network.packet.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -40,7 +44,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
val INSERTION_TIMEOUT = 40
|
val INSERTION_TIMEOUT = 40
|
||||||
}
|
}
|
||||||
|
|
||||||
private val inventoryCache = mutableMapOf<MACAddress, GroupedItemInv>()
|
private val inventoryCache = mutableMapOf<IPAddress, GroupedItemInvView>()
|
||||||
val internalBuffer = TerminalBufferInventory(18)
|
val internalBuffer = TerminalBufferInventory(18)
|
||||||
|
|
||||||
private val locateRequestQueue = LinkedList<StackLocateRequest>()
|
private val locateRequestQueue = LinkedList<StackLocateRequest>()
|
||||||
|
@ -50,13 +54,22 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
private var observers = 0
|
private var observers = 0
|
||||||
val cachedNetItems = ItemStackCollections.intMap()
|
val cachedNetItems = ItemStackCollections.intMap()
|
||||||
var cachedSortedNetItems = listOf<ItemStack>()
|
var cachedSortedNetItems = listOf<ItemStack>()
|
||||||
var counter = 0
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
internalBuffer.addListener(this)
|
internalBuffer.addListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handlePacket(packet: Packet) {
|
override fun findDestination(): Interface? {
|
||||||
|
for (dir in Direction.values()) {
|
||||||
|
val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir)
|
||||||
|
if (itf != null) {
|
||||||
|
return itf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(packet: Packet) {
|
||||||
when (packet) {
|
when (packet) {
|
||||||
is ReadInventoryPacket -> handleReadInventory(packet)
|
is ReadInventoryPacket -> handleReadInventory(packet)
|
||||||
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
|
||||||
|
@ -83,7 +96,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack)
|
ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack)
|
||||||
}
|
}
|
||||||
if (request != null) {
|
if (request != null) {
|
||||||
request.results.add(packet.amount to packet.sourceInterface)
|
request.results.add(packet.amount to packet.stackProvider)
|
||||||
if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) {
|
if (request.totalResultAmount >= request.amount || counter - request.timestamp >= LOCATE_REQUEST_TIMEOUT || request.results.size >= inventoryCache.size) {
|
||||||
stackLocateRequestCompleted(request)
|
stackLocateRequestCompleted(request)
|
||||||
}
|
}
|
||||||
|
@ -106,7 +119,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
|
ItemStackUtil.areEqualIgnoreAmounts(packet.stack, it.stack)
|
||||||
}
|
}
|
||||||
if (insertion != null) {
|
if (insertion != null) {
|
||||||
insertion.results.add(packet.capacity to packet.receivingInterface)
|
insertion.results.add(packet.capacity to packet.stackReceiver)
|
||||||
if (insertion.isFinishable(counter)) {
|
if (insertion.isFinishable(counter)) {
|
||||||
finishInsertion(insertion)
|
finishInsertion(insertion)
|
||||||
}
|
}
|
||||||
|
@ -137,7 +150,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
if (slot in pendingInsertions) continue
|
if (slot in pendingInsertions) continue
|
||||||
val stack = internalBuffer.getStack(slot)
|
val stack = internalBuffer.getStack(slot)
|
||||||
pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter)
|
pendingInsertions[slot] = PendingStackInsertion(slot, stack, counter)
|
||||||
sendToSingle(CheckCapacityPacket(stack, macAddress, MACAddress.BROADCAST))
|
sendPacket(CheckCapacityPacket(stack, ipAddress, IPAddress.BROADCAST))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +168,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
|
|
||||||
for (request in locateRequestQueue) {
|
for (request in locateRequestQueue) {
|
||||||
pendingRequests.add(request)
|
pendingRequests.add(request)
|
||||||
sendToSingle(LocateStackPacket(request.stack, macAddress))
|
sendPacket(LocateStackPacket(request.stack, ipAddress))
|
||||||
}
|
}
|
||||||
locateRequestQueue.clear()
|
locateRequestQueue.clear()
|
||||||
}
|
}
|
||||||
|
@ -179,19 +192,26 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
override fun tick() {
|
||||||
if (observers > 0 && (++counter % 10) == 0) {
|
super.tick()
|
||||||
if (world!!.isClient) {
|
|
||||||
println(cachedNetItems)
|
if (counter % 20 == 0L) {
|
||||||
} else {
|
if (!world!!.isClient) {
|
||||||
updateNetItems()
|
|
||||||
sendEnqueuedLocateRequests()
|
sendEnqueuedLocateRequests()
|
||||||
finishPendingRequests()
|
finishPendingRequests()
|
||||||
beginInsertions()
|
beginInsertions()
|
||||||
finishPendingInsertions()
|
finishPendingInsertions()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (observers > 0) {
|
||||||
|
if (world!!.isClient) {
|
||||||
|
println(cachedNetItems)
|
||||||
|
} else {
|
||||||
|
updateNetItems()
|
||||||
sync()
|
sync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onActivate(player: PlayerEntity) {
|
fun onActivate(player: PlayerEntity) {
|
||||||
if (!world!!.isClient) {
|
if (!world!!.isClient) {
|
||||||
|
@ -199,13 +219,13 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
sync()
|
sync()
|
||||||
|
|
||||||
inventoryCache.clear()
|
inventoryCache.clear()
|
||||||
sendToSingle(RequestInventoryPacket(macAddress))
|
sendPacket(RequestInventoryPacket(ipAddress))
|
||||||
val factory = object: ExtendedScreenHandlerFactory {
|
val factory = object: ExtendedScreenHandlerFactory {
|
||||||
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
||||||
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDisplayName() = LiteralText("Terminal")
|
override fun getDisplayName() = TranslatableText("block.phycon.terminal")
|
||||||
|
|
||||||
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
||||||
buf.writeBlockPos(this@TerminalBlockEntity.pos)
|
buf.writeBlockPos(this@TerminalBlockEntity.pos)
|
||||||
|
@ -230,7 +250,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
val (sourceAmount, sourceInterface) = sortedResults.removeAt(0)
|
||||||
val amountToRequest = min(sourceAmount, request.amount - amountRequested)
|
val amountToRequest = min(sourceAmount, request.amount - amountRequested)
|
||||||
amountRequested += amountToRequest
|
amountRequested += amountToRequest
|
||||||
sendToSingle(ExtractStackPacket(request.stack, amountToRequest, macAddress, sourceInterface.macAddress))
|
sendPacket(ExtractStackPacket(request.stack, amountToRequest, ipAddress, sourceInterface.ipAddress))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +263,7 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
while (!remaining.isEmpty && sortedResults.isNotEmpty()) {
|
||||||
val (capacity, receivingInterface) = sortedResults.removeAt(0)
|
val (capacity, receivingInterface) = sortedResults.removeAt(0)
|
||||||
if (capacity <= 0) continue
|
if (capacity <= 0) continue
|
||||||
sendToSingle(ItemStackPacket(remaining.copy(), macAddress, receivingInterface.macAddress))
|
sendPacket(ItemStackPacket(remaining.copy(), ipAddress, receivingInterface.ipAddress))
|
||||||
// todo: the interface should confirm how much was actually inserted, in case of race condition
|
// todo: the interface should confirm how much was actually inserted, in case of race condition
|
||||||
remaining.count -= capacity
|
remaining.count -= capacity
|
||||||
}
|
}
|
||||||
|
@ -304,27 +324,27 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
|
||||||
data class StackLocateRequest(
|
data class StackLocateRequest(
|
||||||
val stack: ItemStack,
|
val stack: ItemStack,
|
||||||
val amount: Int,
|
val amount: Int,
|
||||||
val timestamp: Int,
|
val timestamp: Long,
|
||||||
var results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf()
|
var results: MutableSet<Pair<Int, NetworkStackProvider>> = mutableSetOf()
|
||||||
) {
|
) {
|
||||||
val totalResultAmount: Int
|
val totalResultAmount: Int
|
||||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||||
|
|
||||||
fun isFinishable(currentTimestamp: Int): Boolean {
|
fun isFinishable(currentTimestamp: Long): Boolean {
|
||||||
return totalResultAmount > amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
return totalResultAmount >= amount || currentTimestamp - timestamp >= TerminalBlockEntity.LOCATE_REQUEST_TIMEOUT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class PendingStackInsertion(
|
data class PendingStackInsertion(
|
||||||
val bufferSlot: Int,
|
val bufferSlot: Int,
|
||||||
val stack: ItemStack,
|
val stack: ItemStack,
|
||||||
val timestamp: Int,
|
val timestamp: Long,
|
||||||
val results: MutableSet<Pair<Int, InterfaceBlockEntity>> = mutableSetOf(),
|
val results: MutableSet<Pair<Int, NetworkStackReceiver>> = mutableSetOf(),
|
||||||
) {
|
) {
|
||||||
val totalCapacity: Int
|
val totalCapacity: Int
|
||||||
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
get() = results.fold(0) { acc, (amount, _) -> acc + amount }
|
||||||
|
|
||||||
fun isFinishable(currentTimestamp: Int): Boolean {
|
fun isFinishable(currentTimestamp: Long): Boolean {
|
||||||
return totalCapacity > stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT
|
return totalCapacity >= stack.count || currentTimestamp - timestamp >= TerminalBlockEntity.INSERTION_TIMEOUT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import net.minecraft.client.gui.screen.ingame.HandledScreen
|
||||||
import net.minecraft.client.util.math.MatrixStack
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
import net.minecraft.entity.player.PlayerInventory
|
import net.minecraft.entity.player.PlayerInventory
|
||||||
import net.minecraft.screen.slot.Slot
|
import net.minecraft.screen.slot.Slot
|
||||||
import net.minecraft.text.LiteralText
|
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import net.shadowfacts.phycon.PhysicalConnectivity
|
import net.shadowfacts.phycon.PhysicalConnectivity
|
||||||
|
@ -33,6 +32,8 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
|
||||||
|
renderBackground(matrixStack)
|
||||||
|
|
||||||
GlStateManager.color4f(1f, 1f, 1f, 1f)
|
GlStateManager.color4f(1f, 1f, 1f, 1f)
|
||||||
client!!.textureManager.bindTexture(BACKGROUND)
|
client!!.textureManager.bindTexture(BACKGROUND)
|
||||||
val x = (width - backgroundWidth) / 2
|
val x = (width - backgroundWidth) / 2
|
||||||
|
@ -40,6 +41,11 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
|
||||||
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
|
super.render(matrixStack, mouseX, mouseY, delta)
|
||||||
|
drawMouseoverTooltip(matrixStack, mouseX, mouseY)
|
||||||
|
}
|
||||||
|
|
||||||
@ExperimentalUnsignedTypes
|
@ExperimentalUnsignedTypes
|
||||||
fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) {
|
fun drawSlotUnderlay(matrixStack: MatrixStack, slot: Slot) {
|
||||||
if (!handler.isBufferSlot(slot.id)) {
|
if (!handler.isBufferSlot(slot.id)) {
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
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.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 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,29 @@
|
||||||
|
package net.shadowfacts.phycon.network.block.test
|
||||||
|
|
||||||
|
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.DeviceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.network.NetworkUtil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class DestBlockEntity: DeviceBlockEntity(PhyBlockEntities.DEST) {
|
||||||
|
|
||||||
|
override fun handle(packet: Packet) {
|
||||||
|
println("$this ($ipAddress) received packet: $packet")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findDestination(): Interface? {
|
||||||
|
for (dir in Direction.values()) {
|
||||||
|
val itf = NetworkUtil.findConnectedInterface(world!!, pos, dir)
|
||||||
|
if (itf != null) {
|
||||||
|
return itf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
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.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
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.packet.Packet
|
||||||
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
||||||
|
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||||
|
import net.shadowfacts.phycon.network.NetworkUtil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class SourceBlockEntity: DeviceBlockEntity(PhyBlockEntities.SOURCE), Tickable {
|
||||||
|
|
||||||
|
override fun handle(packet: Packet) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
super.tick()
|
||||||
|
if (!world!!.isClient && counter % 40 == 0L) {
|
||||||
|
sendPacket(TestPacket(ipAddress, IPAddress(170, 171, 101, 168)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findDestination(): 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)
|
val remainder = doHandleItemStack(packet)
|
||||||
// if there are any items remaining, send them back to the source with incremented bounce count
|
// if there are any items remaining, send them back to the source with incremented bounce count
|
||||||
if (!remainder.isEmpty) {
|
if (!remainder.isEmpty) {
|
||||||
sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source))
|
// sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package net.shadowfacts.phycon.network.component
|
||||||
|
|
||||||
|
import net.shadowfacts.phycon.api.NetworkDevice
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
interface NetworkStackProvider: NetworkDevice {
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package net.shadowfacts.phycon.network.component
|
||||||
|
|
||||||
|
import net.shadowfacts.phycon.api.NetworkDevice
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
interface NetworkStackReceiver: NetworkDevice {
|
||||||
|
}
|
|
@ -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
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.shadowfacts.phycon.api.packet.Packet
|
import net.shadowfacts.phycon.api.packet.Packet
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
abstract class BasePacket(
|
abstract class BasePacket(
|
||||||
@JvmField private val source: MACAddress,
|
@JvmField private val source: IPAddress,
|
||||||
@JvmField private val destination: MACAddress
|
@JvmField private val destination: IPAddress
|
||||||
): Packet {
|
): Packet {
|
||||||
|
|
||||||
override fun getSource() = source
|
override fun getSource() = source
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
import net.shadowfacts.phycon.network.component.NetworkStackReceiver
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class CapacityPacket(val stack: ItemStack, val capacity: Int, val receivingInterface: InterfaceBlockEntity, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
class CapacityPacket(
|
||||||
|
val stack: ItemStack,
|
||||||
|
val capacity: Int,
|
||||||
|
val stackReceiver: NetworkStackReceiver,
|
||||||
|
source: IPAddress,
|
||||||
|
destination: IPAddress
|
||||||
|
): BasePacket(source, destination) {
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class CheckCapacityPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
class CheckCapacityPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||||
}
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class DeviceRemovedPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) {
|
class DeviceRemovedPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) {
|
||||||
constructor(device: DeviceBlockEntity): this(device.macAddress)
|
constructor(device: DeviceBlockEntity): this(device.ipAddress)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
class ExtractStackPacket(val stack: ItemStack, val amount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
|
class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: IPAddress, destination: IPAddress): BasePacket(source, destination) {
|
||||||
constructor(stack: ItemStack, source: MACAddress, destination: MACAddress): this(stack, 0, source, destination)
|
constructor(stack: ItemStack, source: IPAddress, destination: IPAddress): this(stack, 0, source, destination)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class LocateStackPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination) {
|
class LocateStackPacket(val stack: ItemStack, source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import alexiil.mc.lib.attributes.item.GroupedItemInv
|
import alexiil.mc.lib.attributes.item.GroupedItemInvView
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class ReadInventoryPacket(
|
class ReadInventoryPacket(
|
||||||
val inventory: GroupedItemInv,
|
val inventory: GroupedItemInvView,
|
||||||
source: MACAddress,
|
source: IPAddress,
|
||||||
destination: MACAddress
|
destination: IPAddress
|
||||||
): BasePacket(source, destination)
|
): BasePacket(source, destination)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
*/
|
*/
|
||||||
class RequestInventoryPacket(source: MACAddress, destination: MACAddress = MACAddress.BROADCAST): BasePacket(source, destination)
|
class RequestInventoryPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package net.shadowfacts.phycon.network.packet
|
package net.shadowfacts.phycon.network.packet
|
||||||
|
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.shadowfacts.phycon.api.util.MACAddress
|
import net.shadowfacts.phycon.api.util.IPAddress
|
||||||
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
import net.shadowfacts.phycon.network.component.NetworkStackProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author shadowfacts
|
* @author shadowfacts
|
||||||
|
@ -11,8 +11,8 @@ import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
|
||||||
class StackLocationPacket(
|
class StackLocationPacket(
|
||||||
val stack: ItemStack,
|
val stack: ItemStack,
|
||||||
val amount: Int,
|
val amount: Int,
|
||||||
val sourceInterface: InterfaceBlockEntity,
|
val stackProvider: NetworkStackProvider,
|
||||||
source: MACAddress,
|
source: IPAddress,
|
||||||
destination: MACAddress
|
destination: IPAddress
|
||||||
): BasePacket(source, destination) {
|
): BasePacket(source, destination) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package net.shadowfacts.phycon.screen
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.screen.Screen
|
||||||
|
import net.minecraft.client.util.math.MatrixStack
|
||||||
|
import net.minecraft.text.TranslatableText
|
||||||
|
import net.shadowfacts.phycon.network.DeviceBlockEntity
|
||||||
|
import org.lwjgl.glfw.GLFW
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class DeviceConsoleScreen(
|
||||||
|
val device: DeviceBlockEntity,
|
||||||
|
): Screen(TranslatableText("item.phycon.onsole")) {
|
||||||
|
|
||||||
|
override fun init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isPauseScreen() = false
|
||||||
|
|
||||||
|
override fun keyPressed(key: Int, j: Int, k: Int): Boolean {
|
||||||
|
if (key == GLFW.GLFW_KEY_E) {
|
||||||
|
onClose();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.keyPressed(key, j, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
|
||||||
|
renderBackground(matrixStack)
|
||||||
|
|
||||||
|
super.render(matrixStack, mouseX, mouseY, delta)
|
||||||
|
|
||||||
|
drawCenteredString(matrixStack, textRenderer, device.macAddress.toString(), width / 2, height / 2 - 5, 0xffffff)
|
||||||
|
drawCenteredString(matrixStack, textRenderer, device.ipAddress.toString(), width / 2, height / 2 + 5, 0xffffff)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"variants": {
|
||||||
|
"facing=down": {
|
||||||
|
"model": "phycon:block/extractor"
|
||||||
|
},
|
||||||
|
"facing=up": {
|
||||||
|
"model": "phycon:block/extractor",
|
||||||
|
"x": 180
|
||||||
|
},
|
||||||
|
"facing=north": {
|
||||||
|
"model": "phycon:block/extractor",
|
||||||
|
"x": 270
|
||||||
|
},
|
||||||
|
"facing=south": {
|
||||||
|
"model": "phycon:block/extractor",
|
||||||
|
"x": 90
|
||||||
|
},
|
||||||
|
"facing=west": {
|
||||||
|
"model": "phycon:block/extractor",
|
||||||
|
"x": 90,
|
||||||
|
"y": 90
|
||||||
|
},
|
||||||
|
"facing=east": {
|
||||||
|
"model": "phycon:block/extractor",
|
||||||
|
"x": 90,
|
||||||
|
"y": 270
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"block.phycon.switch": "Network Switch",
|
||||||
|
"block.phycon.network_interface": "Inventory Interface",
|
||||||
|
"block.phycon.terminal": "Terminal",
|
||||||
|
"block.phycon.cable": "Cable",
|
||||||
|
"block.phycon.extractor": "Inventory Extractor",
|
||||||
|
"block.phycon.miner": "Block Miner",
|
||||||
|
|
||||||
|
"item.phycon.screwdriver": "Screwdriver",
|
||||||
|
"item.phycon.console": "Console"
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"parent": "block/block",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [0, 0, 0],
|
||||||
|
"to": [16, 2, 16],
|
||||||
|
"faces": {
|
||||||
|
"down": {"texture": "phycon:block/extractor_front"},
|
||||||
|
"up": {"texture": "phycon:block/extractor_back"},
|
||||||
|
"north": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"south": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"west": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"east": {"texture": "phycon:block/extractor_side"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [2, 2, 2],
|
||||||
|
"to": [14, 4, 14],
|
||||||
|
"faces": {
|
||||||
|
"up": {"texture": "phycon:block/extractor_back"},
|
||||||
|
"north": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"south": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"west": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"east": {"texture": "phycon:block/extractor_side"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [4, 4, 4],
|
||||||
|
"to": [12, 6, 12],
|
||||||
|
"faces": {
|
||||||
|
"up": {"texture": "phycon:block/extractor_back"},
|
||||||
|
"north": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"south": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"west": {"texture": "phycon:block/extractor_side"},
|
||||||
|
"east": {"texture": "phycon:block/extractor_side"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [6, 6, 6],
|
||||||
|
"to": [10, 16, 10],
|
||||||
|
"faces": {
|
||||||
|
"up": {"texture": "phycon:block/cable_side"},
|
||||||
|
"north": {"texture": "phycon:block/cable_side"},
|
||||||
|
"south": {"texture": "phycon:block/cable_side"},
|
||||||
|
"west": {"texture": "phycon:block/cable_side"},
|
||||||
|
"east": {"texture": "phycon:block/cable_side"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/generated",
|
||||||
|
"textures": {
|
||||||
|
"layer0": "phycon:item/console"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"parent": "block/block",
|
||||||
|
"display": {
|
||||||
|
"firstperson_righthand": {
|
||||||
|
"rotation": [0, 215, 0],
|
||||||
|
"translation": [0, 0, 0],
|
||||||
|
"scale": [0.4, 0.4, 0.4]
|
||||||
|
},
|
||||||
|
"thirdperson_righthand": {
|
||||||
|
"rotation": [75, 215, 0],
|
||||||
|
"translation": [0, -2.5, 0],
|
||||||
|
"scale": [0.375, 0.375, 0.375]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"_comment": "cable center",
|
||||||
|
"from": [6, 6, 6],
|
||||||
|
"to": [10, 10, 10],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "phycon:block/cable_center" },
|
||||||
|
"up": { "texture": "phycon:block/cable_center" },
|
||||||
|
"north": { "texture": "phycon:block/cable_center" },
|
||||||
|
"south": { "texture": "phycon:block/cable_center" },
|
||||||
|
"west": { "texture": "phycon:block/cable_center" },
|
||||||
|
"east": { "texture": "phycon:block/cable_center" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_comment": "interface side",
|
||||||
|
"from": [2, 2, 14],
|
||||||
|
"to": [14, 14, 16],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "phycon:block/interface_side" },
|
||||||
|
"up": { "texture": "phycon:block/interface_side" },
|
||||||
|
"north": { "texture": "phycon:block/interface_front" },
|
||||||
|
"south": { "texture": "phycon:block/interface_back" },
|
||||||
|
"west": { "texture": "phycon:block/interface_side" },
|
||||||
|
"east": { "texture": "phycon:block/interface_side" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_comment": "interface middle",
|
||||||
|
"from": [6, 6, 10],
|
||||||
|
"to": [10, 10, 14],
|
||||||
|
"faces": {
|
||||||
|
"down": { "texture": "phycon:block/cable_side" },
|
||||||
|
"up": { "texture": "phycon:block/cable_side" },
|
||||||
|
"west": { "texture": "phycon:block/cable_side" },
|
||||||
|
"east": { "texture": "phycon:block/cable_side" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 913 B |
Loading…
Reference in New Issue