Add P2P inventory system

This commit is contained in:
Shadowfacts 2021-12-24 12:34:16 -05:00
parent 9cbad193e2
commit e88ecd3215
28 changed files with 513 additions and 13 deletions

View File

@ -2,8 +2,10 @@ package net.shadowfacts.phycon
import net.fabricmc.api.ModInitializer
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage
import net.fabricmc.loader.api.FabricLoader
import net.shadowfacts.phycon.api.PhyConPlugin
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyItems
@ -31,6 +33,8 @@ object PhysicalConnectivity: ModInitializer {
registerGlobalReceiver(C2STerminalRequestItem)
registerGlobalReceiver(C2STerminalUpdateDisplayedItems)
ItemStorage.SIDED.registerForBlockEntity(P2PReceiverBlockEntity::provideItemStorage, PhyBlockEntities.P2P_RECEIVER)
for (it in FabricLoader.getInstance().getEntrypoints("phycon", PhyConPlugin::class.java)) {
it.initializePhyCon(PhyConAPIImpl)
}

View File

@ -57,6 +57,9 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
is DeviceRemovedPacket -> {
arpTable.remove(packet.source)
}
is PingPacket -> {
sendPacket(PongPacket(ipAddress, packet.source))
}
}
handle(packet)
}

View File

@ -57,10 +57,10 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyB
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
if (minerMode != MinerMode.ON_DEMAND) {
if (minerMode != MinerMode.ON_DEMAND || packet.kind != RequestInventoryPacket.Kind.GROUPED) {
return
}
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
sendPacket(ReadGroupedInventoryPacket(invProxy, ipAddress, packet.source))
}
private fun handleLocateStack(packet: LocateStackPacket) {

View File

@ -64,8 +64,11 @@ class InterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
if (packet.kind != RequestInventoryPacket.Kind.GROUPED) {
return
}
getInventory()?.also { inv ->
sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source))
sendPacket(ReadGroupedInventoryPacket(inv, ipAddress, packet.source))
}
}

View File

@ -0,0 +1,37 @@
package net.shadowfacts.phycon.block.p2p
import net.minecraft.block.BlockState
import net.minecraft.block.Material
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.FaceDeviceBlock
/**
* @author shadowfacts
*/
class P2PInterfaceBlock: FaceDeviceBlock<P2PInterfaceBlockEntity>(
Settings.of(Material.METAL)
.strength(1.5f)
.sounds(BlockSoundGroup.METAL)
) {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "p2p_interface")
}
override val faceThickness = 4.0
override val faceShapes = mapOf(
Direction.DOWN to createCuboidShape(0.0, 0.0, 0.0, 16.0, 4.0, 16.0),
Direction.UP to createCuboidShape(0.0, 12.0, 0.0, 16.0, 16.0, 16.0),
Direction.NORTH to createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 4.0),
Direction.SOUTH to createCuboidShape(0.0, 0.0, 12.0, 16.0, 16.0, 16.0),
Direction.WEST to createCuboidShape(0.0, 0.0, 0.0, 4.0, 16.0, 16.0),
Direction.EAST to createCuboidShape(12.0, 0.0, 0.0, 16.0, 16.0, 16.0)
)
override fun createBlockEntity(pos: BlockPos, state: BlockState) = P2PInterfaceBlockEntity(pos, state)
}

View File

@ -0,0 +1,47 @@
package net.shadowfacts.phycon.block.p2p
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.packet.ReadItemStoragePacket
import net.shadowfacts.phycon.packet.RequestInventoryPacket
/**
* @author shadowfacts
*/
class P2PInterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.P2P_INTERFACE, pos, state) {
private var inventory: Storage<ItemVariant>? = null
private fun updateInventory() {
val facing = cachedState[FaceDeviceBlock.FACING]
inventory = ItemStorage.SIDED.find(world!!, pos.offset(facing), facing.opposite)
}
private fun getInventory(): Storage<ItemVariant>? {
if (inventory == null) updateInventory()
return inventory
}
override fun handle(packet: Packet) {
when (packet) {
is RequestInventoryPacket -> handleRequestInventory(packet)
}
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
if (packet.kind != RequestInventoryPacket.Kind.SIDED) {
return
}
getInventory()?.also {
sendPacket(ReadItemStoragePacket(it, ipAddress, packet.source))
}
}
}

View File

@ -0,0 +1,40 @@
package net.shadowfacts.phycon.block.p2p
import net.minecraft.block.BlockState
import net.minecraft.block.InventoryProvider
import net.minecraft.block.Material
import net.minecraft.inventory.SidedInventory
import net.minecraft.sound.BlockSoundGroup
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.world.WorldAccess
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.block.FaceDeviceBlock
/**
* @author shadowfacts
*/
class P2PReceiverBlock: FaceDeviceBlock<P2PReceiverBlockEntity>(
Settings.of(Material.METAL)
.strength(1.5f)
.sounds(BlockSoundGroup.METAL)
) {
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "p2p_receiver")
}
override val faceThickness = 4.0
override val faceShapes = mapOf(
Direction.DOWN to createCuboidShape(0.0, 0.0, 0.0, 16.0, 4.0, 16.0),
Direction.UP to createCuboidShape(0.0, 12.0, 0.0, 16.0, 16.0, 16.0),
Direction.NORTH to createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 4.0),
Direction.SOUTH to createCuboidShape(0.0, 0.0, 12.0, 16.0, 16.0, 16.0),
Direction.WEST to createCuboidShape(0.0, 0.0, 0.0, 4.0, 16.0, 16.0),
Direction.EAST to createCuboidShape(12.0, 0.0, 0.0, 16.0, 16.0, 16.0)
)
override fun createBlockEntity(pos: BlockPos, state: BlockState) = P2PReceiverBlockEntity(pos, state)
}

View File

@ -0,0 +1,133 @@
package net.shadowfacts.phycon.block.p2p
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
import net.minecraft.block.BlockState
import net.minecraft.nbt.NbtCompound
import net.minecraft.text.Text
import net.minecraft.text.TranslatableText
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.packet.*
import net.shadowfacts.phycon.util.ClientConfigurableDevice
/**
* @author shadowfacts
*/
class P2PReceiverBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.P2P_RECEIVER, pos, state),
ClientConfigurableDevice {
enum class Status {
OK,
NO_TARGET,
WAITING_FOR_RESPONSE;
val displayName: Text
get() = when (this) {
OK -> TranslatableText("gui.phycon.p2p_receiver.status.ok")
NO_TARGET -> TranslatableText("gui.phycon.p2p_receiver.status.no_target")
WAITING_FOR_RESPONSE -> TranslatableText("gui.phycon.p2p_receiver.status.waiting_for_response")
}
}
companion object {
fun provideItemStorage(be: P2PReceiverBlockEntity, side: Direction): Storage<ItemVariant>? {
if (side == be.cachedState[FaceDeviceBlock.FACING]) {
return be.getTargetInventory()
}
return null
}
}
var target: IPAddress? = null
var status = Status.NO_TARGET
var clientObserver: (() -> Unit)? = null
private var isFirstTick = true
// todo: need some way of removing this when there's no network path to the p2p interface
private var targetInventory: Storage<ItemVariant>? = null
override fun handle(packet: Packet) {
when (packet) {
is PongPacket -> if (packet.source == target) status = Status.OK
is ReadItemStoragePacket -> targetInventory = packet.inventory
is DeviceRemovedPacket -> if (packet.source == target) targetInventory = null
}
}
override fun tick() {
super.tick()
if (isFirstTick) {
isFirstTick = false
updateStatus()
}
}
fun getTargetInventory(): Storage<ItemVariant>? {
if (target == null) {
return null
}
if (targetInventory == null) {
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.SIDED, ipAddress, target!!))
}
return targetInventory
}
private fun updateStatus() {
if (world?.isClient != false) {
return
}
assert(!world!!.isClient)
if (target == null) {
status = Status.NO_TARGET
} else {
status = Status.WAITING_FOR_RESPONSE
sendPacket(PingPacket(ipAddress, target!!))
}
markUpdate()
}
override fun toCommonTag(tag: NbtCompound) {
super.toCommonTag(tag)
writeDeviceConfiguration(tag)
}
override fun fromCommonTag(tag: NbtCompound) {
super.fromCommonTag(tag)
loadDeviceConfiguration(tag)
}
override fun toClientTag(tag: NbtCompound): NbtCompound {
tag.putInt("Status", status.ordinal)
return super.toClientTag(tag)
}
override fun fromClientTag(tag: NbtCompound) {
super.fromClientTag(tag)
status = Status.values()[tag.getInt("Status")]
clientObserver?.invoke()
}
override fun writeDeviceConfiguration(tag: NbtCompound) {
target?.address?.let { tag.putInt("Target", it) }
}
override fun loadDeviceConfiguration(tag: NbtCompound) {
target = if (tag.contains("Target")) {
IPAddress(tag.getInt("Target"))
} else {
null
}
updateStatus()
}
}

View File

@ -12,7 +12,7 @@ import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.block.FaceDeviceBlock
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.packet.DeviceRemovedPacket
import net.shadowfacts.phycon.packet.ReadInventoryPacket
import net.shadowfacts.phycon.packet.ReadGroupedInventoryPacket
import net.shadowfacts.phycon.packet.RequestInventoryPacket
import net.shadowfacts.phycon.util.ClientConfigurableDevice
import net.shadowfacts.phycon.util.GhostInv
@ -42,12 +42,12 @@ class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockE
override fun handle(packet: Packet) {
when (packet) {
is ReadInventoryPacket -> handleReadInventory(packet)
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
}
}
private fun handleReadInventory(packet: ReadInventoryPacket) {
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
inventoryCache[packet.source] = packet.inventory
recalculateRedstone()
}
@ -70,7 +70,7 @@ class RedstoneEmitterBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockE
}
private fun updateInventories() {
sendPacket(RequestInventoryPacket(ipAddress))
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
}
private fun recalculateRedstone() {

View File

@ -70,7 +70,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
override fun handle(packet: Packet) {
when (packet) {
is ReadInventoryPacket -> handleReadInventory(packet)
is ReadGroupedInventoryPacket -> handleReadInventory(packet)
is DeviceRemovedPacket -> handleDeviceRemoved(packet)
is StackLocationPacket -> handleStackLocation(packet)
is ItemStackPacket -> handleItemStack(packet)
@ -78,7 +78,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
}
}
private fun handleReadInventory(packet: ReadInventoryPacket) {
private fun handleReadInventory(packet: ReadGroupedInventoryPacket) {
inventoryCache[packet.source] = packet.inventory
updateAndSync()
}

View File

@ -37,7 +37,7 @@ class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTer
updateAndSync()
inventoryCache.clear()
sendPacket(RequestInventoryPacket(ipAddress))
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
return CraftingTerminalScreenHandler(syncId, playerInv, this@CraftingTerminalBlockEntity)

View File

@ -22,7 +22,7 @@ class TerminalBlockEntity(pos: BlockPos, state: BlockState): AbstractTerminalBlo
updateAndSync()
inventoryCache.clear()
sendPacket(RequestInventoryPacket(ipAddress))
sendPacket(RequestInventoryPacket(RequestInventoryPacket.Kind.GROUPED, ipAddress))
val factory = object: ExtendedScreenHandlerFactory {
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler {
return TerminalScreenHandler(syncId, playerInv, this@TerminalBlockEntity)

View File

@ -25,6 +25,10 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
val EXTRACTOR_SIDE = Identifier(PhysicalConnectivity.MODID, "block/extractor_side")
val INSERTER = Identifier(PhysicalConnectivity.MODID, "block/inserter")
val INSERTER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/inserter_side")
val P2P_INTERFACE = Identifier(PhysicalConnectivity.MODID, "block/p2p_interface")
val P2P_INTERFACE_SIDE = Identifier(PhysicalConnectivity.MODID, "block/p2p_interface_side")
val P2P_RECEIVER = Identifier(PhysicalConnectivity.MODID, "block/p2p_receiver")
val P2P_RECEIVER_SIDE = Identifier(PhysicalConnectivity.MODID, "block/p2p_receiver_side")
val CABLES = DyeColor.values().map {
Identifier(PhysicalConnectivity.MODID, "block/cable/${it.getName()}") to it
@ -38,6 +42,8 @@ class PhyModelProvider(resourceManager: ResourceManager) : ModelResourceProvider
REDSTONE_EMITTER -> SimpleFaceDeviceModel(REDSTONE_EMITTER_SIDE)
EXTRACTOR -> SimpleFaceDeviceModel(EXTRACTOR_SIDE)
INSERTER -> SimpleFaceDeviceModel(INSERTER_SIDE)
P2P_INTERFACE -> SimpleFaceDeviceModel(P2P_INTERFACE_SIDE)
P2P_RECEIVER -> SimpleFaceDeviceModel(P2P_RECEIVER_SIDE)
in CABLES -> ColoredCableModel(CABLES[resourceId]!!)
else -> null
}

View File

@ -14,6 +14,7 @@ import net.shadowfacts.cacao.window.Window
import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.block.miner.MinerBlockEntity
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlockEntity
import net.shadowfacts.phycon.component.ActivationController
@ -90,6 +91,15 @@ class DeviceConsoleScreen(
RedstoneEmitterViewController(device)
))
}
if (device is P2PReceiverBlockEntity) {
tabs.add(TabViewController.SimpleTab(
TextureView(Texture(Identifier("textures/item/ender_pearl.png"), 0, 0, 16, 16)).apply {
intrinsicContentSize = Size(16.0, 16.0)
},
TranslatableText("block.phycon.p2p_receiver"),
P2PReceiverViewController(device)
))
}
tabController = TabViewController(tabs)

View File

@ -0,0 +1,58 @@
package net.shadowfacts.phycon.client.screen.console
import net.minecraft.client.MinecraftClient
import net.minecraft.text.TranslatableText
import net.shadowfacts.cacao.util.Color
import net.shadowfacts.cacao.view.Label
import net.shadowfacts.cacao.view.textfield.TextField
import net.shadowfacts.cacao.viewcontroller.ViewController
import net.shadowfacts.kiwidsl.dsl
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
import net.shadowfacts.phycon.networking.C2SConfigureDevice
/**
* @author shadowfacts
*/
class P2PReceiverViewController(
val device: P2PReceiverBlockEntity,
): ViewController() {
override fun viewDidLoad() {
super.viewDidLoad()
val label = Label(TranslatableText("gui.phycon.console.p2p_receiver.target")).apply {
textColor = Color.TEXT
}
view.addSubview(label)
val textField =
TextField(device.target?.toString() ?: "") {
device.target = IPAddress.parse(it.text)
MinecraftClient.getInstance().player!!.networkHandler.sendPacket(C2SConfigureDevice(device))
}
view.addSubview(textField)
val status = Label(device.status.displayName).apply {
textColor = Color.TEXT
}
view.addSubview(status)
device.clientObserver = {
status.text = device.status.displayName
}
view.solver.dsl {
textField.widthAnchor equalTo 100
textField.heightAnchor equalTo 20
textField.topAnchor equalTo view.topAnchor
textField.rightAnchor equalTo view.rightAnchor
label.centerYAnchor equalTo textField.centerYAnchor
label.rightAnchor equalTo (textField.leftAnchor - 4)
status.centerXAnchor equalTo view.centerXAnchor
status.centerYAnchor equalTo (view.centerYAnchor - 10)
}
}
}

View File

@ -17,6 +17,10 @@ import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.block.netswitch.SwitchBlockEntity
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlock
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlockEntity
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlock
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlockEntity
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlockEntity
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
@ -40,6 +44,8 @@ object PhyBlockEntities {
val MINER = create(::MinerBlockEntity, PhyBlocks.MINER)
val REDSTONE_CONTROLLER = create(::RedstoneControllerBlockEntity, PhyBlocks.REDSTONE_CONTROLLER)
val REDSTONE_EMITTER = create(::RedstoneEmitterBlockEntity, PhyBlocks.REDSTONE_EMITTER)
val P2P_INTERFACE = create(::P2PInterfaceBlockEntity, PhyBlocks.P2P_INTERFACE)
val P2P_RECEIVER = create(::P2PReceiverBlockEntity, PhyBlocks.P2P_RECEIVER)
private fun <T: BlockEntity> create(builder: (BlockPos, BlockState) -> T, block: Block): BlockEntityType<T> {
return BlockEntityType.Builder.create(builder, block).build(null)
@ -55,6 +61,8 @@ object PhyBlockEntities {
register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
register(P2PReceiverBlock.ID, P2P_RECEIVER)
}
private fun register(id: Identifier, type: BlockEntityType<*>) {

View File

@ -11,6 +11,8 @@ import net.shadowfacts.phycon.block.inserter.InserterBlock
import net.shadowfacts.phycon.block.miner.MinerBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlock
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlock
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
@ -32,6 +34,8 @@ object PhyBlocks {
val MINER = MinerBlock()
val REDSTONE_CONTROLLER = RedstoneControllerBlock()
val REDSTONE_EMITTER = RedstoneEmitterBlock()
val P2P_INTERFACE = P2PInterfaceBlock()
val P2P_RECEIVER = P2PReceiverBlock()
fun init() {
for ((color, block) in CABLES) {
@ -47,6 +51,8 @@ object PhyBlocks {
register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
register(P2PReceiverBlock.ID, P2P_RECEIVER)
}
private fun register(id: Identifier, block: Block) {

View File

@ -12,12 +12,15 @@ import net.shadowfacts.phycon.block.inserter.InserterBlock
import net.shadowfacts.phycon.block.miner.MinerBlock
import net.shadowfacts.phycon.block.netinterface.InterfaceBlock
import net.shadowfacts.phycon.block.netswitch.SwitchBlock
import net.shadowfacts.phycon.block.p2p.P2PInterfaceBlock
import net.shadowfacts.phycon.block.p2p.P2PReceiverBlock
import net.shadowfacts.phycon.block.redstone_controller.RedstoneControllerBlock
import net.shadowfacts.phycon.block.redstone_emitter.RedstoneEmitterBlock
import net.shadowfacts.phycon.block.terminal.CraftingTerminalBlock
import net.shadowfacts.phycon.block.terminal.TerminalBlock
import net.shadowfacts.phycon.item.DeviceBlockItem
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
import net.shadowfacts.phycon.util.text
/**
* @author shadowfacts
@ -37,6 +40,8 @@ object PhyItems {
val MINER = DeviceBlockItem(PhyBlocks.MINER, Item.Settings())
val REDSTONE_CONTROLLER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_CONTROLLER, Item.Settings())
val REDSTONE_EMITTER = FaceDeviceBlockItem(PhyBlocks.REDSTONE_EMITTER, Item.Settings())
val P2P_INTERFACE = FaceDeviceBlockItem(PhyBlocks.P2P_INTERFACE, Item.Settings())
val P2P_RECEIVER = FaceDeviceBlockItem(PhyBlocks.P2P_RECEIVER, Item.Settings())
val SCREWDRIVER = ScrewdriverItem()
val CONSOLE = ConsoleItem()
@ -61,6 +66,18 @@ object PhyItems {
register(MinerBlock.ID, MINER)
register(RedstoneControllerBlock.ID, REDSTONE_CONTROLLER)
register(RedstoneEmitterBlock.ID, REDSTONE_EMITTER)
register(P2PInterfaceBlock.ID, P2P_INTERFACE)
P2P_INTERFACE.addTooltip(text {
withStyle(darkGray) {
+translate("tooltip.phycon.p2p_interface")
}
})
register(P2PReceiverBlock.ID, P2P_RECEIVER)
P2P_RECEIVER.addTooltip(text {
withStyle(darkGray) {
+translate("tooltip.phycon.p2p_receiver")
}
})
register(ScrewdriverItem.ID, SCREWDRIVER)
register(ConsoleItem.ID, CONSOLE)

View File

@ -14,7 +14,15 @@ import net.shadowfacts.phycon.util.text
*/
open class DeviceBlockItem(block: DeviceBlock<*>, settings: Settings = Settings()): BlockItem(block, settings) {
private var tooltip = mutableListOf<Text>()
fun addTooltip(tooltip: Text) {
this.tooltip.add(tooltip)
}
override fun appendTooltip(stack: ItemStack, world: World?, list: MutableList<Text>, context: TooltipContext) {
list.addAll(tooltip)
val beTag = stack.getSubNbt("BlockEntityTag")
if (beTag != null) {
val ip = IPAddress(beTag.getInt("IPAddress"))

View File

@ -0,0 +1,10 @@
package net.shadowfacts.phycon.packet
import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class PingPacket(source: IPAddress, destination: IPAddress): BasePacket(source, destination)
class PongPacket(source: IPAddress, destination: IPAddress): BasePacket(source, destination)

View File

@ -6,7 +6,7 @@ import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class ReadInventoryPacket(
class ReadGroupedInventoryPacket(
val inventory: GroupedItemInvView,
source: IPAddress,
destination: IPAddress

View File

@ -0,0 +1,14 @@
package net.shadowfacts.phycon.packet
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.fabricmc.fabric.api.transfer.v1.storage.Storage
import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class ReadItemStoragePacket(
val inventory: Storage<ItemVariant>,
source: IPAddress,
destination: IPAddress
): BasePacket(source, destination)

View File

@ -5,4 +5,12 @@ import net.shadowfacts.phycon.api.util.IPAddress
/**
* @author shadowfacts
*/
class RequestInventoryPacket(source: IPAddress, destination: IPAddress = IPAddress.BROADCAST): BasePacket(source, destination)
class RequestInventoryPacket(
val kind: Kind,
source: IPAddress,
destination: IPAddress = IPAddress.BROADCAST
): BasePacket(source, destination) {
enum class Kind {
GROUPED, SIDED
}
}

View File

@ -0,0 +1,7 @@
{
"multipart": [
{
"apply": { "model": "phycon:block/p2p_interface" }
}
]
}

View File

@ -0,0 +1,7 @@
{
"multipart": [
{
"apply": { "model": "phycon:block/p2p_receiver" }
}
]
}

View File

@ -24,6 +24,8 @@
"block.phycon.miner": "Block Miner",
"block.phycon.redstone_controller": "Redstone Controller",
"block.phycon.redstone_emitter": "Redstone Emitter",
"block.phycon.p2p_interface": "P2P Interface",
"block.phycon.p2p_receiver": "P2P Receiver",
"item.phycon.screwdriver": "Screwdriver",
"item.phycon.console": "Console",
@ -56,6 +58,7 @@
"gui.phycon.console.receiver.priority_desc": "When a device puts items into the network, it starts with receiver (e.g., interfaces) with higher priorities. Priorities can be negative.",
"gui.phycon.console.receiver.sync": "Sync with Provider Priority",
"gui.phycon.console.emitter.mode": "Measurement Mode",
"gui.phycon.console.p2p_receiver.target": "P2P Target",
"gui.phycon.redstone_mode.high": "High",
"gui.phycon.redstone_mode.low": "Low",
"gui.phycon.redstone_mode.toggle": "Toggle",
@ -68,9 +71,14 @@
"gui.phycon.miner_mode.on_demand": "On Demand",
"gui.phycon.redstone_emitter_mode.analog": "Analog",
"gui.phycon.redstone_emitter_mode.digital": "Digital",
"gui.phycon.p2p_receiver.status.ok": "OK",
"gui.phycon.p2p_receiver.status.no_target": "No target",
"gui.phycon.p2p_receiver.status.waiting_for_response": "Waiting for response",
"tooltip.phycon.device.configured": "Configured",
"tooltip.phycon.device.ip": "IP: ",
"tooltip.phycon.p2p_interface": "Attach to the point-to-point target inventory",
"tooltip.phycon.p2p_receiver": "Point-to-point inventory destination",
"advancements.phycon.root.title": "Physical Connectivity",
"advancements.phycon.root.description": "Mass item storage and local networking",

View File

@ -0,0 +1,33 @@
{
"parent": "block/block",
"textures": {
"cable": "phycon:block/cable_straight",
"front": "phycon:block/p2p_interface_front",
"back": "phycon:block/p2p_interface_back",
"side": "phycon:block/p2p_interface_back"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 4, 16],
"faces": {
"down": { "texture": "#front" },
"up": { "texture": "#back" },
"north": { "texture": "#side" },
"south": { "texture": "#side" },
"west": { "texture": "#side" },
"east": { "texture": "#side" }
}
},
{
"from": [6, 4, 6],
"to": [10, 6, 10],
"faces": {
"north": { "texture": "#cable" },
"south": { "texture": "#cable" },
"west": { "texture": "#cable" },
"east": { "texture": "#cable" }
}
}
]
}

View File

@ -0,0 +1,33 @@
{
"parent": "block/block",
"textures": {
"cable": "phycon:block/cable_straight",
"front": "phycon:block/p2p_receiver_front",
"back": "phycon:block/p2p_receiver_back",
"side": "phycon:block/p2p_receiver_back"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 4, 16],
"faces": {
"down": { "texture": "#front" },
"up": { "texture": "#back" },
"north": { "texture": "#side" },
"south": { "texture": "#side" },
"west": { "texture": "#side" },
"east": { "texture": "#side" }
}
},
{
"from": [6, 4, 6],
"to": [10, 6, 10],
"faces": {
"north": { "texture": "#cable" },
"south": { "texture": "#cable" },
"west": { "texture": "#cable" },
"east": { "texture": "#cable" }
}
}
]
}